RxJava + Retrofit 應用整理

去年因爲項目重構寫了個 MVP 模式的框架 Demo,採用 RxJava + Retrofit 作爲網路請求框架,一直想整理一下,但上半年確實浪得一(*),現在難得有點空閒,馬上整理一下,作爲回顧,查漏補缺。【聽着怎麼這麼耳熟 ~ 】

相關文章:MVP(Model-View-Presenter)框架整理

網路請求框架基於以下版本:

// RXJava
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
// Retrofit
compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
// JSON Parsing
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
// Glide
compile 'com.github.bumptech.glide:glide:3.7.0'

import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * @author 小僑
 * @time 2017/7/21  14:52
 * @desc RetrofitHelper 類
 * 主要用來構造 retrofit 對象以及得到接口類對象
 */
public class RetrofitHelper {

    private static final RetrofitHelper mRetrofitHelper = new RetrofitHelper();
    private Retrofit mRetrofit;

    private RetrofitHelper() {
        setRetrofit();
    }

    public static RetrofitHelper getInstance(){
        return mRetrofitHelper;
    }

    private void setRetrofit() {
        mRetrofit = new Retrofit.Builder()
                .baseUrl("https://api.douban.com/")
                .addConverterFactory(GsonConverterFactory.create()) // 添加 gson 關聯
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 添加 Rxjava 關聯
                .build();
    }

    public ApiService getApiService() {
        ApiService apiService = mRetrofit.create(ApiService.class);
        return apiService;
    }
}
import io.reactivex.Observable;
import retrofit2.http.GET;
import retrofit2.http.Path;

/**
 * @author 小僑
 * @time 2017/7/21  14:44
 * @desc 數據接口類
 */
public interface ApiService {

    // 豆瓣250:http://api.douban.com/v2/movie/top250
    @GET("v2/movie/top250")
    Observable<Movies> getMovies250();

    // 條目信息:http://api.douban.com/v2/movie/subject/1764789
    @GET("v2/movie/subject/{id}")
    Observable<Movie> getMoviesById(@Path("id") int id);
}
import io.reactivex.disposables.CompositeDisposable;

/**
 * @author 小僑
 * @time 2017/7/21  10:11
 * @desc Presenter 基類
 */
public abstract class BasePresenter<V extends IView, M extends IModel> implements IPresenter {

    protected V mView;
    protected M mModel;
    // 用於取消訂閱:http://blog.csdn.net/tyrantu1989/article/details/69053816
    // RxJava 2.0 CompositeDisposable 取代 CompositeSubscription
    protected CompositeDisposable mCompositeDisposable;

    public BasePresenter() {
        mModel = initModel();
        mCompositeDisposable = new CompositeDisposable();
    }

    protected abstract M initModel();

    @Override
    public void attachView(IView view) {
        mView = (V) view;
    }

    @Override
    public void detachView() {
        // activity 銷燬的時候,切斷所有訂閱關係
        mCompositeDisposable.clear();
        mView = null;
    }
}
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

/**
 * @author 小僑
 * @time 2017/7/21  10:25
 * @desc movie 頁面 Presenter 層
 */
public class MoviePresenter extends BasePresenter<MovieActivity, MovieModel> implements MovieContract.IPresenter {

    // MoviePresenter<MovieActivity> 已經在 MovieActivity 中 onCreate 時綁定了
    // MoviePresenter<MovieModel> 已經在 MoviePresenter 新建時調用 initModel()方法綁定了
    @Override
    protected MovieModel initModel() {
        return new MovieModel();
    }

    @Override
    public void getTop250() {
        mModel.downloadTop250()
                .subscribeOn(Schedulers.io()) // 指定發射事件的線程
                .observeOn(AndroidSchedulers.mainThread()) // 指定消費事件的線程
                .subscribe(new Observer<Movies>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        // 添加訂閱事件到管理器,以便統一管理
                        mCompositeDisposable.add(d); // TODO: 2017/8/28 思考看能不能抽取???除非重寫 Observer?
                        mView.showLoading();
                        // TODO: 這裏不用做 mView != null 判斷,是因爲在 BaseActivity 已經做了 onDestroy()時解綁了
                    }

                    @Override
                    public void onNext(Movies movies) {
                        mView.showTop250(movies);
                    }

                    @Override
                    public void onError(Throwable e) {
                        mView.hideLoading();
                        mView.showToast(e.getMessage());
                    }

                    @Override
                    public void onComplete() {
                        mView.hideLoading();
                    }
                });
    }

    @Override
    public void getMovieInfo(int id) {
        mModel.downloadMovieInfo(id)
                .subscribeOn(Schedulers.io()) // 另開一個線程來下載(指定一個觀察者在哪個調度器上觀察這個Observable)
                .observeOn(AndroidSchedulers.mainThread()) // 下載完回到主線程(指定 Observable 自身在哪個調度器上執行)
                .subscribe(new Observer<Movie>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        mCompositeDisposable.add(d);
                        mView.showLoading();
                    }

                    @Override
                    public void onNext(Movie movie) {
                        mView.showMovieInfo(movie);
                    }

                    @Override
                    public void onError(Throwable e) {
                        mView.hideLoading();
                        mView.showToast(e.getMessage());
                    }

                    @Override
                    public void onComplete() {
                        mView.hideLoading();
                    }
                });
    }
}
import io.reactivex.Observable;

/**
 * @author 小僑
 * @time 2017/7/21  10:30
 * @desc movie 頁面 Model 層
 */
public class MovieModel implements IModel, MovieContract.IModel {

    @Override
    public Observable<Movies> downloadTop250() {
        ApiService apiService = RetrofitHelper.getInstance().getApiService();
        return apiService.getMovies250();
    }

    @Override
    public Observable<Movie> downloadMovieInfo(int id) {
        ApiService apiService = RetrofitHelper.getInstance().getApiService();
        return apiService.getMoviesById(id);
    }
}
import io.reactivex.Observable;

/**
 * @author 小僑
 * @time 2017/7/21  10:23
 * @desc movie 頁面合約類:用於約束/定義 movie 頁面的特有方法
 */
public class MovieContract {

    /**
     * View
     */
    interface IView {
        void showTop250(Movies movies);
        void showMovieInfo(Movie movie);
    }

    /**
     * Prezenter
     */
    interface IPresenter {
        void getTop250();
        void getMovieInfo(int id);
    }

    /**
     * Model
     */
    interface IModel {
        Observable<Movies> downloadTop250();
        Observable<Movie> downloadMovieInfo(int id);
    }
}

Demo 的 Github地址:
https://github.com/ZhangZeQiao/GeneralFramework.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章