Android架构设计-简单粗暴,搞定MVP网络请求内存泄漏

2021-07-20  本文已影响0人  叶满林

一、使用Mvp为什么怎么开始内存内存泄漏了?

我们先简单的看一段Presenter层的代码

 override fun requestData(isRefresh: Boolean, type: String) {
        val call: Call<BaseResponse<Data>> = RequestManager.getInstance().apiService.getData(type)

        call.enqueue(object : Callback<BaseResponse<Data>> {
            override fun onFailure(call: Call<BaseResponse<Data>>, t: Throwable) {
                view.responseData(false, hasMore = false, cards = null, isRefresh = isRefresh)
            }

            override fun onResponse(call: Call<BaseResponse<Data>>, response: Response<BaseResponse<Data>>) {
                if (response.body() != null) {
                    if (response.body()?.state == 200) {
                       view.responseChannelData(true, hasMore = hasMore, cards = response.body()?.data, isRefresh = isRefresh)
                    }
                }
            }
        })
    }
}

大体上这段代码是完成一个单次的网络请求,然后进行回调的过程,那么网络操作是一个耗时操作,我们不知道请求什么时候可以回来。

场景模拟:比如说现在是一个弱网,网络请求回调需要5秒才行。 用户等了2秒,有点不太耐烦,直接把界面关了。

那么由于回调没有完成,view被强持有,无法释放,等到网络回调完成会发生
1.内存泄漏,没有及时释放view
2.空指针,如果下面的逻辑没有写好,数据回来view不已再。(咋还有丝凄凉)

二、解决内存泄漏的思路

第一步:从现象找本质

从上述内存泄漏的原因来看,其实就是Presenter没有跟上view的生命周期。我们其实在view层消失后,即使释放资源,剪断引用链条就可以解决内存泄漏问题了。
那么现在的问题点空就变成
1.view层什么时候资源释放? (找到剪断时机)
2.presenter层怎么释放?(找到剪断方法)

第二步:通过Lifecycle来传递生命周期

说到这里,我不得不说一下。很多人喜欢让Presenter层也拥有onCreate、onDestroy 等等方法,然后让view层在自己的生命周期方法时候去调用Presenter层的方法。且不说Presenter作为一个业务处理层拥有这些方法是否美观。 就仅仅主动调用这一点其实就非常的麻烦,可以主动调用,那么就得承担“被多次调用的风险”和“未被调用的风险”。 在阅读代码的时候,我承认我的拳头硬了

说到Lifecyle就是简单的原理就是让P层去观察V层的生命周期,当V层生命周期发送改变,便可以监听到对应的状态。这样就将显式调用变成了隐式监听。(这里我就不展开说了)
1.首先是让Presenter继承LifecycleObserver接口
2.view层提供getLifecycle方法,让Presenter去观察。

第三步:通过autodispose来进行网络反注册,剪断引用链

简单的讲下个组件的原理:
AutoDispose在内部创建了ArchLifecycleObserver,采用Event.ON_ANY注解监听Lifecyc的生命周期

当Lifecycle发出ON_DESTROY事件时,ArchLifecycleObserver转发该事件给特定observer,该observer通过filter限定Event.ON_DESTROY事件通过
随后当Activity销毁时,Lifecycle发送事件给ArchLifecycleObserver,并调用onDispose方法取消对Lifecycle的监听。
最后回调至ObservableCreate在订阅时创建的CreateEmitter的dispose方法,将CreateEmitter本身赋值为DISPOSED,销毁observer实例.

三、简单粗暴,照着抄就完事了

第一步:搭建Mvp的底层抽象类

1.通过底层架构,把mvp的接口类搭建起来

View层的抽象类

interface IBaseView<T : IBasePresenter> {
    fun getPresenter(): T

    fun getLifecycle(): Lifecycle

    /**
     * 判断Activity、Fragment是否回收
     */
    fun isRecycled(): Boolean
}

Presenter层的抽象类

interface IBasePresenter
2.通过做一个简单的Activity抽象类为例
abstract class MvpBaseActivity<T : BasePresenter<*>> : Activity(), IBaseView<T> {
    private lateinit var mPresenter: T

    override fun getLifecycle(): Lifecycle {
        return super.getLifecycle()
    }

    @LayoutRes
    protected abstract fun getLayoutResId(): Int

    protected abstract fun initAll(savedInstanceState: Bundle?)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(getLayoutResId())
        initPresenter()?.let { mPresenter = it }
        initAll(savedInstanceState)
    }


    override fun isRecycled(): Boolean {
        return isFinishing || isDestroyed
    }

    //有的页面不需要Mvp所以不去实现
    open fun initPresenter(): T? {
        return null
    }

    override fun getPresenter(): T {
        if (!::mPresenter.isInitialized) throw IllegalStateException("please override initPresenter()")
        return mPresenter
    }
}
3.做一个简单的Presenter层抽象类
abstract class BasePresenter<T : IBaseView<*>>() : IBasePresenter, LifecycleObserver {
    lateinit var view: T
    lateinit var scopeProvider: LifecycleScopeProvider<Lifecycle.Event>

    constructor(view: T) : this() {
        this.view = view
        view.getLifecycle().addObserver(this)
        scopeProvider = AndroidLifecycleScopeProvider.from(view.getLifecycle(), Lifecycle.Event.ON_DESTROY)
        release(view)
    }

    private fun release(view: T) {
        view.getLifecycle().addObserver(object : TempLifecycleObserver() {
            override fun onDestroy() {
                view.getLifecycle().removeObserver(this)
            }
        })
    }
}

这样 我们就已经把生命周期悄悄的传递给了presenter,下面是如何简单使用(这里网络请求以Retrofit网络请求为例,不了解retrofit网络请求的同学请坐等我更新,或者去隔壁了解一下)

第二步:使用我们定义好的类

1.首先是契约层

class HomeContract {

    interface View : IBaseView<Presenter> {
        fun responseButtonText(isSuccess: Boolean, buttonText:String)
    }


    abstract class Presenter(view: View) : BasePresenter<View>(view) {
        abstract fun requestButtonText()
    }
}

2.下来是view层

class HomActivity : MvpBaseActivity<HomeContract.Presenter>(), HomeContract.View{
    
    private var demo_tv: TextView? = null

    override fun getLayoutResId(): Int {
        return R.layout.activity_home_live_channel
    }

    override fun initAll(savedInstanceState: Bundle?) {
        initView()
        initData()
    }

    override fun initPresenter(): HomeContract.Presenter? {
        return HomePresenter(this)
    }

    fun initView() {
        demo_tv = findViewById(R.id.demo_tv)
    }

    fun initData() {
        getPresenter().requestButtonText()
    }

    override fun responseButtonText(isSuccess: Boolean,buttonText:String) {
        if(isSuccess){
            demo_tv.text = buttonText;
        }else{
            Toast.makeText(context,"网络请求失败",Toast.LENGTH_LONG)
        }
    }
}

3.接下来是Presenter层

class HomePresenter(view: HomeContract.View) : HomeContract.Presenter(view) {

    override fun requestButtonText(isRefresh: Boolean, categoryId: String, type: String) {
        RequestManager.getInstance()
                .observableApiService
                .getButtonText()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .autoDisposable(scopeProvider)   //重点是这个
                .subscribe(object : SingleObserver<BaseResponse<ButtonData>> {
                    override fun onSubscribe(d: Disposable) {}

                    override fun onSuccess(response: BaseResponse<ButtonData>) {
                        if (response.state == 200) {
                            view.responseButtonText(true,response.buttonText)
                        }
                    }

                    override fun onError(e: Throwable) {
                         view.responseButtonText(false,"")
                    }
                })
    }
}

4.网络层回调定义
这里我们为啥用Single,因为这里只有单次的网络请求,如果回调后无二次网络请求,则使用Single即可

Single<BaseResponse<ButtonData>> getButtonText();
上一篇下一篇

猜你喜欢

热点阅读