Kotlin - API Control with Retrofit and RxJava
Bài đăng này đã không được cập nhật trong 6 năm
Giới thiệu
Hầu hết chúng ta khi lập trình các ứng dụng cho mobile đều phải gọi api
tới server để lấy hay cập nhật dữ liệu.
Đối với những người mới
như mình, mình mất khá nhiều thời gian để xem nên sử dụng cái gì, dùng như thế nào để lấy dữ liệu từ trên server xuống một cách dễ dàng và đơn giản nhất.
Sau khi vật lộn với google mình quyết định sử dụng bộ đôi Retrofit
và RxJava
để tạo ApiService
cho project của mình.
Thông tin chi tiết về 2 thằng này, mọi người có thể tìm trên viblo
có khá nhiều bài viết về nó rồi nhé.
Cài đặt
Retrofit
Retrofit là một thư viện HTTP Client cho Android và Java. Retrofit giúp dễ dàng kết nối tới một REST web service bằng cách dịch API thành các Java interface. Thư viện mạnh mẽ này giúp chúng ta làm việc dễ dàng với dữ liệu JSON hay XML sau đó phân tích thành các đối tượng object cơ bản Plain Old Java Objects (POJOs). Nó cũng cung cấp đầy đủ các phương thức GET, POST, PUT, PATCH, và DELETE.
Download the latest JAR or grab via Maven:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.4.0</version>
</dependency>
or Gradle:
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
RxJava
ReactiveX API tập trung vào đồng bộ dữ liệu, là kết hợp tốt nhất từ các pattern Observer, Iterator và ngôn ngữ lập trình hàm. Lấy dữ liệu theo thời gian thực là vấn đề thông dụng đòi hỏi giải pháp rạch ròi, tối ưu, và có khả năng mở rộng. Sử dụng Observables và các toán tử, ReactiveX cung cấp một tổ hợp các API linh hoạt để tạo và thao tác trên dòng dữ liệu giải quyết vấn đề đồng bộ.
RxJava là thư viện mã nguồn mở implement ReactiveX trên Java. Có 2 lớp chính là Observable và Subscriber:
- Observable là một lớp đưa ra dòng dữ liệu hoặc sự kiện (event). Flow của Observable là đưa ra một hoặc nhiều các items, sau đó gọi kết thúc thành công hoặc lỗi.
- Subscriber lắng nghe flow, thực thi các hành động trên dòng dữ liệu hoặc sự kiện được đưa ra bởi Observable
Cài đặt thông qua Gradle:
compile "io.reactivex.rxjava2:rxjava:2.x.y"
(Please replace x
and y
with the latest version numbers:
)
Sử dụng
Để dễ dàng hơn trong việc gọi api
, mình tạo 1 interface ApiService
chứa thông tin về các request lên server mà mình sử dụng. Ngoài ra mình sử dụng thêm HttpLoggingInterceptor
để debug các request.
const val BASE_URL = "https://YOUR.BASE.URL/API"
const val LOGIN: String = "login"
const val GET_POST_LIST: String = "posts"
const val GET_POST_DETAIL: String = "posts/{post_id}"
const val ATTACH_POST_DATA: String = "posts/{post_id}/upload"
interface ApiService {
@POST(LOGIN)
@FormUrlEncoded
fun getAccessToken(
@Field("client_id") clientId: String,
@Field("client_secret") clientSecret: String,
@Field("grant_type") grantType: String,
@Field("username") userName: String,
@Field("password") password: String
): Observable<User>
@GET(GET_POST_LIST)
fun getPosts(
@Header("Authorization") token: String
) : Observable<PostList>
@GET(GET_POST_DETAIL)
fun getPostDetail(
@Header("Authorization") token: String,
@Path("Post_id") postId: Int
) : Observable<PostDetail>
@Multipart
@POST(ATTACH_POST_DATA)
fun uploadPostData(
@Header("Authorization") token: String,
@Part("post_id") postId: Int,
@Part file: MultipartBody.Part
): Observable<PostDetail>
companion object {
private val logging: HttpLoggingInterceptor = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
private val client: OkHttpClient = OkHttpClient.Builder().addInterceptor(logging).build()
fun create(): ApiService {
val retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.client(client)
.build()
return retrofit.create(ApiService::class.java)
}
}
}
Như các bạn có thể thấy, ApiService
của mình khá là đơn giản.
Mình đặt phương thức create()
trong companion object
để khi sử dụng mình có thể dễ dàng tạp một instance của service, chẳng hạn như
companion object {
private val apiService by lazy { ApiService.create() }
private var disposable: Disposable? = null
}
Ứng với mỗi phương thức, mình sử dụng Observable
cùng với data class
chứa dữ liệu. Dưới đây là ví dụ về cách sử dụng kết hợp giữa Retrofit và RxJava để login, get list, upload file
Login
disposable = apiService.getAccessToken(CLIENT_ID, CLIENT_SECRET, GRANT_TYPE, input_email.text.toString(), input_password.text.toString())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{result -> onLoginSuccess(result)},
{error -> Toast.makeText(this, error.message, Toast.LENGTH_LONG).show()},
{Log.i(TAG, "Login Completed")}
)
Get Post list
val header = "Bearer abcdefghijklmnopqrstuvwxyz"
disposable = apiService.getPostList(header)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{result -> showList(result)},
{error -> Toast.makeText(this, error.message, Toast.LENGTH_SHORT).show()}
)
Upload file
val header = "Bearer abcdefghijklmnopqrstuvwxyz"
val file = File(path)
val uploadFile = RequestBody.create(MediaType.parse(FileHelper.getMimeType(path)), file)
val filePart = MultipartBody.Part.createFormData("thumbnail", file.name, uploadFile)
disposable = apiService.uploadSingleFile(header, postId, filePart)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{result -> onUploadSuccess(result)},
{error -> Toast.makeText(context, error.message, Toast.LENGTH_SHORT).show()}
)
All rights reserved