文章開頭先來引入一個 業務案例安全
這是一個學習英語的App,部分頁面支持 劃詞播放markdown
如何能夠優雅得實現這個真實的業務場景呢?架構
首先須要定義一個全局單例的播放器,播放器有一個方法play(val content: String)
ide
object ContentPlayer {
fun play(content: String) {
//調用系統播放器播放
}
fun prepare(context: Context) {
//播放器的準備工做
}
}
複製代碼
實現ContentPlayer以後,就能夠在支持劃詞播放功能的Activity的劃詞事件回調中這樣寫:post
class ContentActivity : AppCompatActivity(), UnderLineWordCallBack {
override fun onCreate(savedInstanceState: Bundle?) {
...
ContentPlayer.prepare(this)
}
//當前Activity的劃詞播放後回調這裏
override fun callback(content: String) {
// 開始播放
ContentPlayer.play(content)
}
}
複製代碼
這樣這個功能就作完了。真得作完了嗎?若是你的Leader看到這樣的代碼,怕不是次日讓你捲鋪蓋走人~(開玩笑的開玩笑的)學習
這樣的代碼可能會發生 內存泄漏 :
假設客戶劃了一段很長的英語文章,而後點擊播放,播放到一半客戶不想聽了,直接點擊了返回鍵後,播放器還持有着 ContentActivity的引用,在播放器繼續播放的過程當中,ContentActivity是沒法被gc的,這就會出現了問題優化
因此咱們還須要準備一個unAttach()
方法。最終的方案以下:this
object ContentPlayer{
fun play(content: String) {
//調用系統播放器播放
}
fun prepare(context: Context) {
//播放器的準備工做
}
fun unAttach() {
//釋放當前持有的Activity資源
}
}
複製代碼
class ContentActivity : AppCompatActivity(), UnderLineWordCallBack {
override fun onCreate(savedInstanceState: Bundle?) {
...
//準備播放器資源
ContentPlayer.prepare(this)
}
//當前Activity的劃詞播放後回調這裏
override fun callback(content: String) {
// 開始播放
ContentPlayer.play(content)
}
override fun onDestory() {
...
// 釋放資源
ContentPlayer.unAttach()
}
}
複製代碼
上面這樣的代碼固然沒有問題了,能夠正常使用,咱們還嚴謹的保護了App不發生內存泄漏,值得表揚!spa
可是還有問題:code
若是當前App有不少的Activity要用到劃詞播放這個功能,那麼咱們就須要在每個Activity中重複上面的代碼,當代碼量上來以後,會很容易遺忘調用unAttach方法,並且一個項目不多是以後一我的完成,每每是協做開發,若是別人寫的界面想要調用你寫的ContentPlayer,除非你寫了很詳細的註釋,不然必須深刻源碼,才知道在Activity的onDestory處去釋放資源。
更優雅,更安全的寫法,就是利用Lifecycle組件
在進一步使用Lifecycle優化上述代碼以前,先看一下Lifecycle的官方定義:
生命週期感知型組件可執行操做來響應另外一個組件(如 Activity 和 Fragment)的生命週期狀態的變化。這些組件有助於您寫出更有條理且每每更精簡的代碼,這樣的代碼更易於維護。
也就是說,咱們寫代碼中開發的某個組件須要去感知生命週期時,要首先想到使用Lifecycle。
可讓咱們在組件內部來監聽到生命週期,就像這樣:
object ContentPlayer : LifecycleObserver{
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun prepare(context: Context) {
//播放器的準備工做
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun unAttach() {
//釋放當前持有的Activity資源
}
}
複製代碼
經過方法註解,決定當前方法被調用的時機。以後在須要使用ContentPlayer的Activity中去註冊觀察者
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 一行代碼搞定
lifecycle.addObserver(ContentPlayer)
}
複製代碼
用到劃詞播放的界面只需經過一行代碼,lifecycle.addObserver(ContentPlayer)
註冊lifecycle觀察者。完美解決了調用一致性和代碼侵入性太強的問題。
Lifecycle除了給咱們開發者使用以外,在Android源碼很 Lifecycle組件是Google Jectpack架構的基礎,Jectpack的組件:databing、viewmodel等等都依賴於lifecycle對生命週期的感知,因此我認爲在學習jectpack和MVVM以前,須要先了解一下Lifecycle的使用和 基本實現原理