• 从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木有关系的,但是是实际项目中都可能遇到的一些通用封装,适合自己的项目的框架才是最好的,这里只是做个操练,另外代码实现的细节倒不是太重要,重要的是对框架的思想的理解。

  • 相关阅读:
    【02】SASS与SCSS
    【02】sass更新的方法
    10.19 dig:域名查询工具
    10.7 netstat:查看网络状态
    10.6 ip:网络配置工具
    S11 Linux系统管理命令
    11.19 rpm:RPM包管理器
    11.20 yum:自动化RPM包管理工具
    11.2 uptime:显示系统的运行时间及负载
    11.3 free:查看系统内存信息
  • 原文地址:https://www.cnblogs.com/webor2006/p/12461936.html
Copyright © 2020-2023  润新知