一、使用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();