从0来搭建超灵活的MVP商用框架<三>-------网络层加入RxJava、事件总线封装、Dagger2集成

继续接着上一次https://www.cnblogs.com/webor2006/p/12455238.html的框架进行进一步的完善。

网络层加入RxJava:

商用项目中对于网络层精典的搭配当属于“OkHttp+Retrofit+RxJava”了,所以这里也不例外,准备加入RxJava,先添加依赖:

然后再建一个新的包,用来存放RxJava相关的包:

然后这里基于Retrofit的框架进行改造,不过这里还是保留单纯Retrofit的使用方式,其实要变成RxJava的方式也不是很麻烦,之前https://www.cnblogs.com/webor2006/p/10545699.html对于怎么变成RxJava的风格也已经学习过了,所以一些细节就不详细来阐述了,为了能够转换成RxJava,首先得在Retrofit配置中增加一个Adapter:

然后再来定义请求接口,比如简单:

package com.android.core.net.rx;

import java.util.Map;

import io.reactivex.Observable;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Part;
import retrofit2.http.QueryMap;
import retrofit2.http.Streaming;
import retrofit2.http.Url;

public interface RxRestService {
    @GET
    Observable<String> get(@Url String url, @QueryMap Map<String, Object> params);

    @FormUrlEncoded
    @POST
    Observable<String> post(@Url String url, @FieldMap Map<String, Object> params);

    @FormUrlEncoded
    @PUT
    Observable<String> put(@Url String url, @FieldMap Map<String, Object> params);

    @DELETE
    Observable<String> delete(@Url String url, @QueryMap Map<String, Object> params);

    //下载是直接到内存,所以需要 @Streaming
    @Streaming
    @GET
    Observable<ResponseBody> download(@Url String url, @QueryMap Map<String, Object> params);

    //上传
    @Multipart
    @POST
    Observable<String> upload(@Url String url, @Part MultipartBody.Part file);

    //原始数据
    @POST
    Observable<String> postRaw(@Url String url, @Body RequestBody body);

    @PUT
    Observable<String> putRaw(@Url String url, @Body RequestBody body);
}

这就没啥可解释的,就是将之前的Call换成了Observable了,然后再来建立相关的Client,还是利用构建者模式:

package com.android.core.net.rx;


import com.android.core.net.HttpMethod;
import com.android.core.net.RestCreator;

import java.io.File;
import java.util.HashMap;

import io.reactivex.Observable;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;

public class RxRestClient {
    private final HashMap<String, Object> PARAMS;
    private final String URL;
    private final RequestBody BODY;
    //上传下载
    private final File FILE;


    public RxRestClient(HashMap<String, Object> params,
                        String url,
                        RequestBody body,
                        File file) {
        this.PARAMS = params;
        this.URL = url;
        this.BODY = body;
        this.FILE = file;

    }

    public static RxRestClientBuilder create() {
        return new RxRestClientBuilder();
    }

    //开始实现真实的网络操作
    private Observable<String> request(HttpMethod method) {
        final RxRestService service = RestCreator.getRxRestService();
        Observable<String> observable = null;

        switch (method) {
            case GET:
                observable = service.get(URL, PARAMS);
                break;
            case POST:
                observable = service.post(URL, PARAMS);
                break;
            case PUT:
                observable = service.put(URL, PARAMS);
                break;
            case DELETE:
                observable = service.delete(URL, PARAMS);
                break;
            case UPLOAD:
                final RequestBody requestBody = RequestBody.create(MultipartBody.FORM, FILE);
                final MultipartBody.Part body = MultipartBody.Part.createFormData(
                        "file", FILE.getName(), requestBody);
                observable = service.upload(URL, body);
                break;
            default:
                break;
        }
        return observable;
    }


    //各种请求
    public final Observable<String> get() {
        return request(HttpMethod.GET);
    }

    public final Observable<String> post() {
        return request(HttpMethod.POST);
    }

    public final Observable<String> put() {
        return request(HttpMethod.PUT);
    }

    public final Observable<String> delete() {
        return request(HttpMethod.DELETE);
    }

    public final Observable<String> upload() {
        return request(HttpMethod.UPLOAD);
    }

    public final Observable<ResponseBody> download() {
        return RestCreator.getRxRestService().download(URL, PARAMS);
    }

}
package com.android.core.net.rx;


import java.io.File;
import java.util.HashMap;

import okhttp3.MediaType;
import okhttp3.RequestBody;

public class RxRestClientBuilder {
    private HashMap<String, Object> mParams;
    private String mUrl;
    private RequestBody mBody;

    //上传下载
    private File mFile;

    RxRestClientBuilder() {

    }

    public final RxRestClientBuilder url(String url) {
        this.mUrl = url;
        return this;
    }

    public final RxRestClientBuilder params(HashMap<String, Object> params) {
        this.mParams = params;
        return this;
    }

    public final RxRestClientBuilder raw(String raw) {
        this.mBody = RequestBody.create(
                MediaType.parse("application/json;charset=UTF-8"), raw);
        return this;
    }

    //上传
    public final RxRestClientBuilder file(File file) {
        this.mFile = file;
        return this;
    }

    public final RxRestClientBuilder file(String file) {
        this.mFile = new File(file);
        return this;
    }


    public final RxRestClient build() {
        return new RxRestClient(mParams, mUrl, mBody, mFile);
    }
}

其中这块得增加一个获取RxRestService的方法:

这里就不去调用了,比较简单。

事件总线封装:

接下来做写个类似于RxBus的东东来改善MVP中的代码,哪一块代码呢?

对于MVP中的数据请求,往往是Model层进行数据的加载,然后加载完的数据通过回调接口返给P层,然后P层再来调用V进行数据展现,如下:

嗯,那有啥问题么?当然没啥问题,只是需要定义多余的回调接口嘛:

那用RxBus来解决不就行了嘛,这里自己来实现一个,比较简单,先来定义一个注解:

package com.android.core.net.rx.databus;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RegisterRxBus {
    String value();
}
package com.android.core.net.rx.databus;


import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public class RxBus {
    //订阅者集合
    private Set<Object> subscribers;

    //volatile 自带线程安全(禁止指令重排)
    private static volatile RxBus instance;

    private RxBus() {
        //读写分离的集合
        subscribers = new CopyOnWriteArraySet<>();
    }

    public static synchronized RxBus getInstance() {
        if (instance == null) {
            synchronized (RxBus.class) {
                if (instance == null) {
                    instance = new RxBus();
                }
            }
        }
        return instance;
    }

    /**
     * 注册
     */
    public synchronized void register(Object subscriber) {
        subscribers.add(subscriber);
    }

    /**
     * 取消注册
     */
    public synchronized void unRegister(Object subscriber) {
        subscribers.remove(subscriber);
    }

}

其中由于这条总线会存大多线程经常访问的情况,所以对于线程的同步比较讲究,订阅集合也采用线程安全比较高的CopyOnWriteArraySet了,接下来则需要来处理数据,最终来回调订阅集合中标有RegisterRxBus注解的方法了,这里采用RxJava的方式,具体如下:

package com.android.core.net.rx.databus;


import java.lang.reflect.Method;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

public class RxBus {
    //订阅者集合
    private Set<Object> subscribers;

    //volatile 自带线程安全(禁止指令重排)
    private static volatile RxBus instance;

    private RxBus() {
        //读写分离的集合
        subscribers = new CopyOnWriteArraySet<>();
    }

    public static synchronized RxBus getInstance() {
        if (instance == null) {
            synchronized (RxBus.class) {
                if (instance == null) {
                    instance = new RxBus();
                }
            }
        }
        return instance;
    }

    /**
     * 注册
     */
    public synchronized void register(Object subscriber) {
        subscribers.add(subscriber);
    }

    /**
     * 取消注册
     */
    public synchronized void unRegister(Object subscriber) {
        subscribers.remove(subscriber);
    }

    /**
     * 把处理过程包装起来
     * function:就是用户的操作
     */
    public void chainProcess(Function function) {
        Observable.just("")
                .subscribeOn(Schedulers.io())
                .map(function)//在这里进行网络操作
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Object>() {
                    @Override
                    public void accept(Object data) throws Exception {
                        //上面的function的处理结果就会到data上
                        if (data == null) {
                            return;
                        }
                        //把数据发送到表示层
                        send(data);
                    }
                });
    }

    public void send(Object data) {
        for (Object subscriber : subscribers) {
            //扫描注解,将数据发送到注册的对象标记的位置(一个方法)
            //subscriber表示层
            callMethodByAnnotation(subscriber, data);
        }

    }

    private void callMethodByAnnotation(Object target, Object data) {
        //1.得到presenter中写的所有的方法
        Method[] methodArray = target.getClass().getDeclaredMethods();
        for (int i = 0; i < methodArray.length; i++) {
            try {
                //2.如果哪个方法上用了我们写的注解,就把数据输入
                if (methodArray[i].getAnnotation(RegisterRxBus.class) != null) {
                    Class paramType = methodArray[i].getParameterTypes()[0];
                    if (data.getClass().getName().equals(paramType.getName())) {
                        //执行
                        methodArray[i].invoke(target, new Object[]{data});
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


    }

}

好,此时咱们就可以利用这个事件总线来优化我们的MVP的代码了,具体修改如下:

然后在MainActivity中来具体实现一下:

此时则需要在P中定义一个订阅方法:

接下来Model的接口就可以去掉回调方法了:

然后实现的Model就变为:

此时就用了RxBus改造完了。

Dagger2集成:

接下来则加入Dagger2的功能,让一些强new的对象变为注入的方式,来加大框架的灵活度,关于它的用法在之前https://www.cnblogs.com/webor2006/p/12392271.html已经详细学习过了, 那怎么将其加入到咱们目前的框架当中呢?这里简单演示一下,在Activity中我们使用了Http请求数据了,如下:

所以此时需要用我们封装的Http的框架来进行数据的请求,这里就最合适用Dagger的方式了,具体下面简单演示一下:

先引入依赖包:

先定义Module,里面提供对像的创建:

package com.android.mvparcstudy.di;

import com.android.isolation_processor.httpprocessor.HttpHelper;

import dagger.Module;
import dagger.Provides;

@Module
public class HttpModule {
    @Provides
    public HttpHelper providerHttpHelper() {
        return HttpHelper.obtain();
    }
}

然后再到组件中进行Module的注册:

package com.android.mvparcstudy.di;

import com.android.mvparcstudy.MainActivity;

import dagger.Component;

@Component(modules = {HttpModule.class})
public interface HttpComponent {
    void injectMainActivity(MainActivity activity);
}

此时编译一下,然后在Activity中进行注入:

这里就简单用一下既可,在实际项目中如果有对像不想硬new的话,就都可以采用Dagger2框架来注入,具体根据实际需要再来用它既可。

关于MVP框架的封装就到这了,里面有很多是跟MVP木有关系的,但是是实际项目中都可能遇到的一些通用封装,适合自己的项目的框架才是最好的,这里只是做个操练,另外代码实现的细节倒不是太重要,重要的是对框架的思想的理解。

原文地址:https://www.cnblogs.com/webor2006/p/12461936.html