Retrofit+RxJava

前言

前面寫(xiě)RxJava的時(shí)候就提過(guò)要來(lái)這么一篇RxJava和Retrofit結(jié)合使用的博客,那時(shí)由于Retrofit那篇博客還沒(méi)寫(xiě),直接寫(xiě)兩個(gè)結(jié)合的用法的話理解起來(lái)會(huì)比較困難?,F(xiàn)在Retrofit我們也學(xué)完了,是時(shí)候把欠的的那篇博客不上了。兩個(gè)組合起來(lái)用法其實(shí)還是挺簡(jiǎn)單的,說(shuō)白了就是將Retrofit的網(wǎng)絡(luò)請(qǐng)求接口方法的返回值由Callback修改為Observable,這樣一來(lái)這兩個(gè)框架就結(jié)合起來(lái)了,Retrofit網(wǎng)絡(luò)請(qǐng)求的結(jié)果就可以通過(guò)RxJava各種操作符進(jìn)行各種花式操作了。這篇博客還是老規(guī)矩直接上例子,在例子中解釋說(shuō)明。

Retrofit不使用RxJava時(shí)和使用時(shí)對(duì)比

  • 用于描述網(wǎng)絡(luò)請(qǐng)求的接口設(shè)置
public interface GetRequest_Interface {
    // 傳統(tǒng)方式:Call<..>接口形式
    @GET("部分url地址")
    Call<Translation> getCall();
}

    //  RxJava 方式:Observable<..>接口形式
    @GET("url地址")
    public interface GetRequest_Interface {
    Observable<Translation> getCall();
  • 網(wǎng)絡(luò)請(qǐng)求的封裝形式 & 發(fā)送形式
        <--傳統(tǒng)方式 -> >
        // 1. 創(chuàng)建 網(wǎng)絡(luò)請(qǐng)求接口 的實(shí)例
        GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

        // 2. 采用Call<..>接口 對(duì) 發(fā)送請(qǐng)求 進(jìn)行封裝
        Call<Translation> call = request.getCall();

        // 3. 發(fā)送網(wǎng)絡(luò)請(qǐng)求(異步)
        call.enqueue(new Callback<Translation>() {
            // 請(qǐng)求成功時(shí)回調(diào)
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                 ...
            }

            // 請(qǐng)求失敗時(shí)回調(diào)
            @Override
            public void onFailure(Call<Translation> call, Throwable throwable) {
                ....
            }
        });

       <--RxJava 版方式 -> >
        // 1. 創(chuàng)建 網(wǎng)絡(luò)請(qǐng)求接口 的實(shí)例
        GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

        // 2. 采用Observable<...>形式 對(duì) 網(wǎng)絡(luò)請(qǐng)求 進(jìn)行封裝
        Observable<Translation> observable = request.getCall();

        // 3. 發(fā)送網(wǎng)絡(luò)請(qǐng)求(異步)
        observable.subscribeOn(Schedulers.io())               // 在IO線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求
                .observeOn(AndroidSchedulers.mainThread())  // 回到主線程 處理請(qǐng)求結(jié)果
                .subscribe(new Observer<Translation>() {
                    // 發(fā)送請(qǐng)求后調(diào)用該復(fù)寫(xiě)方法(無(wú)論請(qǐng)求成功與否)
                    @Override
                    public void onSubscribe(Disposable d) {
                        ...// 初始化工作
                    }

                    // 發(fā)送請(qǐng)求成功后調(diào)用該復(fù)寫(xiě)方法
                    @Override
                    public void onNext(Translation result) {
                        ...// 對(duì)返回結(jié)果Translation類對(duì)象 進(jìn)行處理
                    }

                    // 發(fā)送請(qǐng)求成功后,先調(diào)用onNext()再調(diào)用該復(fù)寫(xiě)方法
                    @Override
                    public void onComplete() {
                        Log.d(TAG, "請(qǐng)求成功");
                    }

                    // 發(fā)送請(qǐng)求失敗后調(diào)用該復(fù)寫(xiě)方法
                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "請(qǐng)求失敗");
                    }
                });
  • 這樣一對(duì)比是不是瞬間就明白了這兩個(gè)框架結(jié)合起來(lái)的用法了,沒(méi)錯(cuò),就是這么簡(jiǎn)單,到此為止本篇博客就結(jié)束了,哈哈,騙你的,皮這一下很開(kāi)心,說(shuō)好的例子還沒(méi)寫(xiě)呢,下面我們就以一個(gè)例子來(lái)講解下具體用法。

兩個(gè)框架結(jié)合使用的網(wǎng)絡(luò)請(qǐng)求例子

1. build.gradle中添加兩個(gè)庫(kù)的依賴、Gson解析的依賴和圖片加載庫(kù)Glide的依賴

dependencies {
    //添加RxJava依賴
    implementation "io.reactivex.rxjava2:rxjava:2.2.3"
    //添加RxAndroid依賴,專門(mén)用于Android的Rx庫(kù)
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
    //添加Retrofit依賴
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    //銜接 Retrofit & RxJava,此處一定要注意使用RxJava2的版本
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
    //添加Gson解析
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
    //添加圖片加載庫(kù)依賴
    implementation 'com.github.bumptech.glide:glide:4.8.0'
}

2. 添加網(wǎng)絡(luò)權(quán)限

<uses-permission android:name="android.permission.INTERNET"/>

3. 創(chuàng)建接收服務(wù)器返回?cái)?shù)據(jù)的類

URL : https://www.zhuangbi.info/search?q=在下

image.png
  • ZaiXiaImage.java
public class ZaiXiaImage {
    //這里只取有用字段,其它沒(méi)用字段就懶得寫(xiě)了
    public String created_at;
    public String image_url;
}

4. 創(chuàng)建用于描述網(wǎng)絡(luò)請(qǐng)求的接口

import java.util.List;

import io.reactivex.Observable;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface ZaiXiaApi {
    //采用 注解 + Observable<...>接口 描述網(wǎng)絡(luò)請(qǐng)求參數(shù)
    //search()是接收網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)的方法,這里是從所有圖片中將“在下”類別的圖片查找出來(lái)
    @GET("search")
    Observable<List<ZaiXiaImage>> search(@Query("q") String query);
}

5. 布局部分代碼

  • 布局由于用到了RecyclerView和CardView,所以別忘了添加依賴
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/gridRv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>
  • 圖片布局:grid_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="4dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="4dp"
    app:cardCornerRadius="2dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="4dp">

        <ImageView
            android:id="@+id/imageIv"
            android:layout_width="match_parent"
            android:layout_height="160dp" />

        <TextView
            android:id="@+id/descriptionTv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp" />

    </LinearLayout>
</android.support.v7.widget.CardView>

6. 用于展示圖片的適配器代碼

  • ZaiXiaGridAdapter.java
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.util.List;

public class ZaiXiaGridAdapter extends RecyclerView.Adapter {
    private List<ZaiXiaImage> images;

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        MyViewHolder myViewHolder = (MyViewHolder) holder;
        ZaiXiaImage image = images.get(position);
        Glide.with(holder.itemView.getContext()).load(image.image_url).into(myViewHolder.imageIv);
        myViewHolder.descriptionTv.setText(image.created_at);
    }

    @Override
    public int getItemCount() {
        return images == null ? 0 : images.size();
    }

    public void setImages(List<ZaiXiaImage> images) {
        this.images = images;
        notifyDataSetChanged();
    }

    private class MyViewHolder extends RecyclerView.ViewHolder {
        ImageView imageIv; //圖片
        TextView descriptionTv; //創(chuàng)建時(shí)間

        public MyViewHolder(View itemView) {
            super(itemView);
            imageIv = itemView.findViewById(R.id.imageIv);
            descriptionTv = itemView.findViewById(R.id.descriptionTv);
        }
    }

}

7. 主頁(yè)面代碼

  • MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity {

    private RecyclerView gridRv;
    private ZaiXiaGridAdapter adapter;
    //切斷觀察者操作對(duì)象
    private Disposable disposable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gridRv = findViewById(R.id.gridRv);
        gridRv.setLayoutManager(new GridLayoutManager(MainActivity.this, 2));
        adapter = new ZaiXiaGridAdapter();
        gridRv.setAdapter(adapter);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://www.zhuangbi.info/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //支持RxJava
                .build();
        //創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口的實(shí)例
        ZaiXiaApi zaiXiaApi = retrofit.create(ZaiXiaApi.class);
        //通過(guò)接口方法獲取請(qǐng)求對(duì)象,用Observable<...>進(jìn)行了封裝,將返回用Observable對(duì)象
        Observable<List<ZaiXiaImage>> observable = zaiXiaApi.search("在下");
        disposable = observable.subscribeOn(Schedulers.io())
                .map(new Function<List<ZaiXiaImage>, List<ZaiXiaImage>>() { //通過(guò)map操作符將時(shí)間數(shù)據(jù)格式進(jìn)行轉(zhuǎn)換
                    @Override
                    public List<ZaiXiaImage> apply(List<ZaiXiaImage> zaiXiaImages) throws Exception {
                        SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                        List<ZaiXiaImage> images = new ArrayList<>();
                        for (int i = 0; i < zaiXiaImages.size(); i++) {
                            ZaiXiaImage zaiXiaImage = zaiXiaImages.get(i);
                            Date date = inputFormat.parse(zaiXiaImage.created_at);
                            zaiXiaImage.created_at = outputFormat.format(date);
                            images.add(zaiXiaImage);
                        }
                        return images;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<List<ZaiXiaImage>>() {
                    @Override
                    public void accept(@NonNull List<ZaiXiaImage> images) throws Exception {
                        adapter.setImages(images);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        Toast.makeText(MainActivity.this, "數(shù)據(jù)加載失敗", Toast.LENGTH_SHORT).show();
                    }
                });
    }

    @Override
    protected void onDestroy() {
        //頁(yè)面銷毀時(shí)切斷觀察者,不再接收上游事件
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
        super.onDestroy();
    }
}

8. 運(yùn)行效果

效果圖.png

感謝

Android:Retrofit 結(jié)合 RxJava的優(yōu)雅使用(含實(shí)例教程)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容