rxjava+retrofit+mvp封装

简介
工作期间有空我就学习rxjava2的使用,现在结合mvp的架构给大家封装出一个开发框架,考虑到代码的重用性,数据接口的加密解密,我这里做出了可以商用的,不单是学习。
框架代码下载

本框架所用到包

 compile 'com.android.support:design:25.3.1'
    compile 'com.android.support:cardview-v7:25.0.1'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    //http
    compile 'io.reactivex.rxjava2:rxjava:2.1.1'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'
    compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar'
    //rxbind
    compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
    compile 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0'
    compile 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0'
    //上拉下拉控件
    compile 'com.jcodecraeer:xrecyclerview:1.5.9'
    //图片压缩库
    compile 'id.zelory:compressor:2.1.0'
    //动画
    compile 'com.nineoldandroids:library:2.4.0'
    //轮播图-bug,点击回调不能再内部类中,更新图片list要是新的对象
    compile 'com.youth.banner:banner:1.4.10'

都是常用的,结合了网上很多大牛的想法封装出来,由于工作时间忙,一直没有系统的整理处理,可能还有不足请见谅,现在给大家瞅瞅…

先看使用方法,不然怎么知道好不好

里面源码文件demo文件夹放的都是例子,LoginPresenter2,Recycle2Presenter都是封装后使用,LoginPresenter,RecyclePresenter是未封装,
1.来一个登录的界面
由于是mvp架构,我们创建LoginPresenter2,里面是处理view层传来的数据交给model层,这里考虑到每个业务模块一般都有网络访问,那么每次都写这样的接口很烦啊,所以做了封装,创建了基类,直接继承使用就可以。

public class LoginPresenter2 extends HttpPresenter<LoginContract.ILoginView> {
    public LoginPresenter2(LoginContract.ILoginView view) {
        super(view);
    }

    @Override   //第一种传参方式 map
    public void doHttpRequest(Map<String, String> map) {
        mModel.httpMap("http://120.24.44.102/fuc/api/web/userapi/login.html", GlobalCode.encryArgs(map))
                .subscribe(new Consumer<ResponseBody>() {
                    @Override
                    public void accept(@NonNull ResponseBody responseBody) throws Exception {
                        String result = new String(responseBody.string());

                        //显示网络返回的数据
                        mView.showHttpResponse(result);
                 
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        GlobalCode.printLog(Log.getStackTraceString(throwable));
                    }
                });
    }

    @Override //第二种传参方式 对象
    protected void doHttpRequest2(Object object) {
        final LoginRequest loginRequest = (LoginRequest) object;
        mModel.httpMap("http://120.24.44.102/fuc/api/web/userapi/login.html", setArgField(loginRequest))
                .subscribe(new Consumer<ResponseBody>() {
                    @Override
                    public void accept(@NonNull ResponseBody responseBody) throws Exception {
                        String result = new String(responseBody.string());
                        //显示网络返回的数据
                        mView.showHttpResponse(result);
                         //本地测试 数据对象转化
                        LoginResponse loginResponse = GlobalCode.getHttpResponse(result, LoginResponse.class);
                        GlobalCode.printLog(loginResponse.getType_id() + "");
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        GlobalCode.printLog(throwable);
                    }
                });
    }}

//契约类
public class LoginContract {
    interface ILoginView extends BaseView {

        void showHttpResponse(String str);

        ImageView showImgBg();
    }

//    interface ILoginPresenter extends BasePresenter {
//        void doHttpRequest(Map<String, String> map);
//    }

//    interface IModel extends BaseModel {
//        Observable<ResponseBody> httpMap(Map<String, String> map);
//    }

}

看到请求简单吗,用map携带请求参数,这里动态传入URL,不用每次都去写一个observable,注意到就是HttpPresenter类,就是我封装后的,

public class HttpPresenter<T extends BaseView> extends BasePresenterImpl<T> implements GlobalPresenter {

    protected GlobalModel mModel;

    public HttpPresenter(T view) {
        super(view);
        this.mModel = new GlobalModel() {
            @Override
            public Observable<ResponseBody> httpMap(String url, Map<String, String> map) {
                return ApiEngine.getInstance().getApiService().doRequestUrl(url, map)
                        .compose(RxSchedulers.<ResponseBody>io2main())
                        .doOnSubscribe(new Consumer<Disposable>() {  //在subscribe()前调用
                            @Override
                            public void accept(@NonNull Disposable disposable) throws Exception {
                                addDispoable(disposable);

                                LoadingDialog.showprogress(mView.getCurContext(), "正在加载..");
                            }
                        })
                        .doOnTerminate(new Action() {   //action没有返回值,function有返回值
                            @Override
                            public void run() throws Exception {
                                LoadingDialog.dismissprogress();
                                System.out.println("onTerminate>>>>>");
                            }
                        });
            }
        };
    }

    @Override
    public void doHttpRequest(Map<String, String> map) {

    }

    protected void doHttpRequest2(Object obj) {

    }

}

//类中的BaseView,BasePresenterImpl,GlobalPresenter,都是一次写好的基类,调用者继承使用就好,这里重载HttpPresenter(T view)看到动态创建observable,带等待框,可控制订阅disposable(防止activity退出网络仍然请求,持有View会内存泄漏)

@FormUrlEncoded
    @POST()
    Observable<ResponseBody> doRequestUrl(@Url String url, @FieldMap Map<String, String> map); //动态创建observable,共用post请求

看到我们返回的网络对象会是ResponeBody,由于商业软件都是带加密的,返回一般就是key="?",data="?",我这里的使用方法是用//本地测试 数据对象转化 LoginResponse loginResponse = GlobalCode.getHttpResponse(result, LoginResponse.class); GlobalCode.printLog(loginResponse.getType_id() + "");
大家一般用的都是对象或者map保存我们从网络接收到json字段,所有要写用Gson解析的成

 //解析一个对象 //存在错误收集 httpjson
    public static <T> T getHttpResponse(String result, Class<T> cls) {
        String httpResponse = result;
        JSONObject jsonObject = null;
        //返回的数据{code:0,message:0k,data:{}}
        //我们要判断返回码200(200成功返回JsonObject对象),其他码要弹出错误提示(return null)
        jsonObject = httpJson(httpResponse);
        if (null == jsonObject) return null;
        String jsonstring = String.valueOf(jsonObject);
        T t = null;
        try {
            JSONObject jsonObject1 = new JSONObject(jsonstring);
            JSONObject jsondata = jsonObject1.getJSONObject("data");

//            printLog(String.valueOf(jsondata));
            Gson gson = new Gson();
            t = gson.fromJson(String.valueOf(jsondata), cls);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return t;
    }

咋LoginAty类支持toolbar,mvp解耦

public class LoginAty extends BaseActivity<LoginPresenter2> implements LoginContract.ILoginView
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login_aty);
    }
 @Override
    protected LoginPresenter2 onCreatePresenter() {
        return new LoginPresenter2(this);
    }
 @Override
    public void showHttpResponse(String str) {
        tv_txt.setText(str);
        GlobalCode.printLog("get_log_text" + str);
    }

封装以后大大减少开发代码,很多重用的逻辑都在基类中写好。

2.我们再看列表界面的请求有多快,

public class Recycle2presenter extends ReHttpListPresenter<ReContract.IRecycleView, IdCell> {
    private ReAdapter mAdapter;

    public Recycle2presenter(ReContract.IRecycleView view, String url) {
        super(view, url);
    }

    @Override
    protected Map<String, String> setArgsMap() {
        mArgsMap.put("page", mCurrentPage + "");
        mArgsMap.put("pagesize", 10 + "");

        mArgsMap.put("phone", "13232508893");
        mArgsMap.put("password", "123456");
        mArgsMap.put("type", "PASSWORD");

        return super.setArgsMap();
    }

    @Override
    protected void setReAdapter() {
        super.setReAdapter();
        mAdapter = new ReAdapter(mView.getCurContext(), mDataList, R.layout.list_item, new GlobalReHolder.onItemGlobalClickListener() {
            @Override
            public void onItemClickListener(int position) {
                Toast.makeText(mView.getCurContext(), "pp-" + position, Toast.LENGTH_SHORT).show();
            }
        });
        mView.getReView().setAdapter(mAdapter);
    }

    @Override
    protected void handlerData(String result, boolean ismore) {

        HttpListResponse<IdCell> httpListResponse = GlobalCode.getHttpResponseList(str_json2, IdCell.class);
        GlobalCode.printLog(httpListResponse+"");
        List<IdCell> list = httpListResponse.getSelect();
        mCurrentPage++;
        mPageCount = httpListResponse.getPagination().getPageCount();
        if (ismore) {
            mView.getReView().loadMoreComplete();
        } else {
            mView.getReView().refreshComplete();
        }
        mDataList.addAll(list);  //list=null -->bug?
        mDataList.addAll(list);  //list=null -->bug?
        mDataList.addAll(list);  //list=null -->bug?
        mDataList.addAll(list);  //list=null -->bug?
        mAdapter.notifyDataSetChanged();
    }
     String str_json2 = "{\"code\":\"0\",\"message\":\"获取成功\"," +
            "\"data\":{\"select\":[{\"id\":4,\"user_id\":14,\"name\":\"罗泉清\",\"phone\":\"00989778278\",\"gender\":1,\"car_plate\":\"粤C2N111\",\"id_card\":\"441481199010121111\",\"car_type\":\"大货车\"},{\"id\":6,\"user_id\":14,\"name\":\"罗泉清\",\"phone\":\"00989778005\",\"gender\":1,\"car_plate\":\"粤C2N111\",\"id_card\":\"441481199010124009\",\"car_type\":\"大货车\"}]," +
            "\"pagination\":{\"totalCount\":2,\"pageCount\":2}}}";}

如果你要创建一个列表,你只要创建行数据bean-Idcell,设配器ReAdapter,网络请求传参在setArgsMap(),适配器创建在setReAdapter(),获取到上拉下拉分页数据在handlerData()处理。
在ListAty我们解耦view层的显示里面只有View的初始化,其他业务逻辑都交给Recycle2Presenter实现。

public class ListAty extends BaseActivity<GlobalPresenter> implements ReContract.IRecycleView
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_aty);
        this.setBarTitle("通用类集合窗口");
    }

    //只要重写该方法就可以创建新的listaty.
    @Override
    protected GlobalPresenter onCreatePresenter() {
        return new Recycle2presenter(this,"http://120.24.44.102/fuc/api/web/userapi/login.html");
    }

看到列表Activity,只写了这么少代码,是由于继承封装网络请求的RehttpListpresenter类,该类是专门用于Recycleview分页上拉下拉的网络请求,给你看下里面构造方法实现网络请求的代码,依然是动态url

//必须继承  
    public ReHttpListPresenter(T view, String url) {
        super(view);
        this.mHttpUrl = url;
        this.mModel = new GlobalModel() {
            @Override
            public Observable<ResponseBody> httpMap(String url, Map<String, String> map) {
                return ApiEngine.getInstance().getApiService().doRequestUrl(url + "?page=" + mCurrentPage, map) //注意加密
                        .compose(RxSchedulers.<ResponseBody>io2main())
                        .doOnSubscribe(new Consumer<Disposable>() {
                            @Override
                            public void accept(@NonNull Disposable disposable) throws Exception {
                                addDispoable(disposable);
                            }
                        });
            }
        };
//这里是每次上拉下拉都会调用到数据接收方法,返回的依然是一个ResponseBody,
 protected void loadData(Map<String, String> map, final boolean ismore) {
        mModel.httpMap(mHttpUrl, GlobalCode.encryArgs(map)).subscribe(new Consumer<ResponseBody>() {
            @Override
            public void accept(@NonNull ResponseBody responseBody) throws Exception {
                handlerData(responseBody.string(), ismore);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(@NonNull Throwable throwable) throws Exception {
                GlobalCode.printLog(Log.getStackTraceString(throwable));
                if (ismore) {
                    mView.getReView().loadMoreComplete();
                } else {
                    mView.getReView().refreshComplete();
                }
            }
        });
    }

对于接收到网络jsonobject文本,我们用

//返回一个JsonObject
//我的list数据格式可以看变量str_json2,有分页,你们可以根据自己格式修改函数方法得到//自己想要的,GlobalCode是一个创建一个工具类。
HttpListResponse<IdCell> httpListResponse = GlobalCode.getHttpResponseList(str_json2, IdCell.class);

//public static <T> HttpListResponse<T> getHttpResponseList(String result, Class<T> cls) 

我们注意一下加密,post请求是将参数放到body中,加密用的rsa,aes,我们发到服务器接口的加密数据返回格式会是{code:0,message:"",key:"?",data:"?"},我的请求接口很多带共用的参数,如token,每次请求接口都写这些参数也是浪费,在post请求中用GlobalCode.encryArgs()处理公共参数,已经考虑到加密和不加密,你不要管太多,只传参数就可以,当然传对象也可以我做了封装。。。

对于rxjava使用

大学那会就看rxjava1.0,觉得看不懂,很难用,不想去学,后来在工作中很多参考的项目都用了rxjava2,我就认真学习了,发现你明白以后,码代码是真的快,不用管handler,不用去多次判断某些逻辑(rxbinding),复杂的业务就也好用,例如多层网络嵌套,联合判断,多个网络请求后不同数据更新UI。
它自带的线程调度实在太厉害,精髓是subscribeOn()指定未指定线程的observable(被观察者),且第一次有效,observeOn()每次有效指定线程切换。我开始看他的线程调度方法位置也懵逼的,我靠什么意思,后来看了很多文章感悟出来,有些总结话你每看一次都会有新的感悟,_。如果你要复杂的使用flatmap,scan,filter,map这些操作符,一定要把线程调度理解好,单纯使用没什么切换的就写个ObservableTransformer.
RxTextUtil里面有rxjava2的学习代码。Rxbinding,RxPermission,这些使用难度都不大。
框架代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值