Android MVP Base类的封装,内存泄漏,代理,多presenter,注解依赖等封装(2)

1、Model

新建一个base 文件,在里面创建一个BaseModel

这里的其实就是一个空的类,后期的话,我们根据项目需求,再添加内容

package com.traveleasy.electricity.Base;

public abstract class BaseModel {

}

2、View 层

我们的IBaseView 是一个接口类,这里现在就只干一件事情,获取上下文

package com.traveleasy.electricity.Base;

import android.content.Context;

public interface IBaseView {

Context getContext();

}

看到这里,很多人会问,你的View 层就这些吗?答案肯定不是啦,各位看官,请别着急,视图层,我在后面会写。

3、presenter

重点来了,其实在我个人看来,整个MVP 框架中,presenter算是最辛苦的了,因为它要统筹大局,调兵遣将不是。

我先创建一个 IBasePresenter 接口类,这里我们定义一个IBaseView 的泛型,里面定义两个方法,绑定view 和解绑view 。

package com.traveleasy.electricity.Base;

public interface IBasePresenter {

// 绑定

void attachView(V view);

// 解绑

void detechView();

}

下面是重点,BasePresenter 的实现类

这这里,我使用了软引用的方式,来处理presenter 在获取activity 和销毁的时候,造成的内存泄漏的问题。

也运用了一些aop 的思想,即通过动态代理,做统一的逻辑判断。

package com.traveleasy.electricity.Base;

import androidx.lifecycle.LifecycleObserver;

import java.lang.ref.SoftReference;

import java.lang.ref.WeakReference;

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;

/**

  • 使用软引用的方式让 P 层持有 V 层的引用,并且提供了 getView() 方法给 P 层调用,

  • 父类 View 变量进行私有化,防止子类对其进行更改造成的其他错误。我们的 MainPresenter

  • 获取 Activity 的引用就可以使用 getView() 方法获得。软引用在内存降到不足的情况下,

  • GC 就会进行优先回收释放那些以软引用方式引用的对象,一定程度上去避免内存溢出(OOM)。

  • @param

*/

public abstract class BasePresenter<V extends IBaseView, M extends BaseModel> implements IBasePresenter {

// 使用软引用,避免内存泄漏,导致OOM 情况发送

protected SoftReference mReferenceView;

protected V mProxyView;

protected M mModel;

@SuppressWarnings(“unchecked”)

@Override

public void attachView(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;

}

@SuppressWarnings(“unchecked”)

public M getModel() {

return mModel;

}

@Override

public void detechView() {

mReferenceView.clear();

mReferenceView = null;

}

}

由于Java 单继承的特性,会造成我们在封装BaseActivity 和BaseFragment 时,会有很多的重复代码,BaseActivity 必须继承 Activity 才能启动,而 BaseFragment 又必须继承 Fragment 。

在讲解BaseActivity和BaseFragment 之前,我们先看一下代理模块的代码。

1、新建一个Proxy 接口类

package com.traveleasy.electricity.proxy;

/**

  • 由于Java 单继承的特性,这里我们使用proxy 代理,来实现 BaseActivity 和 BaseFragment 重复代码的封装实现

  • 这里封装两个接口,一个绑定Presenter, 一个解绑Presenter

*/

public interface IProxy {

void bindPresenter();

void unBindPresenter();

}

2、创建proxyIml 实现类

package com.traveleasy.electricity.proxy;

import com.traveleasy.electricity.Base.BasePresenter;

import com.traveleasy.electricity.Base.IBaseView;

import com.traveleasy.electricity.inject.InjectPresenter;

import java.lang.reflect.Field;

import java.util.ArrayList;

import java.util.List;

/**

  • 前面我们创建了proxy 代理,里面有解绑和绑定Presenter 的抽象方法

  • 这里我们创建一个proxyIml 接口实现类,用来统一代理重复的代码

*/

public class ProxyImpl implements IProxy {

private IBaseView mView;

// 定义一个数组,保存使用过的presenter,用于解绑

private List mInjectPresenters;

public ProxyImpl(IBaseView view) {

this.mView = view;

mInjectPresenters = new ArrayList<>();

}

/**

  • 绑定 presenter 的实现

*/

@Override

public void bindPresenter() {

// 获得已经声明的变量,包括私有的

Field[] fields = mView.getClass().getDeclaredFields();

for (Field field : fields) {

// 获取变量上面的注解类型

InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);

if (injectPresenter != null) {

try {

Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();

BasePresenter mInjectPresenter = type.newInstance();

mInjectPresenter.attachView(mView);

field.setAccessible(true);

field.set(mView, mInjectPresenter);

mInjectPresenters.add(mInjectPresenter);

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

throw new RuntimeException(“SubClass must extends Class:BasePresenter”);

}

}

}

}

/**

  • 解绑 presenter 的实现

  • 避免内存泄漏

*/

@Override

public void unBindPresenter() {

for (BasePresenter presenter : mInjectPresenters) {

presenter.detechView();

}

mInjectPresenters.clear();

mInjectPresenters = null;

}

}

3、再分别创建proxyActivity和 proxyFragment 类

package com.traveleasy.electricity.proxy;

import com.traveleasy.electricity.Base.IBaseView;

/**

  • 新建proxyActivity 代理实现类,用来代理activity 中重复的代码

*/

public class ProxyActivity extends ProxyImpl {

public ProxyActivity(IBaseView view) {

super(view);

}

}

package com.traveleasy.electricity.proxy;

import com.traveleasy.electricity.Base.IBaseView;

/**

  • 新建proxyFragment 实现类,用于处理fragment 中重复的代码

*/

public class ProxyFragment extends ProxyImpl {

public ProxyFragment(IBaseView view) {

super(view);

}

}

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

image

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

image

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

[外链图片转存中…(img-aKn3BKeu-1714285084276)]

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

[外链图片转存中…(img-DBODOQhm-1714285084277)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值