泛型参数怎么new_Android MVP(四)运用反射配置泛型 Model

6245ed2a22e4da727456d9af1a99bb3e.png

这篇是基于上篇(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 类,来看看包详情

f1401055fc90c398ad475e6db5344e9b.png

第二步,我们的 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 来实例化的问题,通过反射可以让我们的代码变得更加的优雅,看起来也比较舒服。当然,对于初学者来说,这样的代码看起来是有点难理解,还是要死磕到底啊。

ec9d173b3a3b878aeedcdf1ce41d93b9.png

码字不易,看到这里别只点收藏啊,动动小手关注一下小编呗。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值