12/08/2018, 15:44

RxJava 2 và Retrofit trong ứng dụng Android

RxJava là 1 Reactive dựa trên Java framework. Nó giúp bạn thực hiện các tác vụ đồng bộ hoặc không đồng bộ trong chương trình. Trong bài này mình sẽ hướng dẫn các bạn sử dụng RxJava kết hợp với Retrofit để thức hiện lấy dữ liệu từ API. Khởi tao Project: trong ví dụ này mình sẽ khởi tạo 1 ...

  • RxJava là 1 Reactive dựa trên Java framework. Nó giúp bạn thực hiện các tác vụ đồng bộ hoặc không đồng bộ trong chương trình. Trong bài này mình sẽ hướng dẫn các bạn sử dụng RxJava kết hợp với Retrofit để thức hiện lấy dữ liệu từ API.
  • Khởi tao Project: trong ví dụ này mình sẽ khởi tạo 1 ứng dụng với package com.demo.retrofitrxjava, Activity là MainActivity và layout là activity_main.
  • Thêm Dependencies và enabling Jack compiler: Trong file app’s build.gradle.
jackOptions {
    enabled true
}

Chúng ta cần cài đặt Java version 8 để có thể sử dụng cách viết Lambda trong code.

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

Thêm các dependencies cần thiết.

compile 'com.android.support:recyclerview-v7:25.0.1'
compile 'com.android.support:cardview-v7:25.0.1'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

ở trên mình đã thêm các thứ viện r RxJava, Retrofit, Card View và Recycler View.

  • Thêm Permissions vào Manifest
<uses-permission android:name="android.permission.INTERNET"/>

Xây dựng layout

Trong layout activity_main.xml chúng ta sẽ sử dụng một RecyclerView bao ngoài là 1 ViewGroup là Relative Layout.

// activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_awidth="match_parent"
    android:layout_height="match_parent"
    tools:context="com.demo.retrofitrxjava.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:scrollbars="vertical"
        android:layout_awidth="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

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.

// recycler_row.xml
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_awidth="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="5dp"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    card_view:cardCornerRadius="5dp">

    <LinearLayout
        android:layout_awidth="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_name"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:textSize="18sp"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tv_version"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tv_api_level"
            android:layout_awidth="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</android.support.v7.widget.CardView>

Xây dựng Model

Như layout recycler_row.xml ở trên mình xây dựng, thì mình cần 1 Model với 3 trường để chứa các dữ liệu Android version name, version number and API level

// package com.demo.retrofitrxjava.model;
public class Android {

    private String ver;
    private String name;
    private String api;

    public String getVer() {
        return ver;
    }

    public String getName() {
        return name;
    }

    public String getApi() {
        return api;
    }
}

Tạo 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.

// package com.demo.retrofitrxjava.network;

public interface RequestInterface {

    @GET("android/jsonarray/")
    Observable<List<Android>> register();
}

Tạo Adapter cho RecyclerView

Tạo file DataAdapter.java

public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {

    private ArrayList<Android> mAndroidList;

    public DataAdapter(ArrayList<Android> androidList) {
        mAndroidList = androidList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {

        holder.mTvName.setText(mAndroidList.get(position).getName());
        holder.mTvVersion.setText(mAndroidList.get(position).getVer());
        holder.mTvApi.setText(mAndroidList.get(position).getApi());
    }

    @Override
    public int getItemCount() {
        return mAndroidList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{

        private TextView mTvName,mTvVersion,mTvApi;
        public ViewHolder(View view) {
            super(view);

            mTvName = (TextView)view.findViewById(R.id.tv_name);
            mTvVersion = (TextView)view.findViewById(R.id.tv_version);
            mTvApi = (TextView)view.findViewById(R.id.tv_api_level);
        }
    }
}

DataAdapter có nhiệm vụ chuyển đổi dữ liệu đầu vào là 1 List<Android> androidList lấy từ API và hiển thị lên màn hình dưới dạng danh sách các phần tử riêng biệt .

Ở đây mình sẽ khởi tạo 1 đối trượng CompositeDisposable để thêm tất cả các .subscribe() và đó và clear nó khi Activity onDestroy(). Trong RxJava 1 thì chúng ta khởi tao đối tượng CompositeSubscription nhưng trong phiên bản từ 2.0 trở đi Rxjava đã loại bỏ đối tượng này.

Khởi tạo RecyclerView

Khởi tạo RecyclerView

private void initRecyclerView() {
    mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    mRecyclerView.setHasFixedSize(true);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
    mRecyclerView.setLayoutManager(layoutManager);
    }

Lấy dữ liệu từ server

private void loadJSON() {
    RequestInterface requestInterface = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build().create(RequestInterface.class);

    Disposable disposable = requestInterface.register()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(this::handleResponse, this::handleError);

     mCompositeDisposable.add(disposable);
    }

ở đây chắc các bạn thấy cách viết mới mẻ này subscribe(this::handleResponse,this::handleError)). Thức chất đây là cách viết ngắn gọn của Java 8 Lambda. Cách viết đầy đủ sẽ là

    subscribe(response -> handleResponse(response), error -> handleError(error))

Khi chung ta thêm Disposable vào CompositeDisposable thông qua phương thức mCompositeDisposable.add(disposable); và mình sẽ gọi hàm mCompositeDisposable.clear() khi Activity gọi vào hàm onStop() hay onDestroy() sẽ tránh được trường hợp bị mất Context khi Activity bị kill.

Hàm xử lý dữ liệu trả về

private void handleResponse(List<Android> androidList) {
        mAndroidArrayList = new ArrayList<>(androidList);
        mAdapter = new DataAdapter(mAndroidArrayList);
        mRecyclerView.setAdapter(mAdapter);
    }

private void handleError(Throwable error) {
    Toast.makeText(this, "Error " + error.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}

private void handleSuccess() {
    Toast.makeText(this, "Get data success! ", Toast.LENGTH_SHORT).show();
}

Ở đây hàm handleResponse() sẽ nhận dữ liệu từ hàm onNext() của subscribe và hiển thị dữ liệu lên RecyclerView. Hai hàm handleError và handleSuccess sẽ nhận 2 sự kiện onError() và onComplete() từ subscribe để bắt các sự kiện khi sảy ra lỗi hoặc là kết thúc.

Ở 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 ứng dụng Android để lấy dữ liệu từ API. Thông qua bài viết trên các bạn có thể thấy sự khác nhau cơ bản giữa RxJava 2 và RxJava là sự khác nhau ở cách .subscribe() và cách quản lý sự kiện thông qua đối tượng CompositeDisposable trong RxJava. Link source code tham khảo: https://github.com/huyquyet/DemoRxJava2Retrofit

0