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 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 * @return */ public static T getNetWorkApi(Class 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 getAllBus(@Header("Cookie") String session); @POST("pda/mobileLogin.action") Observable login(@Query("username") String userName, @Query("password") String pwd, @Query("devId") String did); @POST("pda/mobileLogin.action") Observable login2(@QueryMap Map 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 oblogin = new Observer() { @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 opts = new HashMap() ; 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() { @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去掉了,不能够直接看效果。
源码
更多相关文章
- 在Android中自定义捕获Application全局异常,可以替换掉系统的强制
- 还在用Android(安卓)Studio看接口日志?一款可视化的Debug调试工具
- Android(安卓)自定义View界面大合集
- android自定义button样式【转】
- android实现屏幕滑动(类似主屏滑动第一屏---->到第2屏)
- java/android 设计模式学习笔记(8)---桥接模式
- android 项目中使用到的网络请求框架以及如何配置好接口URL
- android 源码设计模式之--代理模式(Proxy)
- Android自定义控件系列案例【二】