Android-Retrofit2+Rxjava2之网络通用请求-初步封装

一直也是用MVP模式,也就结合Rx做网络请求,Rx子线程和UI线程的切换是相当的方便(小白后面准备看下相关的切换的源码)。MVP了,一般有presenter层处理网络请求,以及调用view相关的方法,实现数据和View直接的交互。

image

从图来看也是View仅仅涉及到Presenter层的交互。当前啦,实际上View里面也有实体类的影子,不过仅仅只是拿实体类进行了界面的相关展示 - 小白使用MVP就是这种情况,比如界面里面会有控件拿实体类进行设置的一些操作:

image

之前小白有封装过BaseAdapter,那个地方我已经将这个dataModle和控件的绑定放到了一起,如果那种情况下的话,界面里面的东西就更少了。或许还得看你如何做的封装。你不能说就可以完全分离,准确讲应该是减低耦合度! 使结构更加清下,逻辑更加明了。更便于维护和完善。

而MVC耦合度就高了

image

View涉及到实体类,控制类的相关处理,只能说代码多是一方面,逻辑性也烦,维护起来费劲。以前的东家的工程我现在看起来都有点费劲,该重写了。

关于这个MVVM模式,有童鞋也在用。配合dataBinding据说还可以。很早之前有尝试过案例,小白隐隐感觉貌似还行吧。后面再具体分析看看,借鉴的思路,说不定MVVM更好用妮?

步入正题。。了解了MVP,也尝试使用过的话,如果作为像小白这样的新手,我基本上会写很多presenter,基本就是一个界面一个,而且处理都很类似..加上之前的预处理啥的,基本都是很多相同的处理逻辑和代码。

image

感觉有点多了,对吧?而且下面还有对应的contract(View和Presenter的纽带)。之前我们也是进行了数据预处理Android-Retrofit2+Rxjava2之网络请求预处理-Func1、Subscriber ,这样的话基本上数据请求都是类似如下的方式(看个分页列表的请求吧):

image
image
image

每个列表页面基本都是这种操作??为何不封装一个请求方法呢? 如果是一个请求方法怎么根据不同的实体类(dataModel)的类型,通过请求的Json进行对应类型的转换呢?

小白起初想法:泛型 之前有接触和实践了泛型,所以小白就想,应该可以试一试.

但问题来了? 像retrifit这种泛型接口定义是不能够被正确执行的(小白本想按照这种思路,最后都写完逻辑了,发现不得行):

image

以上是不行的,关于这个有网友和我一样,感觉自己像“瓜皮”Retrofit2.0简单封装成统一接口处理网络请求 哈哈...

小白目前是这样的:1. 以String作为data的真实数据类型

image

2. 然后通过Fastjson将其转换为对应的实体类,然后将其结构返回给请求者的回调(onSuccess方法).

3. 如果你试图将拿到的data直接利用fastjson转换为泛型类型,那样不行的,会报错的(人家本来就需要一个实体类进行转换,你还给一个泛型)

image
image

那怎么搞了? 想要封装通用,又不想写太多的请求方法?小白想,可以提供一个接口,有视图界面负责创建和实现转换,并返回泛型类型。

image

就是这样,可以滴...

image

而视图里面实现如下:

image

这样就解决了这个转换实体类的问题。嗯嗯。貌似还可以的样纸。 小白又想,或许可以提供一个string转实体类的管理类,专门定义各种实体类的转换,并返回泛型类型,应该可以这样。后面看看咯...

然后继续回到这个请求接口定义的地方

image

我把之前需要的参数放到了@Url中进行设置,这样就实现了接口通用。省去了定义多个service的情况。

最后把这个Preseter泛型类型的基础请求服务层搞一下

image

基本上就有了雏形了。。小白感觉还行,目前还是简化了不少东西。

直接贴上三个相关类:

BaseControlPresenter.java

import com.x.finance.controller.BaseControlContract;
import com.x.finance.net.BaseSubscribers;
import com.x.finance.net.ExceptionHandle;
import com.x.finance.net.ResponseFunc;
import com.x.finance.net.RetrofitManager;
import com.x.finance.net.service.BaseService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/*
*@Description: 请求服务表示层
*@Author: hl
*@Time: 2018/11/21 13:54
*/
public class BaseControlPresenter implements BaseControlContract.Presenter{
    private BaseControlContract.View view;                  ///< 数据【对象】请求
    private BaseControlContract.RefreshView refreshView;   ///< 数据【对象】列表请求
    private BaseService baseService;                       ///< 请求服务
    private List subscriptionList = new ArrayList();
    private DataHandler dataHandler;
    private DataListHandler dataListHandler;

    private BaseControlPresenter(){
        this.baseService = RetrofitManager.getInstance()
                .getmRetrofit()
                .create(BaseService.class);
    }

    private BaseControlPresenter(BaseControlContract.View _view){
        this();
        this.view = _view;
    }

    private BaseControlPresenter(BaseControlContract.RefreshView _refreshView){
        this();
        this.refreshView = _refreshView;
    }

    public BaseControlPresenter(BaseControlContract.View _view, DataHandler _dataHandler){
        this(_view);
        this.dataHandler = _dataHandler;
    }

    public BaseControlPresenter(BaseControlContract.View _view, DataListHandler _dataListHandler){
        this(_view);
        this.dataListHandler = _dataListHandler;
    }

    public BaseControlPresenter(BaseControlContract.RefreshView _refreshView, DataHandler _dataHandler){
        this(_refreshView);
        this.dataHandler = _dataHandler;
    }

    public BaseControlPresenter(BaseControlContract.RefreshView _refreshView, DataListHandler _dataListHandler){
        this(_refreshView);
        this.dataListHandler = _dataListHandler;
    }

    public BaseControlPresenter(BaseControlContract.View _view, BaseControlContract.RefreshView _refreshView, DataHandler _dataHandler){
        this();
        this.view = _view;
        this.refreshView = _refreshView;
        this.dataHandler = _dataHandler;
    }

    public BaseControlPresenter(BaseControlContract.View _view, BaseControlContract.RefreshView _refreshView, DataHandler _dataHandler, DataListHandler _dataListHandler){
        this();
        this.view = _view;
        this.refreshView = _refreshView;
        this.dataHandler = _dataHandler;
        this.dataListHandler = _dataListHandler;
    }

    @Override
    public void requestData(final String _funUrl, HashMap _paramList) {
        ///< 显示进度条
        view.showDialog();
        ///< 加入Token参数
        _paramList.put("access_token", UserInfoControlPresenter.getToken());
        Subscription subscription = baseService.getData(_funUrl, _paramList)
                .subscribeOn(Schedulers.io())
                .map(new ResponseFunc<>(new ResponseFunc.CallMe() {
                    @Override
                    public D onCall(String data, String requestTime) {
                        return dataHandler.String2Data(data);
                    }
                }))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseSubscribers(view) {
                    @Override
                    public void onCompleted() {
                        view.disDialog();
                    }

                    @Override
                    public void onErrors(ExceptionHandle.ResponeThrowable responeThrowable) {
                        ///< 接下来就可以根据状态码进行处理...
                        int statusCode = responeThrowable.code;
                        switch (statusCode) {
                            case ExceptionHandle.ERROR.TOKEN:
                                UserInfoControlPresenter.clearAcount();
                                view.showToast("你的账号异常,请重新登录,谢谢!");
                                break;
                            default:
                                view.showToast(responeThrowable.message);
                                break;
                        }
                        onCompleted();
                    }

                    @Override
                    public void onNext(D data) {
                        view.onSucess(data);
                    }
                });

        subscriptionList.add(subscription);
    }

    @Override
    public void requestDataList(final String _funUrl, final int _pageNum, final boolean _bIsRefresh) {
        ///< 不是刷新,则显示进度条加载
        if (!_bIsRefresh){
            ///< 显示进度条 - 首次刷新会显示,其他都是空运行
            refreshView.showDialog();
        }
        Subscription subscription = baseService.getDataList(_funUrl, _pageNum, UserInfoControlPresenter.getToken())
                .subscribeOn(Schedulers.io())
                .map(new ResponseFunc<>(new ResponseFunc.CallMe, String>() {
                    @Override
                    public List onCall(String data, String requestTime) {
                        return dataListHandler.String2DataList(data);
                    }
                }))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseSubscribers>(refreshView) {
                    @Override
                    public void onCompleted() {
                        ///< 如果是刷新才调用刷新结束接口
                        if (_bIsRefresh){
                            if (1 == _pageNum){
                                refreshView.finishRefresh();
                            }
                            else{
                                refreshView.finishLoadMore();
                            }
                        }
                        else{   ///< @首次请求, 不是刷新,取消进度条
                            refreshView.disDialog();
                        }
                    }

                    @Override
                    public void onErrors(ExceptionHandle.ResponeThrowable responeThrowable) {
                        ///< 接下来就可以根据状态码进行处理...
                        int statusCode = responeThrowable.code;
                        switch (statusCode) {
                            case ExceptionHandle.ERROR.TOKEN:
                                UserInfoControlPresenter.clearAcount();
                                refreshView.showToast("你的账号异常,请重新登录,谢谢!");
                                break;
                            default:
                                refreshView.showToast(responeThrowable.message);
                                break;
                        }
                        if (!_bIsRefresh){
                            refreshView.retryDialog();
                        }
                        else{
                            refreshView.onRequestFailer();
                        }
                        onCompleted();
                    }

                    @Override
                    public void onNext(List dataList) {
                        if (dataList.size() < 1){
                            if (1 == _pageNum){ ///< @再次请求首页如果没有数据的情况下,清空列表
                                refreshView.resetItemList();
                                refreshView.onSucess(dataList);
                            }
                            else{
                                refreshView.showToast("沒有糖果了!");
                            }
                        }else{
                            if (1 == _pageNum){
                                refreshView.resetItemList();
                                refreshView.onSucess(dataList);
                            }
                            else{
                                refreshView.onSucess(dataList);
                            }
                        }
                    }
                });

        subscriptionList.add(subscription);
    }

    @Override
    public void releaseResource() {
        for (int i = 0; i < subscriptionList.size(); ++i){
            if (null != subscriptionList.get(i) && !subscriptionList.get(i).isUnsubscribed()) {
                subscriptionList.get(i).unsubscribe();
            }
        }
        subscriptionList.clear();
    }

    /*
    *@Description: JSON数据处理回调 - 调用者进行处理
    *@Author: hl
    *@Time: 2018/11/21 16:44
    */
    public interface DataListHandler{
        List String2DataList(String strData);    ///< JSON字符串转换为对象列表返回
    }
    public interface DataHandler{
        D String2Data(String strData);              ///< JSON字符串转换为对象返回
    }
}

BaseControlContract.java

import java.util.HashMap;
import java.util.List;

/*
*@Description: 服务+视图层的纽带
*@Author: hl
*@Time: 2018/11/21 13:55
*/
public interface BaseControlContract {
    /**
     * 负责设置界面
     */
    interface View extends BaseView{
         void onSucess(T t);
    }

    interface RefreshView extends BaseViewByRefresh{
         void onSucess(List listT);
    }

    /**
     * 负责请求网络获取数据
     */
    interface Presenter extends BasePresenter{
        /**
         * 请求数据【对象】
         * @param _funUrl
         * @param _paramList
         */
        void requestData(final String _funUrl, HashMap _paramList);

        /**
         * 请求数据【对象】列表
         * @param _funUrl
         * @param _pageNum
         * @param _bIsRefresh
         */
        void requestDataList(final String _funUrl, int _pageNum, boolean _bIsRefresh);
    }
}

BaseService.java

import com.x.finance.net.HttpResponse;

import java.util.HashMap;

import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
import retrofit2.http.Url;
import rx.Observable;

/*
*@Description: 服务请求方法
*@Author: hl
*@Params:
*  D - data对象、实体类、字符串....
*@Time: 2018/11/21 12:02
*/
public interface BaseService{
    @GET    ///< GET方法 - 获取数据【对象】
    Observable> getData(@Url String url, @QueryMap HashMap paramMap);
    @GET    ///< GET方法 - 获取数据【对象】列表
    Observable> getDataList(@Url String url,
                                                  @Query("page") int pageNum,
                                                  @Query("access_token") String access_token);
    @FormUrlEncoded
    @POST   ///< POST方法 - 获取数据【对象】
    Observable> postData(@Url String url, @FieldMap HashMap paramMap);
}

使用:

image

成功回调的地方:

image

小白的BaseViewByRefresh是基于BaseView的

BaseView.java

  /**
 * View负责显示数据,被Presenter调用来设置界面,可以是Activity, Fragment,或者View, Dialog
 * Created by hl on 2018/3/13.
 */

public interface BaseView {
    /**
     * 共有的一些UI操作,比如吐司,进度条显示,消失等
     */
    void showDialog();
    void disDialog();
    void retryDialog();
    void emptyDialog();
    void showToast(String msg);
    void showRunToast(String msg);
}

BaseViewByRefresh.java

  /**
 * View负责显示数据,被Presenter调用来设置界面,可以是Activity, Fragment,或者View, Dialog
 * Created by hl on 2018/3/13.
 */

public interface BaseViewByRefresh extends BaseView{
    /**
     * 结束下拉刷新
     */
    void finishRefresh();
    /**
     * 结束上拉加载刷新
     */
    void finishLoadMore();
    /**
     * 重置列表
     */
    void resetItemList();

    /**
     * 请求失败
     */
    void onRequestFailer();
}

大量的接口啥的....再结合泛型搞一搞...有些要结合之前的一些总结。然后逐步完善才行。

就先记录到这里吧。。后面再看看怎么完善,小白都不知道这样到底合不合理,哈哈.....

下班了,希望天天坚持,天天开心 - 黄磊

你可能感兴趣的:(Android-Retrofit2+Rxjava2之网络通用请求-初步封装)