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

三年前写过一段时间Android的代码,后面又开始做一些跨平台的工作,比如之前的react-native ,现在的flutter 等,现在想重新找一份工作,思虑再三,还是把Android 捡一捡。

废话不多说,先封装个base MVP 框架记录一下
简单的介绍一下MVP思想,它是将View 层与Model 层彻底隔离,意味着View 和 Model 都不再持有对方的引用,它们通过一个叫做Presenter 的第三者来代理事务的传递,所有Presenter 层会持有Model 与View 层的引用。如下图

在这里插入图片描述

我们访问网络得到数据并显示出来,会是这样的一个流程
1、Activity 启动时,告诉presenter 我要数据了。
2、Presenter 就会叫Model 去访问数据接口,获取数据。
3、Model 得到数据后,返回给Presenter 了,Presenter 一看数据不规范,赶紧处理一下,处理完成
4、Presenter 把处理后的数据汇报给了activity(View), View 拿到数据后,就去做显示的操作,MVP 流程走完,工作结束。

看到这里,MVP 流程是走完了,我们的工作却刚开始,下面一起来实现一下整个流程。
先看一下项目文件图
在这里插入图片描述

既然是写MVP,很多新学朋友肯定不知道先从哪里下手去写,那么既然是MVP,我们就先从Model 层开始吧。

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<V extends IBaseView> {

    // 绑定
    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 <V>
 */
public abstract class BasePresenter<V extends IBaseView, M extends BaseModel> implements IBasePresenter {

    //    使用软引用,避免内存泄漏,导致OOM 情况发送
    protected SoftReference<IBaseView> 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<BasePresenter> 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<V extends IBaseView> extends ProxyImpl {


    public ProxyActivity(IBaseView view) {
        super(view);
    }
}

package com.traveleasy.electricity.proxy;

import com.traveleasy.electricity.Base.IBaseView;

/**
 * 新建proxyFragment 实现类,用于处理fragment 中重复的代码
 */
public class ProxyFragment<V extends IBaseView> extends ProxyImpl {

    public ProxyFragment(IBaseView view) {
        super(view);
    }
}

这里的两个代理类暂时没有代码,因为我们还没有需要在里面处理的业务逻辑,不过我们必须得传入一个泛型的IBaseView 对象,这里的原因就是我们的 ProxyImpl 类中的 presenter 调用 attach() 方法去绑定 View 时,这个 View 是继承 IBaseView 的,所以这必须要一个参数给它,通过继承 ProxyImpl 类将这个 view 用构造函数的方式传给父类。

接下来我们来看一下视图中的代码

package com.traveleasy.electricity.Base;

import android.content.Context;
import android.os.Bundle;
import android.view.View;

import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.traveleasy.electricity.inject.InjectPresenter;
import com.traveleasy.electricity.proxy.ProxyActivity;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseActivity extends AppCompatActivity implements IBaseView {

    private ProxyActivity mProxyActivity;

    protected abstract void initLayout(@Nullable Bundle savedInstanceState);

    protected abstract void initViews();

    protected abstract void initData();


    @SuppressWarnings("SamePresenterValue")
    protected <T extends View> T $(@IdRes int viewId) {
        return findViewById(viewId);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        initLayout(savedInstanceState);

        mProxyActivity = createProxyActivity();
        mProxyActivity.bindPresenter();

        initViews();
        initData();
    }

    @SuppressWarnings("unchecked")
    private ProxyActivity createProxyActivity(){

//        代理为null 的时候, 重新初始化
        if (mProxyActivity == null){
            return new ProxyActivity(this);
        }

        return mProxyActivity;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        mProxyActivity.unBindPresenter();
    }

    @Override
    public Context getContext() {
        return this;
    }

}

package com.traveleasy.electricity.Base;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.traveleasy.electricity.inject.InjectPresenter;
import com.traveleasy.electricity.proxy.ProxyFragment;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseFragment extends Fragment implements IBaseView {

    private ProxyFragment mProxyFragment;

    protected abstract @LayoutRes
    int setLayout();

    protected abstract void initViews(@Nullable Bundle savedInstanceState);

    protected abstract void initData();

    @SuppressWarnings("ConstantConditions")
    protected <T extends View> T $(@IdRes int viewId) {
        return this.getView().findViewById(viewId);
    }

    @SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(setLayout(), container, false);

        mProxyFragment = createProxyFragment();
        mProxyFragment.bindPresenter();

        return view;
    }

    private ProxyFragment createProxyFragment(){

//        如果代理为null 的话,就重新初始化
        if (mProxyFragment == null){
            return new ProxyFragment(this);
        }

        return mProxyFragment;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        initViews(savedInstanceState);
        initData();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

       mProxyFragment.unBindPresenter();
    }
}

上面BaseActivity 和BaseFragment 中的代码是不是很简单?
我们通过代理的方式,代理了View 的绑定和解绑的相关代码。

以上就是BaseMvp 框架的封装。

BaseMvp 框架的使用

源码下载

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
对于Android开发的网络请求框架封装,RxJava、Retrofit和MVP是常用的技术组合。下面是一个简单的示例,演示如何将它们结合起来进行网络请求的封装。 首先,确保你的项目已经引入了RxJava、Retrofit和MVP的相关依赖库。 1. 创建网络请求接口 在你的项目创建一个接口,用于定义网络请求的方法。例如,创建一个名为ApiService的接口: ```java public interface ApiService { @GET("api/endpoint") Observable<ResponseData> getData(); } ``` 2. 创建网络请求管理 创建一个名为ApiManager的,用于管理网络请求。在这个,你可以初始化Retrofit,并提供一个方法来执行具体的网络请求。 ```java public class ApiManager { private static final String BASE_URL = "http://your-api-base-url.com/"; private ApiService apiService; public ApiManager() { Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); apiService = retrofit.create(ApiService.class); } public Observable<ResponseData> getData() { return apiService.getData() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } } ``` 3. 创建Presenter层 在MVP架构,Presenter层负责处理业务逻辑和数据操作。创建一个名为MainPresenter,并在其调用ApiManager执行网络请求。 ```java public class MainPresenter { private MainView mainView; private ApiManager apiManager; public MainPresenter(MainView mainView) { this.mainView = mainView; apiManager = new ApiManager(); } public void fetchData() { apiManager.getData() .subscribe(new Observer<ResponseData>() { @Override public void onSubscribe(Disposable d) { // 可选的订阅回调 } @Override public void onNext(ResponseData responseData) { // 处理请求成功的数据 mainView.showData(responseData); } @Override public void onError(Throwable e) { // 处理请求失败的情况 mainView.showError(e.getMessage()); } @Override public void onComplete() { // 请求完成,可选的回调 } }); } } ``` 4. 创建View层 在MVP架构,View层负责展示数据和处理用户交互。创建一个名为MainActivity的,并实现MainView接口。 ```java public class MainActivity extends AppCompatActivity implements MainView { private MainPresenter mainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainPresenter = new MainPresenter(this); mainPresenter.fetchData(); } @Override public void showData(ResponseData responseData) { // 展示数据到UI上 } @Override public void showError(String errorMessage) { // 展示错误信息到UI上 } } ``` 这就是一个简单的Android网络请求框架封装示例,使用了RxJava、Retrofit和MVP来完成网络请求的处理。当然,你可以根据实际需求进行更加复杂的封装和扩展。希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半身风雪

感谢打赏,你的鼓励,是我创作的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值