一、使用Mvp為什么怎么開(kāi)始內(nèi)存內(nèi)存泄漏了?
我們先簡(jiǎn)單的看一段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)
}
}
}
})
}
}
大體上這段代碼是完成一個(gè)單次的網(wǎng)絡(luò)請(qǐng)求,然后進(jìn)行回調(diào)的過(guò)程,那么網(wǎng)絡(luò)操作是一個(gè)耗時(shí)操作,我們不知道請(qǐng)求什么時(shí)候可以回來(lái)。
場(chǎng)景模擬:比如說(shuō)現(xiàn)在是一個(gè)弱網(wǎng),網(wǎng)絡(luò)請(qǐng)求回調(diào)需要5秒才行。 用戶(hù)等了2秒,有點(diǎn)不太耐煩,直接把界面關(guān)了。
那么由于回調(diào)沒(méi)有完成,view被強(qiáng)持有,無(wú)法釋放,等到網(wǎng)絡(luò)回調(diào)完成會(huì)發(fā)生
1.內(nèi)存泄漏,沒(méi)有及時(shí)釋放view
2.空指針,如果下面的邏輯沒(méi)有寫(xiě)好,數(shù)據(jù)回來(lái)view不已再。(咋還有絲凄涼)
二、解決內(nèi)存泄漏的思路
第一步:從現(xiàn)象找本質(zhì)
從上述內(nèi)存泄漏的原因來(lái)看,其實(shí)就是Presenter沒(méi)有跟上view的生命周期。我們其實(shí)在view層消失后,即使釋放資源,剪斷引用鏈條就可以解決內(nèi)存泄漏問(wèn)題了。
那么現(xiàn)在的問(wèn)題點(diǎn)空就變成
1.view層什么時(shí)候資源釋放? (找到剪斷時(shí)機(jī))
2.presenter層怎么釋放?(找到剪斷方法)
第二步:通過(guò)Lifecycle來(lái)傳遞生命周期
說(shuō)到這里,我不得不說(shuō)一下。很多人喜歡讓Presenter層也擁有onCreate、onDestroy 等等方法,然后讓view層在自己的生命周期方法時(shí)候去調(diào)用Presenter層的方法。且不說(shuō)Presenter作為一個(gè)業(yè)務(wù)處理層擁有這些方法是否美觀。 就僅僅主動(dòng)調(diào)用這一點(diǎn)其實(shí)就非常的麻煩,可以主動(dòng)調(diào)用,那么就得承擔(dān)“被多次調(diào)用的風(fēng)險(xiǎn)”和“未被調(diào)用的風(fēng)險(xiǎn)”。 在閱讀代碼的時(shí)候,我承認(rèn)我的拳頭硬了。
說(shuō)到Lifecyle就是簡(jiǎn)單的原理就是讓P層去觀察V層的生命周期,當(dāng)V層生命周期發(fā)送改變,便可以監(jiān)聽(tīng)到對(duì)應(yīng)的狀態(tài)。這樣就將顯式調(diào)用變成了隱式監(jiān)聽(tīng)。(這里我就不展開(kāi)說(shuō)了)
1.首先是讓Presenter繼承LifecycleObserver接口
2.view層提供getLifecycle方法,讓Presenter去觀察。
第三步:通過(guò)autodispose來(lái)進(jìn)行網(wǎng)絡(luò)反注冊(cè),剪斷引用鏈
簡(jiǎn)單的講下個(gè)組件的原理:
AutoDispose在內(nèi)部創(chuàng)建了ArchLifecycleObserver,采用Event.ON_ANY注解監(jiān)聽(tīng)Lifecyc的生命周期
當(dāng)Lifecycle發(fā)出ON_DESTROY事件時(shí),ArchLifecycleObserver轉(zhuǎn)發(fā)該事件給特定observer,該observer通過(guò)filter限定Event.ON_DESTROY事件通過(guò)
隨后當(dāng)Activity銷(xiāo)毀時(shí),Lifecycle發(fā)送事件給ArchLifecycleObserver,并調(diào)用onDispose方法取消對(duì)Lifecycle的監(jiān)聽(tīng)。
最后回調(diào)至ObservableCreate在訂閱時(shí)創(chuàng)建的CreateEmitter的dispose方法,將CreateEmitter本身賦值為DISPOSED,銷(xiāo)毀observer實(shí)例.
三、簡(jiǎn)單粗暴,照著抄就完事了
第一步:搭建Mvp的底層抽象類(lèi)
1.通過(guò)底層架構(gòu),把mvp的接口類(lèi)搭建起來(lái)
View層的抽象類(lèi)
interface IBaseView<T : IBasePresenter> {
fun getPresenter(): T
fun getLifecycle(): Lifecycle
/**
* 判斷Activity、Fragment是否回收
*/
fun isRecycled(): Boolean
}
Presenter層的抽象類(lèi)
interface IBasePresenter
2.通過(guò)做一個(gè)簡(jiǎn)單的Activity抽象類(lèi)為例
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
}
//有的頁(yè)面不需要Mvp所以不去實(shí)現(xiàn)
open fun initPresenter(): T? {
return null
}
override fun getPresenter(): T {
if (!::mPresenter.isInitialized) throw IllegalStateException("please override initPresenter()")
return mPresenter
}
}
3.做一個(gè)簡(jiǎn)單的Presenter層抽象類(lèi)
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)
}
})
}
}
這樣 我們就已經(jīng)把生命周期悄悄的傳遞給了presenter,下面是如何簡(jiǎn)單使用(這里網(wǎng)絡(luò)請(qǐng)求以Retrofit網(wǎng)絡(luò)請(qǐng)求為例,不了解retrofit網(wǎng)絡(luò)請(qǐng)求的同學(xué)請(qǐng)坐等我更新,或者去隔壁了解一下)
第二步:使用我們定義好的類(lèi)
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.下來(lái)是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,"網(wǎng)絡(luò)請(qǐng)求失敗",Toast.LENGTH_LONG)
}
}
}
3.接下來(lái)是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) //重點(diǎn)是這個(gè)
.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.網(wǎng)絡(luò)層回調(diào)定義
這里我們?yōu)樯队肧ingle,因?yàn)檫@里只有單次的網(wǎng)絡(luò)請(qǐng)求,如果回調(diào)后無(wú)二次網(wǎng)絡(luò)請(qǐng)求,則使用Single即可
Single<BaseResponse<ButtonData>> getButtonText();