个人对MVP+RxJava+Retrofit框架的理解

闲来无事想起好久没看文章了,也没写什么东西,心血来潮将自己对MVP+RxJava+Retrofit框架的理解记录下来方便以后回看,

相信很多开发者都知道目前常用流行的开发网络框架,MVC,MVP,包括MVP变种的passive  view,MVVM等,现在来结合代码来谈谈,首先我有必要说说MVC这个伴随自己一年的伙计,MVC的流程大概如下1、view接受用户请求。2、view传递请求给Controller。3、Controller操作model进行数据更新。4、model通知view变化,5、view显示数据。其实我们一般没这么复杂,都是一个对象类,然后不管什么都往activity里面放,所以传统的MVC很少去细化。下面着重说说MVP,MVP将请求和数据显示严格的区分开,不再什么都去activity中去操作了,请求我们就在M层中去操作,V层显示数据,P层作为两者的纽带来处理业务逻辑。

首先我们引入rxjava和retrofit远程仓库

compile "io.reactivex.rxjava2:rxjava:$rootProject.ext.rxjava2Version"
compile "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofit2Version"
compile "com.squareup.retrofit2:converter-scalars:$rootProject.ext.retrofit2Version"
compile "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofit2Version"
compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.ext.retrofit2Version"
compile "com.trello.rxlifecycle2:rxlifecycle:$rootProject.ext.rxlifecycle"
//compile "com.trello.rxlifecycle2:rxlifecycle-android:$rootProject.ext.rxlifecycle"
compile "com.trello.rxlifecycle2:rxlifecycle-components:$rootProject.ext.rxlifecycle"
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

其次我们要去初始化retrofit的,retrofit是基于OkHttp框架的封装。

public class RetrofitHelper {

    private static OkHttpClient client;
static {
    initClient();
    }
    public static IApiService getBook(){
        return  creatService(IApiService.class,IApiService.Host);
    }

    public static <T> T creatService(Class<T> clzz, String s) {
      Retrofit  retrofit = new Retrofit.Builder()
              .baseUrl(s)
              .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
              .addConverterFactory(GsonConverterFactory.create())
              .client(client)
              .build();

      return retrofit.create(clzz);
    }

    private static void initClient(){
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                try {
                    String text = URLEncoder.encode(message,"utf-8");
                    LoggUtils.e("http",text);
                }catch (Exception e){
                    e.printStackTrace();
                    LoggUtils.e("http",e.getMessage());
                }
            }
        });
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        class  NetIntercepter implements Interceptor{
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                if (request.method().equals("POST")) {
                    if (request.body() instanceof FormBody) {
                        request = addPostFormParams(request);
                    } else if (request.body() instanceof MultipartBody) {
                        request = addPostMultiParams(request);
                    }
                } else if (request.method().equals("GET")) {
                    request = addGetParams(chain);
                }
                return chain.proceed(request);
            }
        }
        client= new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .connectTimeout(IApiService.TIMEOUT, TimeUnit.MILLISECONDS)
                .addNetworkInterceptor(new NetIntercepter())
                .build();
    }

    private static Request addPostMultiParams(Request request) {
        MultipartBody.Builder builder = new MultipartBody.Builder().addFormDataPart("deviceId","123456");
        MultipartBody body = (MultipartBody) request.body();
        for (int i = 0;i<body.size();i++){
            builder.addPart(body.part(i));
        }
        body  = builder.build();
        request = request.newBuilder().post(body).build();
        return request;
    }

    /**
     * get请求数据提交的方法
     * @param chain
     * @return
     */
    private static Request addGetParams(Interceptor.Chain chain) {
        Request request = chain.request();
        HttpUrl urlBuilder = request.url()
                .newBuilder()
                .addQueryParameter("deviceId", "123456").build();
        request = request.newBuilder()
                .url(urlBuilder)
                .build();
        return request;
    }

    /**
     * post  请求提交数据的方法
     * @param request
     * @return
     */
    private static Request addPostFormParams(Request request) {
        FormBody.Builder builder = new FormBody.Builder();
        FormBody body = (FormBody) request.body();
        for (int i = 0;i<body.size();i++){
            builder.addEncoded(body.encodedName(i),body.encodedValue(i));
        }
        body = builder.addEncoded("deviceId","123456").build();
        request = request.newBuilder().post(body).build();
        return request;
    }
}

剩下的我们来建一个服务接口,IApiService,

public interface IApiService {
    long TIMEOUT = 15000;
    String Host = "https://api.xxxx.com/";//这是服务器地址
//    String Srevice_Url = Host+"api/random/";

    @GET("xxxxx")//这是接口地址
    Observable<BaseBean<List<Book>>> searchBook(@Query("q") String bookName);
}

所有的接口全部在在这里进行全面管理。

当然我们还需要一个最重要的点就是,我们网络请求的方法。

public abstract class DefaultObservable<T> implements Observer<BaseBean<T>> {

    @Override
    public void onSubscribe(Disposable d) {

    }


    @Override
    public void onNext(BaseBean<T> tBaseBean) {
        if (tBaseBean.getCount()>0){
            sucess(tBaseBean.getBooks());
        }else {
            onFail("服务异常");
        }

    }

    @Override
    public void onError(Throwable e) {
        if (e instanceof ParseException    || e instanceof JSONException
                || e instanceof ParseException){
            ToastUtils.show("解析错误");
        }else if ( e instanceof HttpException){
            ToastUtils.show("网络错误");
        }else if (e instanceof ConnectException){
            ToastUtils.show("连接错误");
        }else if (e instanceof  InterruptedException){
            ToastUtils.show("连接超时");
        }else {
            ToastUtils.show("未知错误");
        }

    }

    @Override
    public void onComplete() {

    }
    public abstract  void  sucess(T t);

    public abstract  void  showError(String msg);

    public void onFail(String t){
        if (TextUtils.isEmpty(t)) {
            ToastUtils.show(t);
        } else {
            ToastUtils.show(t);
        }
    }

}
这个类是Retrofit中重要的东西,这个是接收推送通知的一个接口,说白了,就是对请求做出回应,类似httpclient中的response。

MVP很重要的一个点就是,我们必须和服务端约定返回数据的格式,

public class BaseBean <T> {
  public  int  code;
 
public  String message;
public  T t;//t代表的是我们各个数据模型的泛型。
}

我们建一个baseBean来存放约定的数据格式,比如我需要一个student类,那么我就用student类来继承basebean。

至此,前戏网络框架结构已经完成,接下来我们针对MVP来说说。

1、M层   会有一个BaseModel接口,里面方法自定定义这个接口主要用来定义Model层的共有方法。

其次会有一个对应类MyMOdel(代表不同的业务model)请求数据,

public class SearchModel implements BaseModel{
    public DefaultObservable<List<Book> >getData(final MyCallBack<Book> callBack) {
        return new DefaultObservable<List<Book>>() {
            @Override
            public void sucess(List<Book> bean) {
                for (Book book : bean) {
                    callBack.loadSucess(book);
                }
            }
            @Override
            public void showError(String mag) {
                    callBack.loadError(mag);
            }
        };
    }
}
P 层  因为P层是M  和  V  的纽带,所以这里有一个BasePresenter来连接M  V,并初始化 M  V;
public class BasePresenter<V extends BaseView,M extends BaseModel> {

    public V mView;
    public M mModel;

public void setPresenter(V view,M model){
    this.mView = view;
    this.mModel = model;
}
public void setPresenter(V view){
    this.mView = view;
}

}

其次对应的还有各个presenter,

public class SearchPresenter extends BasePresenter<SearchView, SearchModel>{
    public void  searchBook(String name){
        RetrofitHelper.getBook().searchBook(name)
                .subscribeOn(Schedulers.io())//运行在子线程,表示读取
                .observeOn(AndroidSchedulers.mainThread())//运行在主线程
                .subscribe(mModel.getData(new MyCallBack<Book>() {
                    @Override
                    public void loadSucess(Book book) {
                        mView.searchSusses(book);
                    }

                    @Override
                    public void loadError(String t) {
                        mView.searchFail(t);
                    }
                }));

    }

}
我们看到,P实际的作用就是通过model来获取数据,然后将数据交个V层显示。

V  层  同理需要有一个BaseView接口来定义所有V层共有的方法

public interface BaseView {
    LifecycleTransformer bindLifecycle();
}
记住,我们需要在 BaseView 中来使用第三方的rxlifecycle,他可以让Observable发布的事件和当前的组件绑定,实现生命周期同步。从而实现当前组件生命周期结束时,自动取消对Observable订阅。

对应的View  

public interface SearchView extends BaseView{
    void searchSusses(Book book);//数据返回成功要做的事

    void searchFail(String errorMsg);

}

得到数据后要做的逻辑。

但是 , 但是 ,但是 重要事情说三遍,Google Assistant官方确不建议这样写,这样写的逻辑上没错,但会是开发流程更加复杂,

接口多余,毫无意义的代码变多,如果我们修改了对应presenter中逻辑,那么我们还需要修改presenter接口中的逻辑;很不方便,官方建议写

一个契约类来实现管理,一眼可以看到,所有的方法统一由契约类来管理,所以修改如下;

public interface BookContract {

interface View extends BaseView<Presenter> {

 void Susses(Book book);//数据返回成功要做的事

 void Fail(String errorMsg);
}

    abstract Presenter extends BasePresenter<View,Model>{

   public void abstract  getBook();

}

}

可以看到,契约类将P和V都统一起来管理。这样我们可以简化开发流程,更加明确了MVP各个层的工作解耦。

推荐一下MVP官方实现的文章。点击打开链接

MVP(Model View Presenter)其实就是一种项目的整体框架,能让你的代码变得更加简洁,说起框架大家可能还会想到MVC、MVVM。由于篇幅原因,这里我们先不讲MVVM,先来看一下MVC。其实Android本身就采用的是MVC(Model View Controllor)模式、其中Model指的是数据逻辑和实体模型;View指的是布局文件、Controllor指的是Activity。对于很多Android初学者可能会有这样的经历,写代码的时候,不管三七二十一都往Activity中写,当然我当初也是这么干的,根本就没有什么框架的概念,只要能实现某一个功能就很开心了,没有管这么多。当然项目比较小还好,一旦项目比较大,你会发现,Activity所承担的任务其实是很重的,它既要负责页面的展示和交互,还得负责数据的请求和业务逻辑之类的工作,相当于既要打理家庭,又要教育自己调皮的孩子,真是又当爹又当妈。。。那该怎么办呢?这时候Presenter这个继父来到了这个家庭。Presenter对Activity说,我来了,以后你就别这么辛苦了,你就好好打理好View这个家,我专门来负责教育Model这孩子,有什么情况我会向你反映的。这时Activity流下了幸福的眼泪,从此,Model、View(Activity)、Presenter一家三口过上了幸福的生活。。。好了磕个药继续,由于Presenter(我们自己建的类)的出现,可以使View(Activity)不用直接和Model打交道,View(Activity)只用负责页面的显示和交互,剩下的和Model交互的事情都交给Presenter做,比如一些网络请求、数据的获取等,当Presenter获取到数据后再交给View(Activity)进行展示,这样,Activity的任务就大大减小了。这便是MVP(Model 还是指的数据逻辑和实体模型,View指的是Activity,P就是Presenter)框架的工作方式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值