基于Retrofit2+OkHttp3+RxJava实现的MVP框架(2)

接上一篇《基于Retrofit2+OkHttp3+RxJava实现的MVP框架(1)》- 点击打开链接

上一篇我们介绍了目前MVP架构中的V和P的实现以及关联沟通方案,但是我认为业务核心是数据,它是业务的根基。那么这篇将着重讲解MVP中的Model模块,以及Model如何与Presenter完成数据交互的。

标题中我们已经透露了,该方案实现中用到的框架是Retrofit2、OkHttp3以及RxJava。我们这里设计的Model模块部分,主要是针对HTTP网络请求类型的数据,如果要考虑本地数据或者其他,结合RxJava一样可以实现。

首先,上一张类图。


从图中看到绿色部分,是MVP的核心类,BasePresenter和BaseView前篇已经介绍过。现在着重讲一下BaseManager及其他类。

ServiceFactory

public class ServiceFactory {
    private static String TAG = ServiceFactory.class.getSimpleName();

    private static class SingletonHolder {
        private static final ServiceFactory INSTANCE = new ServiceFactory();
    }

    /**
     * Singleton function
     * @return
     */
    public static ServiceFactory getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private OkHttpClient mClient;

    private Retrofit mRetrofit;

    private static Context sContext;

    /**
     * Should be called at beginning of process
     * @param context
     */
    public static void initContext(Context context) {
        sContext = context;
    }

    private ServiceFactory() {
        initRetrofit();
    }

    // init configuration of retrofit and okhttp
    private void initRetrofit() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // print the log using interceptor
        builder.addInterceptor(
                new HttpLoggingInterceptor().setLevel(
                        HttpLoggingInterceptor.Level.BODY));
        // http request&response cache dir and file
        File file = new File(sContext.getExternalCacheDir(),
                Configuration.HTTP_CACHE_DIR);
        Cache cache = new Cache(file, Configuration.HTTP_CACHE_SIZE);
        mClient = builder
                .retryOnConnectionFailure(true)
                .connectTimeout(Configuration.HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(Configuration.HTTP_READ_WRITE_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(Configuration.HTTP_READ_WRITE_TIMEOUT, TimeUnit.SECONDS)
                .addInterceptor(new CacheInterceptor()) // ? application interceptor
                .addNetworkInterceptor(new CacheInterceptor()) // ? network interceptor
                .cache(cache)
                .build();
        // init retrofit
        mRetrofit = new Retrofit.Builder()
                .baseUrl(Configuration.HTTP_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // ? async observables
                .client(mClient)
                .build();
    }

    /**
     * Create service object according to retrofit structure
     * @param service
     * @param <T>
     * @return
     */
    public <T> T create(final Class<T> service) {
        if (service == null) {
            throw new RuntimeException("Api service is null!");
        }
        return mRetrofit.create(service);
    }
ServiceFactory,是作为协议接口的创建者,其实是对OkHttp和Retrofit的封装,代码中的实现其实很多开发者已经完成类似功能,这里实现的Factory实际是使用了单例模式,也保持了全局唯一的Retrofit对象以及OkHttp对象。方法create(Class<T> services)是基于Retrofit实现创建服务接口的方式向上提供,方便Manager部分创建自己的服务接口对象。

BaseManager

public abstract class BaseManager {

    /**
     * Request executor by default error transformer and result handle policy.
     * @param observable
     * @param callback
     * @param <T>
     */
    public final <T extends BaseResult> void execute(Observable<T> observable,
                                                     ResponseCallback<T> callback) {
        execute1(observable, new ResultHandler<T>(), callback);
    }

    /**
     * Execute the request by custom ResultHandler
     * @param observable
     * @param resultHandler
     * @param callback
     * @param <T>
     */
    public final <T extends BaseResult> void execute1(Observable<T> observable,
                                                      ResultHandler<T> resultHandler,
                                                      ResponseCallback<T> callback) {
        execute2(observable, new ResultHandler<T>(), new ErrorTransformer<T>(), callback);
    }

    /**
     * Execute request by custom ResultHandler and ErrorTransformer
     * @param observable
     * @param resultHandler
     * @param transformer
     * @param callback
     * @param <T>
     */
    public final <T extends BaseResult> void execute2(Observable<T> observable,
                                                      ResultHandler<T> resultHandler,
                                                      ErrorTransformer<T> transformer,
                                                      ResponseCallback<T> callback) {
        if (observable == null) {
            return;
        }
        observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .doOnNext(resultHandler)
                .onErrorResumeNext(transformer)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(callback);
    }

    /**
     * Execute the request for Type R as final result type.
     * @param observable
     * @param transformer
     * @param callback
     * @param <T> Original result type returned by http request according to restful protocol
     * @param <R> Final result type returned to up layer in application
     */
    public final <T extends BaseResult, R> void executeTransfom(Observable<T> observable,
                                                                DataTransformer<T, R> transformer,
                                                                ResponseCallback<R> callback) {
        executeTransfom1(observable, new ResultHandler<T>(), transformer, callback);
    }

    /**
     * Execute the request for Type R as final result type.
     * @param observable
     * @param resultHandler
     * @param transformer
     * @param callback
     * @param <T> Original result type returned by http request according to restful protocol
     * @param <R> Final result type returned to up layer in application
     */
    public final <T extends BaseResult, R> void executeTransfom1(Observable<T> observable,
                                                                ResultHandler<T> resultHandler,
                                                                DataTransformer<T, R> transformer,
                                                                ResponseCallback<R> callback) {
        executeTransfom2(observable, resultHandler, transformer, new ErrorTransformer<R>(), callback);
    }

    /**
     * Execute the request for Type R as final result type.
     * @param observable
     * @param resultHandler
     * @param transformer
     * @param errorTransformer
     * @param callback
     * @param <T> Original result type returned by http request according to restful protocol
     * @param <R> Final result type returned to up layer in application
     */
    public final <T extends BaseResult, R> void executeTransfom2(Observable<T> observable,
                                                                 ResultHandler<T> resultHandler,
                                                                 DataTransformer<T, R> transformer,
                                                                 ErrorTransformer<R> errorTransformer,
                                                                 ResponseCallback<R> callback) {
        if (observable == null) {
            return;
        }
        observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .doOnNext(resultHandler)
                .flatMap(transformer)
                .onErrorResumeNext(errorTransformer)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(callback);
    }

    /**
     * Result handler for result json or exception
     */
    public class ResultHandler<T extends BaseResult> implements Action1<T> {

        /**
         * Implemented by sub class for self handle result.
         * Used to do some fake data monitor
         * @param data represents the result data
         * @return
         */
        public boolean handled(T data) {
            return false;
        }

        @Override
        public final void call(T data) {
            if (data != null) {
                // if handle the data by sub class itself
                // this will not throw error even result code is not success
                if (handled(data)) {
                    return;
                }
                // TODO Pre-handle the result code
                // TODO If result code is not 200 or custom success code
                // TODO Throw a error or exception to go to onError() of ResponseCallback
                if (!"0200".equals(data.resultCode)) {
                    // Wrapper throwable and throw
                    throw new ServerException(data.resultCode);
                }
            }
        }
    }

    /**
     * Handling the data transforming from result type to custom type.
     * Using the flatmap in Rx
     * @param <T>
     * @param <R>
     */
    public abstract class DataTransformer<T extends BaseResult, R> implements Func1<T, Observable<R>> {

        @Override
        public final Observable<R> call(T data) {
            return transformData(data);
        }

        public abstract Observable<R> transformData(T data);
    }

    /**
     * Transform the common exception to corresponding Observable ResponseThrowable
     * @param <T>
     */
    public class ErrorTransformer<T> implements Func1<Throwable, Observable<T>> {

        @Override
        public Observable<T> call(Throwable throwable) {
            // Wrapper the exception before result go to onError()
            // Or you could handle the data to fake data for success
            return Observable.error(ExceptionHandler.handleException(throwable));
        }
    }

BaseManager是功能接口的封装和提供者的基类,其子类可以被划分为不同的Manager类,比如账号管理,AccountManager,那么会提供登录、注册等接口,供上层的Presenter使用完成对应功能。但是BaseManager抽象了几个execute方法。这些方法就是基于RxJava框架的实现,将请求数据的过程与响应结果的过程执行于不同的线程,这样就很好的解决了线程问题。RxJava的基本知识与使用请自行百度。

在BaseManager里面,也提供了不同的execute重写方法,主要是基于一些不同的rx操作符,比如doOnNext、flatMap、onErrorResumeNext。

  • doOnNext,是针对在事件流走到最后onNext之前的一个节点,此时可以针对响应数据进行修改。BaseManager中的实现是ResultHandler<T>。
  • flatMap,是用来将被观察者事件流改变成另外的事件流,其实可以理解为,当前观察A类型的事件流,到最后要转化为B类型的事件流。BaseManager中的实现是DataTransformer<T, R>。
  • onErrorResumeNext,是用来出现错误,在任何事件流的阶段有异常抛出时,能够将该错误引导为正常的事件流,这里可以针对不同的错误类型,设计正确的事件流结果返回。BaseManager中的实现是ErrorTransformer<T>。

BaseManager中定义的上述三种操作符,可以通过子类Manager来自定义重写实现,来决定自己的特殊数据处理。基于观察者模式,使用Rx中的Subscriber来作为Manager和Presenter的连接桥梁,就可以到M与P的沟通。

ResponseCallback

public abstract class ResponseCallback<T> extends Subscriber<T> {

    public abstract void onRequestStart();
    public abstract void onSuccess(T result);
    public abstract void onRequestFailure(int type, String errorCode);

    /**
     * Default none handling of custom error handled by sub callback
     * They could filter their own error code or type
     * @param throwable
     * @return
     */
    protected boolean filterCustomError(Throwable throwable) {
        return false;
    }

    @Override
    public final void onStart() {
        super.onStart();
        onRequestStart();
    }

    @Override
    public final void onCompleted() {
    }

    @Override
    public final void onError(Throwable throwable) {
        // filter the common error should be handled uniformly
        if (!filterCustomError(throwable)) {
            // handle the common handling
            if (throwable instanceof ExceptionHandler.ResponseThrowable) {
                ExceptionHandler.ResponseThrowable e =
                        (ExceptionHandler.ResponseThrowable) throwable;
                onRequestFailure(e.type, e.code);
            } else {
                onRequestFailure(-1, null); // unknown filtered error
            }
        }
    }

    @Override
    public final void onNext(T result) {
        onSuccess(result);
    }
}

范型<T>作为数据结果的类型。根据onNext、onStart、onError来封装一层方法供调用者自己实现其结果操作。ResponseCallback与BaseManager的实现思路类似,使用者可以通过继承多态的方式,针对各自的业务流程进行结果的特殊处理,上述代码就可以描述清楚。

ResponseThrowable是对不同异常类型及信息的特殊封装。在上文的BaseManager中,ErrorTransformer定义了通用的一场处理流程,并且将不同的Exception进行了统一封装,使用的是ExceptionHandler。

public class ExceptionHandler {

    public static ResponseThrowable handleException(Throwable e) {
        if (e instanceof HttpException) {
            HttpException httpException = (HttpException) e;
            return new ResponseThrowable(e, String.valueOf(httpException.code()), ERROR.HTTP_ERROR);
        }  else if (e instanceof ServerException) { // server error
            ServerException resultException = (ServerException) e;
            return new ResponseThrowable(resultException, resultException.code, ERROR.SERVER_ERROR);
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            return new ResponseThrowable(e, ERROR.PARSE_ERROR);
        } else if (e instanceof ConnectException) {
            return new ResponseThrowable(e, ERROR.NETWORD_ERROR);
        } else if (e instanceof javax.net.ssl.SSLHandshakeException) {
            return new ResponseThrowable(e, ERROR.SSL_ERROR);
        } else if (e instanceof ConnectTimeoutException){
            return new ResponseThrowable(e, ERROR.TIMEOUT_ERROR);
        } else if (e instanceof java.net.SocketTimeoutException) {
            return new ResponseThrowable(e, ERROR.NETWORD_ERROR);
        } else {
            return new ResponseThrowable(e, ERROR.UNKNOWN);
        }
    }

    /**
     * Error type
     */
    public static class ERROR {
        /**
         * Unknown error
         */
        public static final int UNKNOWN = 1000;
        /**
         * Parse error
         */
        public static final int PARSE_ERROR = 1001;
        /**
         * Network error
         */
        public static final int NETWORD_ERROR = 1002;
        /**
         * Http error
         */
        public static final int HTTP_ERROR = 1003;

        /**
         * Certificate error
         */
        public static final int SSL_ERROR = 1005;

        /**
         * Timeout error
         */
        public static final int TIMEOUT_ERROR = 1006;

        /**
         * Server Error
         */
        public static final int SERVER_ERROR = 1007;
    }

    public static class ResponseThrowable extends Exception {
        public String code;
        public int type;

        public ResponseThrowable(Throwable throwable, int type) {
            this(throwable, null, type);
        }

        public ResponseThrowable(Throwable throwable, String code, int type) {
            super(throwable);
            this.code = code;
            this.type = type;
        }
    }

}

这里是将不同的错误类型做了封装与转化,方便上层是用时的统一区分。

我们以Login登录为例子,来串接一下整体的设计流程。

LoginManager

public class LoginManager extends BaseManager {

    /**
     * Login service interface for retrofit with rx
     */
    interface LoginService {
        @POST("api/login")
        Observable<LoginResult> login(@Body LoginParams params); // restful type request using json
    }

    /**
     * Login request
     * @param username
     * @param password
     * @param callback
     */
    public void login(String username, String password, LoginResponseCallback callback) {
        if (callback != null) {
            // 1. Create Login service
            LoginService service = ServiceFactory.getInstance().create(LoginService.class);
            // 2. Create Login params
            LoginParams params = new LoginParams(username, password);
            // 3. Create Observable object by calling service function
            Observable<LoginResult> observable = service.login(params);
            // 4. Execute the request
            // execute(observable, callback);
            // execute1(observable, new LoginDataHandler(), callback);
            execute2(observable, new LoginDataHandler(), new LoginErrorTransformer(), callback);
        }
    }

    /**
     * Login response result handler
     */
    public abstract static class LoginResponseCallback extends ResponseCallback<LoginResult> {
        public abstract void onLoginFailure();

        @Override
        protected boolean filterCustomError(Throwable throwable) {
            // TODO Do some handling to throwable yourself
            if (throwable instanceof ExceptionHandler.ResponseThrowable) {
                ExceptionHandler.ResponseThrowable serverException
                        = (ExceptionHandler.ResponseThrowable) throwable;
                if (ExceptionHandler.ERROR.SERVER_ERROR == serverException.type) {
                    // The result will lead to onLoginFailure function for caller
                    onLoginFailure();
                    return true;
                }
            }
            // Other exception will lead to the common response handler
            return false;
        }
    }

    // login result data handler for fake login success data
    private class LoginDataHandler extends ResultHandler<LoginResult> {
        @Override
        public boolean handled(LoginResult data) {
            if (data == null) {
                data = new LoginResult();
                data.resultCode = "0200";
                data.token = "1234567890";
            }
            return true;
        }
    }

    /**
     * Transform the exception to fake login result object.
     * Lead the failure result to success one.
     */
    private class LoginErrorTransformer extends ErrorTransformer<LoginResult> {
        @Override
        public Observable<LoginResult> call(Throwable throwable) {
            LoginResult data = new LoginResult();
            data.resultCode = "0200";
            data.token = "1234567890";
            return Observable.just(data);
        }
    }
}

LoginManager定义了登录服务接口,LoginService,用以描述HTTP接口协议。然后声明了方法login(),作为上层使用者的调用入口。其内使用的BaseManager的execute2(),方法,重新定义了错误处理流程和结果数据处理流程。

重写了自己的ResponseCallback-LoginResponseCallback,该子类定义了一个错误分支,如果是服务器协议类型错误,就回调方法onLoginFailure()。

重写了LoginDataHandler,作为ResultHandler的实现类,并且重写了handled方法,将内部结果数据赋值成新的结果对象,这里就是可以在服务器接口数据异常的时候构造假数据。

重写了ErrorTransformer-LoginErrorTransformer,作为异常的转化者,这里也是构造了假数据,那么此时无论什么错误结果,都会正常返回该数据到上层。

LoginPresenter

public void login(String username, String password) {
        loginManager.login(username, password, new LoginManager.LoginResponseCallback() {
            @Override
            public void onLoginFailure() {
                if (mView != null) {
                    mView.onLoginFailure();
                }
            }

            @Override
            public void onRequestStart() {
                if (mView != null) {
                    mView.onLogining();
                }
            }

            @Override
            public void onSuccess(LoginResult result) {
                if (mView != null) {
                    mView.onLoginSuccess(result.token);
                }
            }

            @Override
            public void onRequestFailure(int type, String errorCode) {
                if (mView != null) {
                    mView.onLoginFailure();
                }
            }
        });
    }

Presenter中直接创建LoginManager,并且调用其login方法,同时传入参数以及回调的LoginResponseCallback,此时根据不同的结果状态回调,来定义LoginView应该进入的展示状态。

上述内容就是当前设计的基于Retrofit2+OkHttp3+RxJava实现的简单的MVP框架,基于该框架可以迅速的实现各个业务的功能及其流程,方便定制和扩展。当然了,该设计方案也有待商榷的地方,就是P的存在会无端增加过多的文件和类,如果考虑到这一点,直接将Activity作为C,直接与Manager交互,那么就可以切换为MVC模式,只是在多重业务组合的时候,有P的时候更方便。主要还是看大家自己的业务和考虑,哪种比较合适比较方便。


阅读更多
个人分类: APP开发 编程思想
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭