欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實用小技巧之利用Lifecycle寫出更好維護的代碼

 更新時間:2022年05月05日 17:09:00   作者:廚師小p  
lifecycle是一個類,用于存儲有關組件(如Activity或Fragment)的生命周期狀態(tài)的信息,并允許其他對象觀察此狀態(tài),下面這篇文章主要給大家介紹了關于Android實用小技巧之利用Lifecycle寫出更好維護的代碼的相關資料,需要的朋友可以參考下

前言

你是否在onStart()啟動過某項任務卻忘記在onStop()中取消呢?人不是機器,難免會有錯漏。就算老手不會犯錯,也不能保證新人不會。學會下面的小技巧,讓這種粗心成為不可能。

關于Lifecycle的源碼,已經有很多大佬分析過。這篇文章的主旨是讓讀者對Lifecycle的使用場景有更多的體會,這樣也能更好地理解源碼。先來看一個場景,然后一步一步優(yōu)化。

場景

假設我們有一個界面,模擬一個廚房。里面有灶臺和餐桌。要求每秒鐘翻炒一下,總共10秒。一種常規(guī)的實現如下:

class KitchenFragment : Fragment() {
    private var timer: CountDownTimer? = null
    override fun onResume() {
        ...
        timer = object : CountDownTimer(COOKING_TIME_IN_MILLIS, SECOND_IN_MILLIS) {
            override fun onTick(millisUntilFinished: Long) {
                // 翻炒
            }
            override fun onFinish() { 
                // 出鍋 
            }
        }
        timer.start()
    }
    
    override fun onPause() {
        timer?.cancel()
        ...
    }
    
    compaion object {
        private const val COOKING_TIME_IN_MILLIS = 10000L
    }
}

潛在問題:

  • 在別的地方實現類似的功能需要把很多重復代碼復制過去
  • 忘記cancel()可能會造成一系列的麻煩
  • 當產品經理突然提出要同時顛勺5秒以及擦桌子20秒,代碼會變得很長

優(yōu)化版本1

先解決第一個問題,把CountDownTimer放到一個單獨的class。

class KitchenFragment : Fragment() {
    private val timer: CountDownTimer? = null
    override fun onResume() {
        ...
        timer = MyCountDownTimer(onTickAction = { 翻炒 },onFinishAction = { 出鍋 })
        timer.start()
    }
    
    override fun onPause() {
        timer?.cancel()
        ...
    }
}

// MyCountDownTimer.kt
class MyCountDownTimer@JvmOverloads constuctor(
    millisUntilFinished: Long = DEFAULT_DURATION_IN_MILLIS,
    countDownInterval: LONG = SECOND_IN_MILLIS,
    private val onTickAction: () -> Unit,
    private val onFinishAction: () -> Unit = {}
) : CountDownTimer(millisUntilFinished, countDownInterval) {

    override fun onTick(millisUntilFinished: Long) {
        onTickAction.invoke()
    }
    
    override fun onFinish() {
        onFinishAction.invoke()
    }
    
    compaion object {
        private const val DEFAULT_DURATION_IN_MILLIS = 10000L
    }
}

需要復用時,只需傳入需要改動的參數/方法:

// NeighbourKitchenFragment.kt
class NeighbourKitchenFragment : Fragment() {
    private val timer: CountDownTimer? = null
    override fun onResume() {
        ...
        timer = MyCountDownTimer(onTickAction = { 翻炒 },onFinishAction = { 甩鍋 })
        timer.start()
    }
    
    override fun onPause() {
        timer?.cancel()
        ...
    }
}

復用起來好像方便了一點,但是當上面提到過的的問題3出現時,代碼會變成:

class KitchenFragment : Fragment() {
    private val cookTimer1: CountDownTimer? = null
    private val cookTimer2: CountDownTimer? = null
    private val sweepTableTimer: CountDownTimer? = null
    override fun onResume() {
        ...
        cookTimer1 = MyCountDownTimer(onTickAction = { 翻炒 },onFinishAction = { 出鍋 })
        cookTimer1.start()
        
        cookTimer2 = MyCountDownTimer(millisUntilFinished = BRITAIN_SPOON_DURATION_IN_MILLIS,onTickAction = { 顛勺 })
        cookTimer2.start()
        
        sweepTableTimer = MyCountDownTimer(millisUntilFinished = SWEEP_TABLE_DURATION_IN_MILLIS,onTickAction = { 擦桌子 })
        sweepTableTimer.start()
    }
    
    override fun onPause() {
        cookTimer1?.cancel()
        cookTimer2?.cancel()
        sweepTableTimer?.cancel()
        ...
    }
    
    compaion object {
        private const val BRITAIN_SPOON_DURATION_IN_MILLIS = 5000L
        private const val SWEEP_TABLE_DURATION_IN_MILLIS = 20000L
    }
}

隨著需求增加,Fragment變得越來越長,也更難維護。同時,當在onResume中添加timer時被同事打斷,之后就有可能會忘記在onPause中cancel()。有沒有辦法解決這些問題呢?

接下來切入正題,讓我們看看Lifecycle能做什么。

優(yōu)化版本2

首先讓MyCountDownTimer實現DefaultLifecycleObserver,這樣它就是lifecycle-aware的了。這有什么用呢?有了這個,MyCountDownTimer就能在fragment/activity生命周期發(fā)生變化的時候得到通知并在內部處理cancel()等操作。

// MyCountDownTimer.kt
// Lifecycle-aware CountDownTimer
class MyCountDownTimer@JvmOverloads constuctor(
    millisUntilFinished: Long = DEFAULT_DURATION_IN_MILLIS,
    countDownInterval: LONG = SECOND_IN_MILLIS,
    private val onTickAction: () -> Unit,
    private val onFinishAction: () -> Unit = {}
) : CountDownTimer(millisUntilFinished, countDownInterval), DefaultLifecycleObserver {
    override fun onTick(millisUntilFinished: Long) {
        onTickAction.invoke()
    }
    
    override fun onFinish() {
        onFinishAction.invoke()
    }
    
    // onResume時自動開始
    override fun onResume(owner: LifecycleOwner) {
        start()
    }
    
    // onPause時自動取消
    override fun onPause(owner: LifecycleOwner) {
        cancel()
    }
    
    // onDestroy時停止觀察
    override fun onDestroy(owner: LifecycleOwner) {
        owner.lifecycle.removeObserver(this)
    }
    
    compaion object {
        private const val DEFAULT_DURATION_IN_MILLIS = 10000L
    }
}

上面例子中的KitchenFragment將會變成這樣:

class KitchenFragment : Fragment() {
    override fun onCreate() {
        ...
        initTimer()
    }
    
    private fun initTimer() {
        // 翻炒任務
        val timer1 = MyCountDownTimer(onTickAction = { 翻炒 },onFinishAction = { 出鍋 })
        // 顛勺任務
        val timer2 = MyCountDownTimer(millisUntilFinished = BRITAIN_SPOON_DURATION_IN_MILLIS,onTickAction = { 顛勺 })
        // 擦桌任務
        val timer3 = MyCountDownTimer(millisUntilFinished = SWEEP_TABLE_DURATION_IN_MILLIS,onTickAction = { 擦桌子 })
        
        viewLifecycleOwner.lifecycle.apply {
            addObserver(timer1)
            addObserver(timer2)
            addObserver(timer3)
        }
    }
    
    compaion object {
        private const val BRITAIN_SPOON_DURATION_IN_MILLIS = 5000L
        private const val SWEEP_TABLE_DURATION_IN_MILLIS = 20000L
    }
}

在Fragment中只需要專注于添加需要的功能,不用操心取消任務與停止觀察。既清爽又不容易犯錯。

單元測試

因為邏輯代碼都封裝在MyCountDownTimer,主要測試這個class就可以了。不需要給每一個使用MyCountDownTimer的Fragment都寫詳細的測試。

只需要mock一個LifecycleOwner就足夠,也不需要啟動一個mock Fragment。

class MyCountDownTimerTest {
    private lateinit var timer: MyCountDownTimer
    private lateinit var lifeCycle: LifecycleRegistry
    @Before
    fun setUp() {
        val lifeCycleOwner: LifecycleOwner = mock(LifecycleOwner::class.java)
        lifeCycle = LifecycleRegistry(lifeCycleOwner)
        timer = MyCountDownTimer(onTickAction = { 翻炒 },onFinishAction = { 出鍋 })
        lifeCycle.addObserver(timer)

        lifeCycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    }

    @Test
    fun timerActionExecuted() {
        lifeCycle.markState(Lifecycle.State.RESUMED)
        // 檢測是否開始翻炒,出鍋
        ...
    }
}

總結

通過把重復的代碼和邏輯封裝在自定義的LifecycleObserver內部,不僅可以給Activity/Fragment“瘦身”,防止忘記在onStop()/onDestroy()中收拾,還可以使復用代碼更加方便。同時也遵循設計模式,降低了Fragment與Timer之間的耦合度,讓代碼更好維護。

到此這篇關于Android實用小技巧之利用Lifecycle寫出更好維護的代碼的文章就介紹到這了,更多相關Android Lifecycle好維護的代碼內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Android仿微博首頁Tab加號彈窗功能

    Android仿微博首頁Tab加號彈窗功能

    這篇文章主要為大家詳細介紹了Android仿微博首頁Tab加號彈窗功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • android 放大鏡ShapeDrawable妙用分享

    android 放大鏡ShapeDrawable妙用分享

    android上想實現局部放大的效果,比如畫面中加個放大鏡的效果,發(fā)現ShapeDrawable是一個最好的選擇。
    2013-06-06
  • Convert WebP to PNG using java

    Convert WebP to PNG using java

    本文主要介紹Convert WebP to PNG using java,這里對 WebP 做了詳細說明,并講解Linux 環(huán)境下WebP 轉png格式的示例,有興趣的小伙伴可以參考下
    2016-08-08
  • Android不顯示開機向導和開機氣泡問題

    Android不顯示開機向導和開機氣泡問題

    這篇文章主要介紹了Android不顯示開機向導和開機氣泡問題,需要的朋友可以參考下
    2019-05-05
  • Android如何自定義升級對話框示例詳解

    Android如何自定義升級對話框示例詳解

    對話框是我們在平時經常會遇到的一個功能,但自帶的對話框不夠美觀,大家一般都會自定義,下面這篇文章主要給大家介紹了關于Android如何自定義升級對話框的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08
  • Android實現定時器的3種方法

    Android實現定時器的3種方法

    這篇文章主要為大家詳細介紹了Android實現定時器的3種方法,感興趣的小伙伴們可以參考一下
    2016-07-07
  • Android利用BitMap獲得圖片像素數據的方法

    Android利用BitMap獲得圖片像素數據的方法

    這篇文章主要介紹了Android利用BitMap獲得圖片像素數據的方法,結合實例對比分析了Android獲取圖片像素數據的相關技巧,需要的朋友可以參考下
    2016-02-02
  • flutter實現一個列表下拉抽屜的示例代碼

    flutter實現一個列表下拉抽屜的示例代碼

    本文主要介紹了flutter實現一個列表下拉抽屜的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 詳解AndroidStudio中代碼重構菜單Refactor功能

    詳解AndroidStudio中代碼重構菜單Refactor功能

    這篇文章主要介紹了AndroidStudio中代碼重構菜單Refactor功能詳解,本文通過代碼演示,功能截圖來詳細說明as為大名重構提供的各項功能,需要的朋友可以參考下
    2019-11-11
  • Android ViewPager實現無限循環(huán)的實例

    Android ViewPager實現無限循環(huán)的實例

    這篇文章主要介紹了Android ViewPager實現無限循環(huán)的實例的相關資料,需要的朋友可以參考下
    2017-07-07

最新評論