Kotlin: Tìm hiểu về Rxjava2 và Retrofit (Phần I)
Retrofit. Retrofit là một thư viện hỗ trợ việc kết nối và lấy dữ liệu từ một WebService cho Android và Java, được tạo ra bởi Square. Với retrofit bạn có thể dễ dàng lấy dữ liệu từ webservice, convert dữ liệu trả về dạng json thành các object. RXjava và Rxandroid. Rxjava và Rxandroid Là thư viện ...
Retrofit. Retrofit là một thư viện hỗ trợ việc kết nối và lấy dữ liệu từ một WebService cho Android và Java, được tạo ra bởi Square. Với retrofit bạn có thể dễ dàng lấy dữ liệu từ webservice, convert dữ liệu trả về dạng json thành các object.
RXjava và Rxandroid. Rxjava và Rxandroid Là thư viện mã nguồn mở implement ReactiveX trên Java, ReactiveX hỗ trợ lập trình dữ liệu bất đồng bộ, được thiết kế dự trên Observer pattern, nó giúp cho việc sử lý dữ liệu bất đồng bộ một cách hiệu quả , Rxjava cung cấp rất nhiều các operator hỗ trợ cho việc sử lý dữ liệu nhứ filter, groupBy, ...
Trong phần nay chúng ta sẽ cũng nhau tìm hiểu cách kết hợp Rxjava và Retrofit để lấy dữ liệu API và hiển thị lên giao diện trong Kotlin
Dưới đây, chúng ta sẽ thực hiện việc lấy thông tin các phiên bản android dựa vào api :https://api.learn2crack.com/android/jsonarray/
1.Thêm các Dependencies cần thiết RxJava, Retrofit, Card View, Recycler View và ConstraintLayout.
// ConstraintLayout. implementation 'com.android.support.constraint:constraint-layout:1.0.2' // Recyclerview compile 'com.android.support:recyclerview-v7:26.1.0' compile 'com.android.support:cardview-v7:26.1.0' compile 'com.android.support:design:26.1.0' // RxJava compile 'io.reactivex.rxjava2:rxjava:2.0.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' // Retrofit compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
2.Thêm Permissions cho Manifest
<uses-permission android:name="android.permission.INTERNET"/>
3.Tạo layout
- activity_android_version.xml Trong layout activity_android_version.xml chúng ta sẽ sử dụng một RecyclerView bao ngoài là 1 ViewGroup là ConstraintLayout.
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_awidth="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_android_list" android:layout_awidth="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
- item_android_version.xml Tiếp tới là 1 layout cho các item của RecylerView với các TextView để hiển thị Android version name, version number and API level.
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_awidth="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="1dp" android:background="@color/colorItemAndroidVersion" android:foreground="?android:attr/selectableItemBackground"> <TextView android:id="@+id/tv_name" android:layout_awidth="0dp" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:textColor="@android:color/white" android:textSize="24sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv_version" android:layout_awidth="0dp" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:textColor="@android:color/white" android:textSize="18sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_name" /> <TextView android:id="@+id/tv_api_level" android:layout_awidth="0dp" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:textColor="@android:color/white" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_version" /> </android.support.constraint.ConstraintLayout>
4.Xây dựng Model
- AndroidVersion
data class AndroidVersion(val name: String, val ver: String, val api: String)
5.Creating Retrofit Interface Vì ở đây chúng ta sử dụng kết hợp giữa RxJava và Retrofit nên đối tượng trả về của hàm được định nghĩa này cần là 1 Observable.
- Apiservice
interface ApiService { @GET("android/jsonarray/") fun getAndroidVersion(): Observable<List<AndroidVersion>> }
6.Tạo Adapter cho RecyclerView
class AndroidVersionAdapter(private val androidVersionList: List<AndroidVersion>) : RecyclerView.Adapter<AndroidVersionAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_android_version, parent, false) return ViewHolder(view) } override fun getItemCount() = androidVersionList.count() override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.bind(androidVersionList[position]) } class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { fun bind(android: AndroidVersion) { itemView.tv_name.text = android.name itemView.tv_version.text = android.ver itemView.tv_api_level.text = android.api } } }
7.Tạo Repository Lớp Repository sử dụng Retrofit builder của Retrofit để tạo ra một rest client mới với url đã cung cấp (BASE_URL)
class Repository { companion object { private var retrofit: Retrofit? = null private var builder: Retrofit.Builder = Retrofit.Builder().baseUrl(Constants.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) private val httpClient = OkHttpClient.Builder() fun <S> createService(serviceClass: Class<S>): S { return createService(serviceClass, null) } fun <S> createService(serviceClass: Class<S>, authToken: Map<String, String>?): S { if (authToken != null) { var interceptor = AuthenticationInterceptor(authToken!!) if (!httpClient.interceptors().contains(interceptor)) { httpClient.addInterceptor(interceptor) builder.client(httpClient.build()) retrofit = builder.build() } } retrofit = builder.build() return retrofit!!.create(serviceClass) } } class AuthenticationInterceptor(private val authToken: Map<String, String>) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val original = chain.request() val builder = original.newBuilder() for (key in authToken.keys) { builder.header(key, authToken.getValue(key)) } val request = builder.build() return chain.proceed(request) } }
8.Tạo Activity
class ListAndroidVersionActivity : AppCompatActivity() { private val TAG = ListAndroidVersionActivity::class.java.simpleName private var mAdapter: AndroidVersionAdapter? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_android_version) initRecyclerView() requestAndroidVersion() } // khởi tao recyclerview private fun initRecyclerView() { rv_android_list.setHasFixedSize(true) val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(this) rv_android_list.layoutManager = layoutManager } // request data tu server private fun requestAndroidVersion() { Repository.createService(ApiService::class.java).getAndroidVersion() .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe( //cú pháp của rxjava trong kotlin { result -> //request thành công handleSuccessAndroidVersion(result) }, { error -> //request thất bai handlerErrorAndroidVersion(error) } ) } //Xử lí dữ liệu khi request thành công private fun handleSuccessAndroidVersion(result: List<AndroidVersion>) { mAdapter = AndroidVersionAdapter(result) rv_android_list.adapter = mAdapter } //Xử lí dữ l request thất bại private fun handlerErrorAndroidVersion(error: Throwable) { Log.e(TAG, "handlerErrorAndroidVersion: ${error.localizedMessage}") Toast.makeText(this, "Error ${error.localizedMessage}", Toast.LENGTH_SHORT).show() } }
https://github.com/oTongXuanAn/viblo_android_kotlin_example
Ở trên mình đã giới thiệu cơ bản với các bạn về cách kết hợp giữa RxJava 2 và Retrofit trong Kotlin để lấy dữ liệu từ API. Bài kế tiếp chúng ta sẽ viết lại ví dụ trên với mô hình MVP và MVVP