Android Mvp设计模式结合RxJava+OkHttp+retrofit浅谈

前一段时间撸了好久的webview和前端的代码,停下来时间感觉要学点什么东西,在此和大家分享下我对mvp设计模式的理解,可能很多小伙伴项目中也会用到。先上代码,后面附上个人总结。

View层

/** * Created by qiang.lin,view的接口,主要做一些获取用户输入的操作,和界面显示toast,页面跳转。 */public interface LoginViewInterface { void showMsg(String msg); String getUser(); String getPwd(); void startIntent();} public class LoginActivity extends BaseActivity implements View.OnClickListener, LoginViewInterface { @InjectView(R.id.name) EditText name; @InjectView(R.id.pwd) EditText pwd; @InjectView(R.id.skip_register) TextView skipRegister; @InjectView(R.id.forget_pwd) TextView forgetPwd; @InjectView(R.id.login) Button login; private LoginPreInterface loginPreInterface; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); MyApplication.getInstance().getActivityManager().addActivity(this); ButterKnife.inject(this); initView(); initData(); } @Override protected void initData() { } @Override protected void initView() { loginPreInterface=new LoginPreImpl(this); login.setOnClickListener(this); forgetPwd.setOnClickListener(this); skipRegister.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.skip_register: Intent intent = new Intent(LoginActivity.this, RegisterActivity.class); startActivity(intent); break; case R.id.login: loginPreInterface.login(); break; case R.id.forget_pwd: break; } } @Override protected void onDestroy() { super.onDestroy(); MyApplication.getInstance().getActivityManager().finishActivity(this); Log.i("登录界面销毁", "—-"); } @Override public void showMsg(String msg) { Toast.makeText(LoginActivity.this, msg, Toast.LENGTH_LONG).show(); } @Override public String getUser() { return name.getText().toString(); } @Override public String getPwd() { return pwd.getText().toString(); } @Override public void startIntent() { Intent intent=new Intent(LoginActivity.this,MainActivity.class); startActivity(intent); }

在activity里面实现View的接口,主要做一些用户界面操作,我用了butterknife这个插件,这个大家可以去上网百度,快速实例化控件,并且对每个Activity进行管理。
butterknift使用:
添加依赖 compile ‘com.jakewharton:butterknife:6.1.0’
下载bufferknife就行,在setting里面可以直接下载。

P层

import example.com.mvpdesign.view.interfaces.LoginViewInterface;/** * Created by qiang.lin ,登录功能接口 */public interface LoginPreInterface { void login();} /** * Created by qiang.lin 方法回调,成功还是失败 */public interface OnLoginListener { void onFail(); void onSucceed();} /** * Created by qiang.lin,P层的实现类 */public class LoginPreImpl implements LoginPreInterface,OnLoginListener { private LoginViewInterface loginViewInterface; private LoginModel loginModel; public LoginPreImpl(LoginViewInterface loginViewInterface) { this.loginViewInterface = loginViewInterface; loginModel = new LoginModelImpl(this); } @Override public void login() { String pwd = loginViewInterface.getPwd(); String name = loginViewInterface.getUser(); if(pwd.isEmpty()||name.isEmpty()){ loginViewInterface.showMsg("用户信息不全"); return; } loginModel.login(name, pwd); } @Override public void onFail() { loginViewInterface.showMsg("用户名或密码错误"); } @Override public void onSucceed() { loginViewInterface.startIntent(); loginViewInterface.showMsg("登录成功"); }}

Model层

/** * Created by qiang.lin,实体类 */public class Entity<T> { private int code; private T msg; public Entity(int code, T msg) { super(); this.code = code; this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public T getMsg() { return msg; } public void setMsg(T msg) { this.msg = msg; }} /** * Created by qiang.lin m层的功能接口 */public interface LoginModel { void login(String name,String pwd);}

这里开始就要用到网络请求框架和Rxjava。
添加依赖

compile ‘com.squareup.retrofit2:retrofit:2.3.0’ compile ‘com.squareup.okhttp3:okhttp:3.8.1’ compile ‘com.google.code.gson:gson:2.8.1’ compile ‘com.squareup.retrofit2:converter-gson:2.3.0’ compile ‘com.squareup.retrofit2:adapter-rxjava2:2.3.0’ compile ‘io.reactivex.rxjava2:rxjava:2.1.1’ compile ‘io.reactivex.rxjava2:rxandroid:2.0.1’ compile ‘com.squareup.okhttp3:logging-interceptor:3.8.1’ /** * Created by qiang.lin */public class LoginModelImpl implements LoginModel { private OnLoginListener onLoginListener; public LoginModelImpl(OnLoginListener onLoginListener) { this.onLoginListener = onLoginListener; } @Override public void login(String name, String pwd) { RxJavaClient.login(name, pwd, new Observer<Entity>() { private Disposable disposable; private int i; @Override public void onSubscribe(@NonNull Disposable d) { //这里可以判断中断观察者接受数据源,被观察者还是会继续发送剩下数据。 disposable = d; } @Override public void onNext(@NonNull Entity entity) { //网络端发来的请求,disposable会让观察者停止接受数据源,但是被观察者还是会继续发送 //返回的数据在entity里面// i++;// if (i == 6) {// disposable.dispose();// Log.d("—-", "isDisposed : " + disposable.isDisposed());// } boolean flag = isMainThread(); Log.i("—————-是否在主线程上", flag + ""); //根据网络请求的返回码判断调用成功方法还是失败方法。 onLoginListener.onSucceed(); } @Override public void onError(@NonNull Throwable e) { Log.e("rxjava错误日志", e + ""); onLoginListener.onFail(); } @Override public void onComplete() { Log.i("——-onComplete", ""); } }); } //判断是否在主线程上 public boolean isMainThread() { return Looper.getMainLooper().getThread() == Thread.currentThread(); }}

在这里要搭建网络请求框架,我就直接上代码了,直接用。

/** * Created by qiang.lin * 这里要创建一个方法,在retrofitservice也要创建一个方法 *///遇到耗时操作的时候可能要做修改,图片、文件、缓存public class RxJavaClient { //创建实例调用 private static final RetrofitService retrofitService = RetrofitClient.getClient(); //POST请求 public static void login(String name, String pwd, Observer<Entity> observer) { setSubscribe(retrofitService.login(name, pwd), observer); } //公共方法 public static <T> void setSubscribe(Observable<T> observable, Observer<T> observer) { observable.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.newThread())//子线程访问网络 .observeOn(AndroidSchedulers.mainThread())//回调到主线程 .subscribe(observer); }} /** * Created by qiang.lin */public interface RetrofitService { //把原来的retrofit的Call回调换成了rxjava的被观察者,跟网络连接就是被观察者 @Headers("Content-Type:application/json;charset=UTF-8") @FormUrlEncoded @POST("android/login") Observable<Entity> login(@Field("name") String name, @Field("pwd") String pwd);} /** * Created by qiang.lin *///单例模式public class RetrofitClient { private static RetrofitService retrofitService; private static final String TAG=RetrofitClient.class.getSimpleName(); public static RetrofitService getClient() { if (retrofitService == null) { OkHttpClient okClient = new OkHttpClient(); HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); int cacheSize = 10 * 1024 * 1024; // 10 MiB Cache cache = new Cache(MyApplication.getInstance().getCacheDir(), cacheSize);//缓存的目录 OkHttpClient.Builder builder = new OkHttpClient().newBuilder() .connectTimeout(10, TimeUnit.SECONDS)//设置超时时间 .readTimeout(10, TimeUnit.SECONDS)//设置读取超时时间 .writeTimeout(10, TimeUnit.SECONDS)//设置写入超时时间 .addInterceptor(interceptor).addNetworkInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { // 进行重定向等操作 //Interceptor的典型使用场景,就是对request和response的Headers进行编辑 Response response=chain.proceed(chain.request()); Request request = chain.request(); long t1 = System.nanoTime(); Log.d(TAG,String.format("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers())); long t2 = System.nanoTime(); Log.d(TAG, String.format("Received response for %s in %.1fms%n%sconnection=%s", response.request().url(), (t2 – t1) / 1e6d, response.headers(), chain.connection())); Log.i("————response",response.toString()); return response; } }) .cache(cache); okClient = builder.build(); Retrofit client = new Retrofit.Builder() //地址 .baseUrl(Contants.WEB_URL) .client(okClient) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//将Callable接口转换成Observable接口 .build(); retrofitService = client.create(RetrofitService.class); } return retrofitService; }}

到这里一个综合案例就完成了,我基本关键点都有注释,大家可以看看。

总结:1、V层:抽象出获取用户输入和页面更新的接口,实例化P层对象,调用P层的方法,持有
的是P层接口的引用,防止gc回收的时候发现Activity仍持有引用而无法回收,导致oom
2、P层:抽象出具体功能的接口,如Login(interface),然后再Impl方法里面进行实现,
构造器里面传递过来的时候V层的接口class,通过这个来调用V层进行更新。
P层实例化M层的接口,然后调用M层从网络端获取的数据,整合V层过来的数据进行逻辑操作,
操作完成后调用通过接口实例调用V层的更新方法。
3、M层:和mvc里面的M层差不多,调用网络服务,获取数据,把网络服务抽象出来写成工具类。
4、 Android MVP设计模式比较多的采用了多态,通过接口的暴露,让P层持有两个层级的数据,降低了M层和V层的耦合,逻辑操作和视图更新分离,利于单元测试,但是需要些很多个接口类。
做单元测试的时候,可以写一个P层的测试类,这样来测试,因为主要的逻辑操作都在P层,减少了Activity的代码量。
5、真的是接口爆炸,我写了好多的接口,可能到项目大了它的优点就出来了。

以上仅代表博主本人的个人见解,如果不恰当的地方,可留言纠正。