Android MVP(四)运用反射配置泛型 Model

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主威威喵  |  博客主页https://blog.csdn.net/smile_running

 

MVP 架构系列文章:

Android MVP 架构(一)MVP 架构介绍与实战运用

Android MVP 架构(二)MVP 之 BaseMVP 基础框架设计

Android MVP 架构(三)MVP 内存泄漏分析与动态代理

Android MVP 架构(四)MVP 泛型 Model 的配置

Android MVP 架构(五)MVP 多个 Presenter 依赖注入

Android MVP 架构(六)MVP 之 BaseFragment 的封装

Android MVP 架构(七)MVP 之代理模式消除重复代码(结束)

源码地址:

github下载:MVPDemo

csdn 下载:MVPDemo

    这篇是基于上篇(Android MVP 架构(三)MVP 内存泄漏分析与动态代理)的 BaseMVP 框架基础上进行配置和修改的,上篇我们介绍了 MVP 可能存在的内存泄漏的问题,还有就是如何使用动态代理,我们把同一段代码或同一个业务逻辑判断操作项抽离出来,用的就是 AOP 思想。AOP 思想的一种编程手段,使用动态代理的方式进行抽离重复的代码或进行统一的逻辑处理。

    使用动态代理对 View 层进行抽离统一的逻辑判断,这一项工作我们在上篇文章中已经完成了。紧接着,我们就应该考虑其他层的封装处理。这篇文章,我们就拿 Model 层开刀。

    首先,看看我们的 BaseMVP 框架中的 Model 层,Model 虽然提供数据源都各不相同,但每次引用它时,都需要在 Presenter 层拿到它的引用才行,最简单的引用方式是 new 出它的实例,比如下面的 MianPresenter 中的代码:

/**
 * presenter 层,承担业务逻辑处理,数据源处理等
 */
public class MainPresenter extends BasePresenter<MainContract.IMainView> implements MainContract.IMainPresenter {

    private MainContract.IMainModel mModel;

    @Override
    public void attech(IBaseView view) {
        super.attech(view);
        mModel = new DataModel();
    }

    @Override
    public void handlerData() {
        getView().showDialog();

        mModel.requestBaidu(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String content = response.body().string();
                getView().succes(content);
            }
        });
    }

    @Override
    public void detech() {
        super.detech();
        /**
         * 释放内存、关闭网络请求、关闭线程等操作
         */
        Log.d("==========", "detech: 解除绑定,释放内存");
    }
}

    就像代码中的 IMainModel 接口,我们每次要获取数据源时,都要去 new 它的一个实现类,这种方法都是可以的。但是,每次去 new 又显得麻烦,而且通常来说,一个 Presenter 和一个 Model 是一对一的关系,所以,我们想到了创建对象的另一种方式:通过反射来获取。

    首先,分析一下每一个 Model 肯定是不同的类型,这里就必须用到泛型。又因为 Model 层只有与 Presenter 层才有引用的关系,Presenter 持有 Model 的引用,所以这里的 Presenter 所持有的必定是一个泛型的 Model ,而不是具体的。而且我们是写 BaseMVP 框架,所以泛型应该封装到 BasePresenter 基类中去,才能让实现它的子类去调用。

    于是呢,我们的第一步,创建 BaseModel 基类,这里没有什么新的方法,主要用于泛型与继承的关系。如果有什么比较特殊的数据源或通用的可以在基类中提供。

    第4个版本我们与前3个版本对比,就添加了一个 BaseModel 类,来看看包详情

创建 BaseModel 基类:

package com.test.mvp.mvpdemo.mvp.v4.basemvp;

public abstract class BaseModel {
}

    第二步,我们的 DataModel 就要继承 BaseModel 基类,提供相应的 Presenter 提供特有的数据。

修改 DataModel 实现类:

package com.test.mvp.mvpdemo.mvp.v4.model;

import com.test.mvp.mvpdemo.mvp.v4.MainContract;
import com.test.mvp.mvpdemo.mvp.v4.basemvp.BaseModel;

import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;

/**
 * model 层,请求网络或数据库,提供数据源(原始数据)
 */
public class DataModel extends BaseModel implements MainContract.IMainModel {

    @Override
    public void requestBaidu(Callback callback) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url("https://www.baidu.com/")
                .build();
        client.newCall(request).enqueue(callback);
    }
}

    接下来,就是我们的重点:BasePresenter 类的修改与处理,我们要为 BasePresenter 类再添加一个泛型参数,提供对不同 Model 实现类的支持。再者,就是使用反射来实例化 Model 对象,这里可能是比较容易出错的。一个是对反射的理解,另一个是对泛型的理解。我们先看看代码,再进行解释。

修改 BasePresenter 基类:

package com.test.mvp.mvpdemo.mvp.v4.basemvp;

import android.util.Log;

import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

public abstract class BasePresenter<V extends IBaseView, M extends BaseModel> implements IBasePresenter {
    private SoftReference<IBaseView> mReferenceView;
    private V mProxyView;
    private M mModel;

    @SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
    @Override
    public void attach(IBaseView view) {
        //使用软引用创建对象
        mReferenceView = new SoftReference<>(view);
        //使用动态代理做统一的逻辑判断 aop 思想
        mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                if (mReferenceView == null || mReferenceView.get() == null) {
                    return null;
                }
                return method.invoke(mReferenceView.get(), objects);
            }
        });

        //通过获得泛型类的父类,拿到泛型的接口类实例,通过反射来实例化 model
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        if (type != null) {
            Type[] types = type.getActualTypeArguments();
            try {
                mModel = (M) ((Class<?>) types[1]).newInstance();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }

    }

    @SuppressWarnings("unchecked")
    public V getView() {
        return mProxyView;
    }

    protected M getModel() {
        return mModel;
    }

    @Override
    public void detach() {
        mReferenceView.clear();
        mReferenceView = null;
    }
}

    先看类的参数,我们添加了一个继承自刚刚写的 BaseModel 类的泛型参数,这里不难理解。可能比较难理解的是如何实例化 Model 对象吧,也就是这个例子中的 DataModel 类的实例化。

    既然这样,我们先来看看在 MainPresenter 实现类中该如何传递这个泛型 Model ,应该是传入 DataModel 吧,来看看我们的MainPresenter 类代码:
修改 MainPresenter  实现类:

/**
 * presenter 层,承担业务逻辑处理,数据源处理等
 */
public class MainPresenter extends BasePresenter<MainContract.IMainView, DataModel> implements MainContract.IMainPresenter {

    @Override
    public void handlerData() {
        getView().showDialog();

        getModel().requestBaidu(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String content = response.body().string();
                getView().succes(content);
            }
        });
    }

    @Override
    public void detach() {
        super.detach();
        /**
         * 释放内存、关闭网络请求、关闭线程等操作
         */
        Log.d("==========", "detech: 解除绑定,释放内存");
    }
}

    这里我们传入的是 DataModel 的实例,而 MainPresenter 类是继承自 BasePresenter 基类的,所以在 BasePresenter 的反射代码中的 this 指的就是 MainPresenter 类的对象。看如下反射代码:

反射代码部分:

        //通过获得泛型类的父类,拿到泛型的接口类实例,通过反射来实例化 model
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();

        Log.d("===========", "attach: "+this.getClass().getSimpleName());
        if (type != null) {
            Type[] types = type.getActualTypeArguments();
            try {
                mModel = (M) ((Class<?>) types[1]).newInstance();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }

通过 Log 打印就能验证一下,看看是否正确。

    我们拿到的是 MainPresenter 类的对象,这不是我们想要的啊,我们想要的是 DataModel 类的对象。又因为这里 DataModel 是通过 BasePresenter 类的泛型传进去的,所以我们通过反射机制是可以获取到 MainPresenter 的父类 BasePresenter 类。再接着,我们应该去获取 BasePresenter 的泛型参数,这里的 BasePresenter 有两个泛型参数,它返回一个 Type[] 数组。而第二个就是我们需要的真正的 DataModel 类对象了,最后通过类对象的 newInstance() 实例化就可以了。

    看起来是有点难理解,不过还是 Java 的基础啊,正是运用了 Java 的反射来动态的创建 Model 层,这是我们写框架的必备知识。那么,到这里我们又解决了 Model 层需要手动 new 来实例化的问题,通过反射可以让我们的代码变得更加的优雅,看起来也比较舒服。当然,对于初学者来说,这样的代码看起来是有点难理解,还是要死磕到底啊。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值