編輯:關於Android編程
如果對Loader、AsyncTaskLoader、CursorLoader、LoaderManager等概念不明白或不知道如何使用Loader機制,可參見博文Android中Loader及LoaderManager的使用(附源碼下載)。本文主要通過研究Loader及其子類的生命周期的方式來對Loader及其子類、LoaderManager的源碼進行研究。
Loader是靠LoaderManager管理的,LoaderManager可以同時管理多個Loader,即LoaderManager與Loader是一對多的關系。我們是在Activity或Fragment使用Loader的,雖然Loader有很多public方法,但是我們不能直接調用Loader的這些public方法,因為這會擾亂LoaderManag對Loader的正常管理,我們應該通過LoaderManager的initLoader以及restartLoader方法間接管理Loader,並通過LoaderCallbacks的回調方法(onCreateLoader、onLoadFinished、onLoaderReset)對數據進行相應處理。
Loader本身不具備異步加載數據的能力;AsyncTaskLoader繼承自Loader,通過AsyncTask可以異步加載數據;CursorLoader繼承自AsyncTaskLoader,可以異步加載Cursor數據。
我們是在Activity或Fragment使用Loader的,Activity、Fragment與LoaderManagement交互類似於client-server模式,即Activity或Fragment是該client-server模型中的client端,即客戶端,在本文中,我們所提到的客戶端均指的是Loader的使用者,即Activity或Fragment。
概括來說,Loader有兩大生命周期: active 和 inactive,即活動狀態和非活動狀態。這一點在LoaderManager的源碼中體現的很直觀: LoaderManager內部有兩個數組mLoaders和mInactiveLoaders,其中mLoaders存儲著所有處於active狀態的Loader,mInactiveLoaders存儲著所有處於inactive狀態的Loader。
細分來說,Loader的active狀態又分為started狀態和stopped狀態,即啟動狀態和停止狀態,注意,stopped狀態也是active生命周期的。Loader的inactive狀態又分為abandoned狀態和reseted狀態,即廢棄狀態和重置狀態,其中abandoned狀態表明Loader現在已經廢棄了,過段時間也會被重置,reseted狀態表明該Loader完全被銷毀重用了。Loader活躍度從高到低依次為 started -> stopped -> abandoned -> reseted,這也對應著Loader的四個生命周期,Loader處於started狀態時最活躍,Loader處於reseted狀態時完全不活躍。實際上,處於stopped狀態的Loader也有可能再次轉變為started狀態,所以我們要稍將上面started到stopped之間單向箭頭改為雙向箭頭,即Loader准確的生命周期應該是 started <-> stopped -> abandoned -> reseted。
以下是對Loader及其子類各生命周期中源碼調用過程的分析,需要說明的是,由於AsyncLoader繼承自Loader、CursorLoader繼承自AsyncLoader,所以我們在分析代碼時,這三個類都會涉及,因為子類可以實現或重寫父類的方法,比如Loader類自身有個空的方法onStartLoading(),AsyncLoader沒有重寫該方法,但是CursorLoader重寫了Loader中的空方法onStartLoading()從而CursorLoader在該方法中實現自己的邏輯。
需要注意的是,LoaderManager是個抽象類,Android有一個類LoaderManagerImpl實現了LoaderManager,Activity或Fragment中通過getLoaderManager()方法返回的其實是一個LoaderManagerImpl的實例,所以我們要同時研究LoaderManager和LoaderManagerImpl 。
Loader及其相關類的源碼地址如下:
Loader源碼
AsyncTaskLoader源碼
CursorLoader源碼
LoaderManager源碼
LoaderManagerImpl源碼
Loader在執行了startLoading()方法後,會進入started狀態,LoaderManager會在合適的時機執行Loader.startLoading()方法,概括來說,當我們執行LoadManager.initLoader()時,如果Loader不存在,內部會執行LoadCallbacks的onCreateLoader()方法創建Loader,並讓新創建的Loader執行startLoading()方法。
具體執行過程如下:
LoaderManager.initLoader() ->
LoaderManager.createAndInstallLoader() ->
LoaderManager.createLoader() ->
LoaderCallbacks.onCreateLoader() ->
得到loader之後創建LoaderInfo ->
LoaderManager.installLoader() ->
將其放入LoaderManager內部維護的mLoaders數組中 ->
LoaderInfo.start() ->
Loader處於started狀態 ->
Loader.startLoading() ->
我們可以在onStartLoading()中寫我們的邏輯,在started狀態下,Loader應該監控數據源的變化,並將新數據發送給客戶端,具體來說就是當監控到新數據後,調用Loader.deliverResult()方法,觸發LoadCallbacks.onLoadFinished()回調的執行,從而客戶端可以從該回調中輕松獲取數據。
CursorLoader重寫了Loader中的onStartLoading()方法,以下是CursorLoader在執行到onStartLoading()之後的邏輯,從中我們可以看出AsyncLoader和CursorLoader如何實現異步加載數據。
CursorLoader.onStartLoading() ->
AsyncTaskLoader.forceLoad() ->
Loader.forceLoad() ->
AsyncTaskLoader.onForceLoad() ->
AsyncTaskLoader.executePendingTask() ->
進入異步線程->
LoadTask.doInBackground() ->
AsyncTaskLoader.onLoadInBackground() ->
AsyncTaskLoader.doInBackground() ->
得到實際的數據 ->
退出異步線程,返回主線程 ->
LoadTask.onPostExecute() ->
AsyncTaskLoader.dispatchOnLoadComplete() ->
CursorLoader.deliverResult() -> Loader.deliverResult() ->
LoaderInfo.onLoadComplete() ->
LoaderInfo.callOnLoadFinished() ->
LoaderCallbacks.onLoadFinished()
Loader在執行了stopLoading()狀態後,會進入stopped狀態,LoaderManager會在合適的時機執行Loader.stopLoading()方法,概括來說,當Activity將要處於stopped狀態的時候會執行Activity的performStop()方法,在該方法內會執行FragmentController的doLoaderStop()方法,在該方法內又會執行FragmentHostCallback的 doLoaderStop()方法,在該方法內部會執行LoaderManager的doStop()方法,在該方法內,LoaderManager會遍歷所有的內部存儲的LoaderInfo,依次執行LoaderInfo的stop()方法,在該方法中內部又會調用Loader.stopLoading()方法,此時Loader進入stopped方法,然後執行Loader的stopLoading()。
started -> stopped狀態變化的具體執行過程如下:
Activity.performStop() ->
FragmentController.doLoaderStop() ->
FragmentHostCallback.doLoaderStop() ->
LoaderManager.doStop() ->
所有LoaderInfo.stop() ->
Loader.stopLoading() ->
Loader進入stopped狀態 ->
onStopLoading(),我們可以在onStartLoading()中寫我們的邏輯。
由上面的調用過程我們可以發現,當Activity處於stopped狀態時,所有的Loader也會被置於stopped狀態,其實你如果去觀察Fragment的源碼也會發現當Fragment處於stopped狀態時,所有的Loader也會被置於stopped狀態。
當Activity執行onStart()方法的時候,其內部又會執行FragmentController的doLoaderStart()方法,進而執行FragmentHostCallback的doLoaderStart()方法,進而執行LoaderManager的doStart()方法,內部會遍歷所有LoaderInfo,並執行LoaderInfo的start()方法,進而執行Loader的startLoading()方法,從而Loader又進入了started狀態,進而執行Loader的onStartLoading()。
stopped -> started狀態變化的具體執行過程如下:
Activity.onStart() ->
FragmentController.doLoaderStart() ->
FragmentHostCallback.doLoaderStart() ->
LoaderManager.doStart() ->
所有LoaderInfo.start() ->
Loader.startLoading() ->
Loader從stopped狀態進入started狀態 ->
Loader.onStartLoading()。
由上面的調用過程我們可以發現,當Activity從stopped重新處於started狀態時,所有處於stopped狀態的Loader也會被從stopped狀態變為started狀態,其實你如果去觀察Fragment的源碼也會發現當Fragment從stopped狀態變為started狀態時,Loader也會從stopped狀態變為started狀態。
通過上面的描述,我們可以得知,Android想保持Loader與其用者(Activity或Fragment)的狀態保持一致,同為started或同為stopped。
當Loader處於stopped狀態的時候,我們應該繼續監聽數據的變化,但是此時有新數據的時候我們應該先存起來,不將其發送給客戶端,因為客戶端(Activity或Fragment)也處於stopped狀態,發給客戶端也沒啥用。如果Loader從stopped狀態變為了started狀態,那麼我們此時應該將之前監聽到的新數據發送給客戶端(Activity或Fragment),因為客戶端此時肯定也處於started狀態,發給客戶端之後,客戶端就可以更新UI之類的。
Loader在執行了abandon()方法後,會進入abandoned狀態,LoaderManager會在合適的時機執行Loader.abandon()方法,概括來說,當執行LoaderManager.restartLoader(loaderId)時候,如果指定loaderId對應的Loader存在,而且處於active狀態(具體包括started和stopped兩種狀態),那麼就會調用原Loader的abandon()方法,這樣原Loader就處於abandoned狀態,並且LoaderManager會將該Loader放入到LoaderManager內部維護的mInactiveLoaders數組中,在原Loader進入abandoned狀態後,我們會創建一個新的Loader。此時,剛剛放入到mInactiveLoaders數組中的loader就變成了一個老的廢棄的loader,注意此時該老Loader還不會銷毀,是因為我們雖然創建了新的loader,但是新的loader還沒有即可獲取到數據,所以此時我們依然還要保存該老的loader,這樣客戶端在沒有得到新loader發來的數據前還可以繼續使用老的loader的數據,一旦新loader加載完了數據並發給了客戶端,那此時該老的loader就完全沒用了,LoaderManager會將其置於reseted狀態並將其從mInactiveLoaders中移除掉,即這個老loader被銷毀了,關於如何從abandoned變成reseted的細節下面還會從代碼調用上詳細解釋。
abandoned狀態是Loader從stopped到reseted狀態的一個中間狀態,一般情況下,進入abandoned狀態的Loader會過段時間被完全銷毀標記為reseted狀態,所以abandoned狀態的Loader不應再監聽數據源的變化,更不應該將變化的數據源發送給客戶端。
Loader在執行了reset()方法後,會進入rested狀態,LoaderManager會在合適的時機執行Loader.reset()方法,具體執行過程如下:
上面提到,在執行了LoaderManager的restartLoader()方法後,我們會將原始的loader放入mInactiveLoaders中使其處於abandoned轉台,之後會立即創建一個新Loader。
新Loader會開始其自己新的征程,具體執行過程如下:
LoadManager.initLoader() ->
LoaderManager.createAndInstallLoader ->
LoadCallbacks.onCreateLoader() ->
LoaderManager.installLoader ->
將其放入LoaderManager內部維護的mLoaders數組中 ->
Loader.startLoading() ->
Loader進入started狀態 ->
Loader.onStartLoading(),此時我們會在Loader的onStartLoading()中去加載數據,當加載完畢後,我們會執行Loader.deliverResult(data)去將數據派發出去給客戶端使用,從該方法開始,其調用順序是Loader.deliverResult(data) ->
LoaderInfo.onLoadComplete() ->
LoaderInfo.callOnLoadFinished ->
LoaderCallbacks.onLoadFinished ->
客戶端拿到數據 ->
檢查該loaderId在mInactiveLoaders中有沒有對應loaderId的loader,如果能找到,那麼就說明從mInactiveLoaders中找到的這個被廢棄的loader恰恰是上面我們解釋abandoned的時候由於LoaderManager.restartLoader(loaderId)的執行被塞到mInactiveLoaders並處於abandoned狀態的,那麼此時mInactiveLoaders中的這個老loader就完全沒用了,LoaderManager會調用該廢棄Loader的reset()方法,對於該廢棄的Loader具體執行過程是:
廢棄的LoaderInfo.destroy() ->
廢棄的Loader.reset() ->
廢棄的Loader.onReset() ->
廢棄的Loader此時狀態從abandoned變為rested狀態 ->
最後LoaderManager將其從mInactiveLoaders中移除掉,即這個老loader被銷毀了。
處於reseted狀態的Loader被完全銷毀了,或者准確的說LoaderManager把該Loader標記為銷毀狀態reseted。
希望本文對大家理解Loader的生命周期有所幫助,在理解了Loader生命周期的基礎上,我們才能寫出符合自己需求的Loader,後面會寫自定義Loader的文章。
Android中Button控件應該算作是比較簡單的控件,然而,它的使用頻率卻是非常的高,今天,我在這裡總結了三種常用的點擊Button實現其功能的方法。1.很多時候,我
基本布局演示1. 定義包含GridView 的 main.xmk<?xml version=1.0 encoding=utf-8?><L
ScaleType表示ImageView的縮放類型,決定了一張圖片在ImageView控件內如何縮放和顯示。ScaleType的官方文檔:https://develope
第二種實現android應用Theme的方式是通過apk來實現的。下面是一個demo。 1.首先必須新建一個apk,類似的插件,然後在該apk的Androi