Android MVP+RXJava+Retrofit框架的初步构建

之前看了关于MVP、RXJava、Retrofit的开发资料就尝试把它们都整合在一起,这里介绍的内容和搭建的框架是基于我的理解去做的,而且也是初步去构建自己的开发框架,所以难免会有理解不到的地方,不敢保证一点bug都没有,也不建议大家用到真实的项目中去,只是拿来学习。

一、MVP模式的简介

这里写图片描述
view则用来展示数据,显示界面,业务的的处理就交给Presenter 来处理,数据的访问存储就交给Model 来处理,这样分工比较明确,逻辑也清晰,修改起来也比较方便。
(1)其中View可以对应着Activity、Fragment;
(2)Presenter就是一个中介,响应View发出的请求,同时去调用Model来处理,最后也会把请求的结果返回到view中去;
(3)model响应Presenter的请求,并把请求结果返回给presenter,比如请求网络的工作就可以交给它来做;
(4)它们通过接口来实现相互之间的调用。

二、基础框架的搭建

1、Retrofit的构建

(1) 添加依赖库

这里写图片描述
我这里把它做成依赖库,这样就可以给其它app公用了,就是netlib,
然后在它的build.gradle添加依赖库。

    compile 'com.squareup.okhttp3:okhttp:3.2.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0'
    compile 'com.squareup.retrofit2:converter-scalars:2.0.0'
    compile 'com.squareup.retrofit2:retrofit:2.0.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
    compile 'io.reactivex:rxjava:1.0.10'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
(2)设置OkHttp

a.可以设置日志信息
b.获取头部信息,比如sessionid,我这里就有获取到登录返回的session
c.设置超时的时间

public class OkhttpManage {
    //超时时间,60s
    private final static long timeOut=60;
    private static OkHttpClient okHttpClient;
    public static OkHttpClient getOkHttp(Context applicationContext){
        if(okHttpClient==null){
            //日志
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
            okHttpClient = new OkHttpClient().newBuilder()
                    .connectTimeout(timeOut, TimeUnit.SECONDS)
                    .addInterceptor(new GetCookiesInterceptor(applicationContext))
                    .addInterceptor(logging)
                    .build();
        }
        return okHttpClient;
    }

    /**
     * 获取请求头信息,保存cookie
     */
    static class GetCookiesInterceptor implements Interceptor {
        Context context;
        SharedPreferences sp;
        SharedPreferences.Editor editor;
        public GetCookiesInterceptor(Context context){
            this.context = context;
            sp = context.getSharedPreferences("Cookie",Context.MODE_PRIVATE);
            editor = sp.edit();
        }
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response originnalResponse=null;
            try {
                originnalResponse = chain.proceed(chain.request());
                if (!originnalResponse.headers("Set-Cookie").isEmpty()) {
                    List<String> header = originnalResponse.headers("Set-Cookie");
                    for (String s : header) {
                        if (s.contains("JSESSIONID")) {
                            editor.putString("cookie",s.split(";")[0]);
                            editor.commit();
                        }
                    }
                }
            }catch (Exception e){
                if(e instanceof java.net.SocketTimeoutException){
                    new LThread(context,1).start();
                    System.out.println("GetCookiesInterceptor  超时:");
                }else if(e instanceof java.net.ConnectException){
                    new LThread(context,0).start();
                    System.out.println("网络不通");
                }
                e.printStackTrace();
            }
            return originnalResponse;
        }
    }
    static class LThread extends Thread{
        Context context;
        int flag;
        public LThread(Context context,int flag){
            this.context = context;
            this.flag=flag;
        }
        @Override
        public void run() {
            Looper.prepare();
            Handler h = new Handler(){
                @Override
                public void dispatchMessage(Message msg) {
                    if(msg!=null&&msg.what==0){
                        Toast.makeText(context,"网络不通,请检查网络",Toast.LENGTH_SHORT).show();
                    }else if(msg!=null&&msg.what==1){
                        Toast.makeText(context,"请求超时",Toast.LENGTH_SHORT).show();
                    }
                }
            };
            h.sendEmptyMessage(flag);
            Looper.loop();
        }
    }

}
(3)创建retrofit的管理类

其中泛型就是下文提到的Model定义的接口,用gson处理返回的数据,用Rxjava做处理数据的适配器。

public class RetrofitManage {

    /**
     * @param tClass 自定义的请求接口
     * @param baseUrl 请求基本路径
     * @param context 请求上下文
     * @param <T>
     * @return
     */
    public static <T> T getNetWorkApi(Class<T> tClass,String baseUrl,Context context){
        Converter.Factory gsonConverterFactory = GsonConverterFactory.create();
        Converter.Factory scalarsConverterFactory = ScalarsConverterFactory.create();
        CallAdapter.Factory rxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create();
        Retrofit retrofit = new Retrofit.Builder()
                .client(OkhttpManage.getOkHttp(context))
                .baseUrl(baseUrl)
                .addConverterFactory(scalarsConverterFactory)
                .addConverterFactory(gsonConverterFactory)
                .addCallAdapterFactory(rxJavaCallAdapterFactory)
                .build();
        return retrofit.create(tClass);
    }

}

2、MVP的构建

(1)定义view的接口

这是用在activity或fragment上显示数据的,根据自己实际的需要定义即可。

public interface GetDataInterface {
     //登录成功的回调
     void loginSuccess(UserInfoResult userInfoResult);
     //错误信息的显示
     void onError(Throwable e);
     //查询数据成功的回调
     void getBusSuccess(AllBusinessResult allBusinessResult);
}
(2)定义presenter 的接口
public interface Loginpresenter {
    public  void getAllBus(@NonNull String session);
    public void login(String userName, String pwd, String did);
}
(3)定义model接口

这是retrofit的,其中@post代表post请求
a.参数@Header(“Cookie”) String session ,就是要添加到叫“Cookie”头部的内容,根据实际需求修改即可。
b.参数@Query(“username”) String userName,就是请求的参数有username=””
c.像上面一个一个写比较多的时候就不友好了,可以用
@QueryMap Map

public interface LoginAndOther {
    @POST("pda/queryGlobalQuantityByDay.action")
    Observable<AllBusinessResult> getAllBus(@Header("Cookie") String session);
    @POST("pda/mobileLogin.action")
    Observable<UserInfoResult> login(@Query("username") String userName,
                                     @Query("password") String pwd, @Query("devId") String did);
    @POST("pda/mobileLogin.action")
    Observable<UserInfoResult> login2(@QueryMap Map<String,String> opts);
}
(4)实现presenter定义的接口

a、baseUrl就是基本的路径,最好以“/”结尾,这里涉及到公司内容,我就不显示它的路径了

b、GetDataInterface gt; 就是上面定义的view 的接口

c、CompositeSubscription ss;//是RXJava 的内容,用来管理subscription

d、通过RetrofitManage.getNetWorkApi来进行网络请求,这在上面的Retrofit构建里设置的,同时也调用到model的接口了,这是Retrofit的使用

e、subscribeOn(Schedulers.io())可以让请求运行在其它的线程中,
observeOn(AndroidSchedulers.mainThread())可以让显示数据操作运行在主线程中去,
subscribe(oblogin) 用来处理数据、显示数据等操作,并在这个参数的对象里面调用View的接口,即GetDataInterface gt,这样MVP就相互关联起来了,请求数据不会再主线程中,显示数据又回到主线程中去。

 Subscription s = RetrofitManage.getNetWorkApi(LoginAndOther.class,baseUrl,context.getApplicationContext())
                .login2(opts)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(oblogin);
        ss.add(s);
public class LoginImpl implements Loginpresenter{
    Context context ;
    CompositeSubscription ss;
    String baseUrl = "";
    GetDataInterface gt;
    public LoginImpl(Context context, GetDataInterface gt,CompositeSubscription ss){
        this.context = context;
        this.ss = ss;
        this.gt = gt;
    }
    Observer<UserInfoResult> oblogin = new Observer<UserInfoResult>() {
        @Override
        public void onCompleted() {
            Log.d("omCompleted","请求完成");
            System.out.println("请求完成");
        }
        @Override
        public void onError(Throwable e) {
            gt.onError(e);
            Log.d("onError",e.getMessage());
            e.printStackTrace();
        }
        @Override
        public void onNext(UserInfoResult userInfoResult) {
            gt.loginSuccess(userInfoResult);
            System.out.println(userInfoResult.toString());
            Log.d("userInfoResult ",userInfoResult.success);
        }
    };


    @Override
    public  void login(String userName, String pwd, String did) {
        Map<String,String> opts = new HashMap<String, String>() ;
        opts.put("username",userName);
        opts.put("password",pwd);
        opts.put("devId",did);
        Subscription s = RetrofitManage.getNetWorkApi(LoginAndOther.class,baseUrl,context.getApplicationContext())
                .login2(opts)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(oblogin);
        ss.add(s);
    }

    @Override
    public void getAllBus(String session) {
        Subscription s = RetrofitManage.getNetWorkApi(LoginAndOther.class,baseUrl,context)
                .getAllBus(session)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<AllBusinessResult>() {
                    @Override
                    public void onCompleted() {
                        Log.d("omCompleted","请求完成");
                        System.out.println("请求完成");
                    }

                    @Override
                    public void onError(Throwable e) {
                        if(e==null)return;
                        Log.d("onError",e.getMessage());
                        e.printStackTrace();
                    }

                    @Override
                    public void onNext(AllBusinessResult allBusinessResult) {
                        gt.getBusSuccess(allBusinessResult);
                    }
                });
        ss.add(s);
    }
    public void destroySubscription(){
        System.out.println("unsubscribe");
        ss.unsubscribe();
    }
}
(5) 在activity或fragment中实现已经定义view的接口

a、就是上面定义的GetDataInterface
b、定义presenter
Loginpresenter lp;
lp = new LoginImpl(this,this,subscriptions);
c、这样就可以通过lp来调用它里面的方法了,比如请求数据

public class DemoActivity extends BaseActivity implements View.OnClickListener,GetDataInterface

三、总结

这是自己动手搭建的框架,其中也遇到不少问题,也参考了RxJavaSamples-master的代码,也是一种尝试。
有需要的也可以下载源码,但是我把url去掉了,不能够直接看效果。
源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值