官术网_书友最值得收藏!

2.3 使用Lifecycle解決實際項目中常見的問題

了解Lifecycle的基本使用之后,接著來看如何使用Lifecycle解決實際項目中常見的問題。

2.3.1 Dialog內(nèi)存泄漏問題分析

Dialog是Android開發(fā)中最常用的組件之一,相信每位讀者都使用過。現(xiàn)在一起實現(xiàn)一個Dialog,用于網(wǎng)絡(luò)請求的簡單提示。Dialog的代碼很簡單,直接設(shè)置一個布局即可,具體如下:

class TipDialog(context: Context) : Dialog(context) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.item_tip_dialog)
    }
}

接下來模擬如下場景:

  • 進入頁面時開始網(wǎng)絡(luò)請求,顯示Dialog。
  • 請求結(jié)束時(兩秒后),退出當(dāng)前頁面。

下面實現(xiàn)上述需求,Activity的代碼如下:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        TipDialog(this).show()
        Handler().postDelayed({
            finish()
        }, 2000)
    }
}

運行程序,兩秒后,軟件出現(xiàn)異常崩潰,錯誤日志如下:

00:58:23.618 28162-28162/com.example.jetpackdemo E/WindowManager: android.view.WindowLeaked: Activity com.example.jetpackdemo.ui.activity.MainActivity has leaked window DecorView@df7a4a4[MainActivity] that was originally added here
        at android.view.ViewRootImpl.<init>(ViewRootImpl.java:818)
        at android.view.ViewRootImpl.<init>(ViewRootImpl.java:798)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:399)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:110)
        at android.app.Dialog.show(Dialog.java:353)
        at com.example.jetpackdemo.ui.activity.MainActivity.onCreate(MainActivity.kt:23)
        at android.app.Activity.performCreate(Activity.java:8146)
        at android.app.Activity.performCreate(Activity.java:8130)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1310)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3668)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3866)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:100)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2296)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:254)
        at android.app.ActivityThread.main(ActivityThread.java:8234)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

相信很多開發(fā)者都遇到過這個錯誤,這是因為在Activity關(guān)閉的時候,Dialog沒有關(guān)閉,進而導(dǎo)致內(nèi)存泄漏。了解了出現(xiàn)異常的原因,解決起來就很容易了,在銷毀Activity的時候,關(guān)閉Dialog即可,示例代碼如下:

class MainActivity : AppCompatActivity() {
    var dialog: TipDialog? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        dialog = TipDialog(this)
        dialog?.show()
        Handler().postDelayed({
            finish()
        }, 2000)
    }
    override fun onDestroy() {
        super.onDestroy()
        dialog?.dismiss()
    }
}

上面的方法雖然可以解決內(nèi)存泄漏問題,但若彈窗類型很多,則需要在onDestroy中編寫許多額外的處理邏輯,且容易忘記,不過,如果使用Lifecycle組件,就可以完美地解決這個問題。

2.3.2 使用Lifecycle打造一個完美的Dialog

由于Dialog中的參數(shù)Context必須是Activity的上下文,因此開發(fā)者完全可以在Dialog中使用Lifecycle組件來感知生命周期,在2.2.1節(jié)中已經(jīng)介紹,只要是在androidx.fragment.app.Fragment、ComponentActivity及其子類Activity中,就可以直接使用Lifecycle組件。所以這成了一個取舍問題,如果xxxActivity繼承的是Activity,將無法直接使用Lifecycle,那就只能自定義LifecycleOwner或者在Activity中注冊了,但是這樣做完全沒有必要,這里默認xxxActivity繼承的是ComponentActivity。

修改TipDialog的代碼,使得TipDialog可以感應(yīng)生命周期變化,示例如下:

class TipDialog(context: Context) : Dialog(context), LifecycleObserver {
    init {
        if (context is ComponentActivity) {
            (context as ComponentActivity).lifecycle.addObserver(this)
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.item_tip_dialog)
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private fun onDestroy() {
        if (isShowing) {
            dismiss()
        }
    }
}

上面的代碼在2.2.1節(jié)中已經(jīng)詳細介紹了,此處就不再贅述。當(dāng)Dialog所依附的Activity被銷毀時,Dialog也可以自動關(guān)閉,再也不用擔(dān)心Dialog的內(nèi)存泄漏問題了。如此一來,就使用Lifecycle實現(xiàn)了一個完美的Dialog。

注意

在實際項目開發(fā)中,Dialog使用不當(dāng)會出現(xiàn)除了內(nèi)存泄漏之外的其他問題,這需要開發(fā)者自行處理,這里解決的只是此種情境下產(chǎn)生的內(nèi)存泄漏問題。

主站蜘蛛池模板: 佛坪县| 高青县| 江津市| 尉犁县| 桃园市| 安图县| 嘉兴市| 黄平县| 体育| 威海市| 象州县| 昭觉县| 临夏市| 霍州市| 旌德县| 临泉县| 靖宇县| 宜丰县| 汝州市| 武夷山市| 清原| 尖扎县| 襄城县| 鞍山市| 南和县| 桂林市| 开鲁县| 松潘县| 新邵县| 海门市| 勃利县| 浏阳市| 治县。| 嘉峪关市| 南漳县| 商城县| 手游| 文昌市| 陵川县| 黎平县| 沐川县|