带你封装MVP架构(上)|青训营笔记(二)

简介: 我们做一个 MVP 架构的封装,主要其相对于MVC更加解耦,能让开发人员在编写代码的时候更加高效和舒服。

MyUtil

该工具类获得了一个全局的 Context ,以及根据此context,创建了开启加载动画以及关闭加载动画的方法

public class MyUtil {
    /**
     * 全局context
     */
    private static Application mApplicationContext;
    private static RxDialogLoading rxDialogLoading;
    /**
     * @param app 初始化全局context
     */
    public static void initialize(Application app) {
        mApplicationContext = app;
    }
    /**
     * 获得全局context
     *
     * @return 当前的全局context
     */
    public static Application getApplication() {
        return mApplicationContext;
    }
    /**
     * 关闭键盘
     */
    public static void closeSoftKeyboard() {
        InputMethodManager inputManger = (InputMethodManager) ActivityUtil.getCurrentActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputManger != null) {
            inputManger.hideSoftInputFromWindow(ActivityUtil.getCurrentActivity().getWindow().getDecorView().getWindowToken(), 0);
        }
    }
    public static String getString(int id) {
        return getApplication().getResources().getString(id);
    }
    /**
     * 展示dialog
     *
     * @param context 传入当前Acitivity
     */
    public static void showLoading(Context context){
        if (rxDialogLoading == null){
            rxDialogLoading = new RxDialogLoading(context);
            rxDialogLoading.setCanceledOnTouchOutside(false);
        }
        rxDialogLoading.show();
    }
    /**
     * 成功隐藏dialog,显示成功
     */
    public static void dismissSuccessLoading(){
        rxDialogLoading.cancel(RxDialogLoading.RxCancelType.success,getString(R.string.load_success));
    }
    /**
     * 失败隐藏dialog,显示失败
     */
    public static void dismissFailedLoading(){
        rxDialogLoading.cancel(RxDialogLoading.RxCancelType.error,getString(R.string.load_error));
    }
}
复制代码

Retrofit + Rxjava 打造优雅网络请求方式

由于该模块代码繁多,文章不会描述每一个类,完整代码请查阅http

其中的 cookie 包是用于做登录状态持久化,但是本demo中未用到

gson 包是做了一个转换器,对网络数据的请求报文和响应报文做了一次数据筛查

API 类是定义了所有的网络请求方法

RetrofitService 类是对该网络模块的集成的方法,是 Retrofit 的核心方法

BaseResponseBodyConverter

该方法是继承了类型为响应报文的 Retrofit 转换器类,可以对对响应报文做数据筛查。我们可以筛查出响应的报文的错误码或者错误描述进行自动的异常处理。

例如返回的错误码描述为当前登录状态过期,那么我们可以取消登录状态,程序自动跳转到登录页面中。

亦或是错误码为非正常状态下,自动抛出自定义的异常,然后App对该异常做 Toast 描述之类的

public class BaseResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final TypeAdapter<T> adapter;
    BaseResponseBodyConverter(TypeAdapter<T> adapter) {
        this.adapter = adapter;
    }
    @Override
    public T convert(ResponseBody value) throws IOException {
        String jsonString = value.string();
        try{
            JSONObject object = new JSONObject(jsonString);
            int code = object.getInt(MyUtil.getString(R.string.code));
            String data ;
            if (code == 1) return adapter.fromJson(jsonString);
            else  data = object.getString(MyUtil.getString(R.string.msg));
            throw new BaseException(code, data);
        }catch (JSONException ex){
            ex.printStackTrace();
            try {
                JSONObject object = new JSONObject(jsonString);
                int error_code = object.getJSONObject("data").getInt(MyUtil.getString(R.string.error_code));
                if (0 != error_code ) {
                    String data;
                    data = object.getJSONObject("data").getString(MyUtil.getString(R.string.error_msg));
                    //异常处理
                    throw new BaseException(error_code, data);
                }
                //正确返回整个json
                return adapter.fromJson(jsonString);
            } catch (JSONException e) {
                e.printStackTrace();
                //数据解析异常即json格式有变动
                throw new BaseException(MyUtil.getString(R.string.PARSE_ERROR_MSG));
            }
        }finally {
            value.close();
        }
    }
}
复制代码

需要注意的是,我们需要针对不同格式的响应报文,定制不同的筛查策略和处理逻辑

MoreBaseUrlInterceptor

自定义一个过滤器,在该过滤器中,我们可以对请求的做一些自动的更改

例如下例,我们可以在检测到请求头中带 urlName 字段的时候,去做一个对应的 BaseUrl 的更新;我们也还可以在这里做一些譬如key这些字段的添加等等

public class MoreBaseUrlInterceptor implements Interceptor {
    private final HashMap<String,String> keyUrl;
    public MoreBaseUrlInterceptor(HashMap<String, String> keyUrl) {
        this.keyUrl = keyUrl;
    }
    @Override
    public Response intercept(Chain chain) throws IOException {
        //获取原始的originalRequest
        Request originalRequest = chain.request();
        //获取老的url
        HttpUrl oldUrl = originalRequest.url();
        //获取originalRequest的创建者builder
        Request.Builder builder = originalRequest.newBuilder();
        //获取头信息的集合如:base,geo
        List<String> urlNameList = originalRequest.headers("urlName");
        if (urlNameList.size() > 0) {
            //删除原有配置中的值,就是namesAndValues集合里的值
            builder.removeHeader("urlName");
            //获取头信息中配置的value,如:m或者mock
            String urlName = urlNameList.get(0);
            HttpUrl baseURL;
            //根据头信息中配置的value,来匹配新的base_url地址
            baseURL = HttpUrl.parse(Objects.requireNonNull(keyUrl.get(urlName)));
            //重建新的HttpUrl,需要重新设置的url部分
            HttpUrl newHttpUrl = oldUrl.newBuilder()
                    .scheme(baseURL.scheme())//http协议如:http或者https
                    .host(baseURL.host())//主机地址
                    .encodedPath(baseURL.encodedPath() +
                            oldUrl.encodedPath().substring(1))//构建路径,为适配MOCK中给出的BaseURL带有Path路径的情况
                    .port(baseURL.port())//端口
                    .build();
            //获取处理后的新newRequest
            Request newRequest = builder.url(newHttpUrl).build();
            return  chain.proceed(newRequest);
        }else{
            Request reOriginalRequest = builder.url(oldUrl).build();
            return chain.proceed(reOriginalRequest);
        }
    }
}
复制代码

RetrofitService

该类是 Retrofit 服务类,对外提供一个服务的单例,然后添加好前面编写的转换器以及过滤器等信息。这样子供外部统一调用这个 Retrofit 单例即可。

public class RetrofitService {
    private volatile static RetrofitService apiRetrofit;
    private API.SZApi apiServer;
    /**
     * 单例调用
     *
     * @return RetrofitService
     */
    public static RetrofitService getInstance() {
        if (apiRetrofit == null) {
            synchronized (Object.class) {
                if (apiRetrofit == null) {
                    apiRetrofit = new RetrofitService();
                }
            }
        }
        return apiRetrofit;
    }
    /**
     * 获取api对象
     *
     * @return api对象
     */
    public API.SZApi getApiService() {
        return apiServer;
    }
    /**
     * 初始化retrofit
     */
    private RetrofitService() {
        //配置okHttp并设置时间、日志信息和cookies
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new MoreBaseUrlInterceptor(API.getKeyUrl()))
                .addInterceptor(httpLoggingInterceptor)
                //设置超时时间
                .connectTimeout(15, TimeUnit.SECONDS)
                //设置Cookie持久化
//                .cookieJar(new CookiesManager(MyUtil.getApplication()))
                .build();
        //关联okHttp并加上rxJava和Gson的配置和baseUrl
        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(BaseConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(API.BASE_URL)
                .build();
        apiServer = retrofit.create(API.SZApi.class);
    }
}
复制代码


相关文章
|
2月前
|
监控 负载均衡 Dubbo
|
4月前
|
前端开发 JavaScript 数据库
Flask狼书笔记 | 09_图片社交网站 - 大型项目的架构与需求(2)
9.8 收藏图片 前面已经学习过如何使用关联表来表示多对多关系,缺点是只能表示关系,不能存储数据(如我还想记录下收藏图片的时间戳)。这种情况下,我们可以使用关联模型来表示多对多关系。 在关联模型中,我们将Photo模型与User模型的多对多关系,分离成了User模型和Collect模型的一对多关系,和Photo模型与Collect模型的一对多关系。
56 0
|
2月前
|
存储 传感器 网络协议
《物联网技术》课程笔记——第二章 物联网技术架构
《物联网技术》课程笔记——第二章 物联网技术架构
|
3月前
|
达摩院 Java Apache
惊动“达摩院”的分布式架构笔记:火于互联网,据说来自于清华
一个星期前,一本Java架构笔记突然在互联网上爆火。因为内容的深度和广度,甚至连阿里最牛的研发中心都被惊动了,而且作者一周后直接被阿里挖走后定级P8,据说作者来自于清华。
|
3月前
|
设计模式 存储 前端开发
【各种问题处理】MVC、MVP、MVVM 、MVI、VIPER 架构(设计模式)
【1月更文挑战第13天】【各种问题处理】MVC、MVP、MVVM 、MVI、VIPER 架构(设计模式)
|
3月前
|
安全 数据挖掘 定位技术
笔记 - 《业务架构解构与实践》
《业务架构解构与实践》的笔记
|
3月前
|
运维 Cloud Native 安全
笔记 - 《阿里云云原生架构实践》
《阿里云云原生架构实践》的笔记
|
3月前
|
NoSQL Java 程序员
阿里开发人员献礼“Java架构成长笔记”,深入内核,拒绝蒙圈
提起阿里,行外人联想到的关键词无非是“交易”、“淘宝”、“支付宝”,但对于程序员来说,阿里庞大的技术体系才是最吸引人的。实际上阿里作为国内一线互联网公司的头把交椅,内部的技术体系和发展都是备受关注的,对于程序员来说,能够进到阿里工作,就是对自己的技术水平进行一个提升和学习。
阿里开发人员献礼“Java架构成长笔记”,深入内核,拒绝蒙圈
|
3月前
|
消息中间件 架构师 Java
Java架构速成笔记:七大专题,1425页考点,挑战P8岗
我们都知道,在程序员的职业生涯中,有多个发展方向,不过就数据表明,近年来选择架构师方向的开发人员也越来越多。
|
3月前
|
SQL 存储 关系型数据库
华为大佬的“百万级”MySQL笔记,基础+优化+架构一键搞定
MySQL不用多说,大家都知道它是目前最为活跃热门的开源数据库,由于成本低,操作简易的特点,所以在互联网企业中被广泛使用,即使是头部的BATJ。由此可见,想要在互联网行业混得风生水起,或者说想要进入BATJ等一线互联网公司,那么熟练掌握MySQL必定是一块必要的敲门砖。