日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

LoaderManager使用详解(三)---实现Loaders

發布時間:2025/7/14 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LoaderManager使用详解(三)---实现Loaders 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這篇文字將介紹Loader<D>類,并且介紹自定義Loader的實現。這是本系列的第三篇文章。
一:Loaders之前世界 二:了解LoaderManager 三:實現Loaders 四:實例:AppListLoader
重中之重,如果你還沒有讀過前面兩篇文章,我建議你在深入之前先讀一讀那兩篇文章。先簡短的 總結一下這篇博客覆蓋了什么內容。Loader之前的世界(第一篇)描述了Android3.0之前的數據載入方法和在UI主線程中執行的冗長的查詢操 作。這些UI非友好的API導致了應用響應變差。總總情況就是了解LoaderManager(第二篇)的寫作動機。這篇文章介紹了 LoaderManager類,并且講到了它在異步載入數據中所扮演的角色。LoaderManager在Activity和Fragment的聲明周期 中管理Loaders,并且在配置變化時保持已載入的數據(譯者注:避免了Activity重啟導致數據重載入)。

Loader基礎


Loades負責在一個單獨線程中執行查詢,監控數據源改變,當探測到改變時將查詢到的結果集發送到注冊的監聽器上(通常是LoaderManager)。下面這些特性使Loaders成為AndroidSDK中強大的工具:
1. 它封裝了實際的數據載入。Activity/Fragment不再需要知道如何載入數據。實際上,Activity/Fragment將該任務委托給了Loader,它在后臺執行查詢要求并且將結果返回給Activity/Fragment。
2. 客戶端不需要知道查詢如何執行。Activity/Fragment不需要擔心查詢如何在獨立的線程中執行,Loder會自動執行這些查詢操作。這種方式不僅減少了代碼復雜度同事也消除了線程相關bug的潛在可能。
3. 它是為安全的事件驅動方式。Loader檢測底層數據,當檢測到改變時,自動執行新的載入獲取最新數據。這使得使用Loader變得容易,客戶端可以相信 Loader將會自己自動更新它的數據。Activity/Fragment所需要做的就是初始化Loader,并且對任何反饋回來的數據進行響應。除此 之外,所有其他的事情都由Loader來解決。
Loaders是一個比較高級的話題,可能需要更多時間來使用它。在下一節中,我們會從分析它的四個定義的特性來開始。

Loader由什么組成?


總共有四個特性最終決定了一個Loader的行為:
1. 執行異步載入的任務。為了確保在一個獨立線程中執行載入操作,Loader的子類必須繼承AsyncTaskLoader<D>而不是Loader<D>類。AsyncTaskLoader<D>是一個抽象Loader,它提供了一個AsyncTask來做它的執行操作。當定義子類時,通過實現抽象方法loadInBackground方法來實現異步task。該方法將在一個工作線程中執行數據加載操作。
2. 在一個注冊監聽器中接收載入完成返回的結果(見附注1)。對于每個Loader來說,LoaderManager注冊一個 OnLoadCompleteListener<D>,該對象將通過調用onLoadFinished(Loader<D> loader, D result)方法使Loader將結果傳送給客戶端。Loader通過調用Loader#deliverResult(D result),將結果傳遞給已注冊的監聽器們。
3. 三種不同狀態(見附注2)。任何Loader將處于三種狀態之中,已啟動、已停止、重啟: a. 處于已啟動狀態的Loader會執行載入操作,并在任何時間將結果傳遞到監聽器中。已啟動的Loader將會監聽數據改變,當檢測到改變時執行新的載入。 一旦啟動,Loader將一直處在已啟動狀態,一直到轉換到已停止和重啟。這是唯一一種onLoadFinished永遠不會調用的狀態。
b. 處于已停止狀態的Loader將會繼續監聽數據改變,但是不會將結果返回給客戶端。在已停止狀態,Loader可能被啟動或者重啟。 c. 當Loader處于重啟狀態時,將不會執行新的載入操作,也不會發送新的結果集,也不會檢測數據變化。當一個Loader進入重啟狀態,它必須解除對應的 數據引用,方便垃圾回收(同樣地,客戶端必須確定,在Loader無效之后,移除了所有該數據的引用)。通常,重啟Loader不會兩次調用;然而,在某 些情況下他們可能會啟動,所以如果必要的話,它們必須能夠適時重啟。
4. 有一個觀察者接受數據源改變的通知。Loader必須實現這些Observer其中之一(比如 ContentObserver,BroadcastReceiver等),來檢測底層數據源的改變。當檢測到數據改變,觀察者必須調用 Loader#onContentChanged()。在該方法中執行兩種不同操作:a. 如果Loader已經處于啟動狀態,就會執行一個新的載入操作; b. 設置一個flag標識數據源有改變,這樣當Loader再次啟動時,就知道應該重新載入數據了。
到目前為止,你應該基本知道了Loader如何工作了。如果沒有的話,我建議你先放一放,稍后再重新讀一遍(讀一下這篇文檔,)。也就是說,讓我們從實際代碼入手,寫寫看。

實現Loader


就如我之前陳述的那樣,在實現自定義Loader的時候有很多需要注意。子類必須實現 loadInBackground()方法,必須覆寫onStartLoading(), onStoppLoading(),onReset(),onCanceled()和deliverResult(D results)來實現一個完整功能的Loader。覆寫這些方法非常重要,LoaderManager將會在Activity/Fragment不同聲 明周期調用不同的方法。例如,當一個Activity第一次啟動,它將會讓LoaderManager在Activity#onStart()中啟動它所 擁有的每個Loaders。如果一個Loader沒有啟動,LoaderManager將會調用startLoading()方法,該方法將Loader 進入已啟動狀態并且立即調用Loader的onStartLoading()方法。也就是說,LoaderManager在后臺所做的大量工作都是基于 Loader正確實現的基礎上,所以不要小看實現這些方法的重要性。
下面的代碼就是Loader典型實現的樣板。SampleLoader查詢結果為一個包含SampleItem對象的列表,并且將查詢結果列表List<SampleItem>返回給客戶端:
[java] view plaincopy
  • public?class?SampleLoader?extends?AsyncTaskLoader<List<SampleItem>>?{??
  • ??
  • ??//?We?hold?a?reference?to?the?Loader’s?data?here.??
  • ??private?List<SampleItem>?mData;??
  • ??
  • ??public?SampleLoader(Context?ctx)?{??
  • ????//?Loaders?may?be?used?across?multiple?Activitys?(assuming?they?aren't??
  • ????//?bound?to?the?LoaderManager),?so?NEVER?hold?a?reference?to?the?context??
  • ????//?directly.?Doing?so?will?cause?you?to?leak?an?entire?Activity's?context.??
  • ????//?The?superclass?constructor?will?store?a?reference?to?the?Application??
  • ????//?Context?instead,?and?can?be?retrieved?with?a?call?to?getContext().??
  • ????super(ctx);??
  • ??}??
  • ??
  • ??/****************************************************/??
  • ??/**?(1)?A?task?that?performs?the?asynchronous?load?**/??
  • ??/****************************************************/??
  • ??
  • ??@Override??
  • ??public?List<SampleItem>?loadInBackground()?{??
  • ????//?This?method?is?called?on?a?background?thread?and?should?generate?a??
  • ????//?new?set?of?data?to?be?delivered?back?to?the?client.??
  • ????List<SampleItem>?data?=?new?ArrayList<SampleItem>();??
  • ??
  • ????//?TODO:?Perform?the?query?here?and?add?the?results?to?'data'.??
  • ??
  • ????return?data;??
  • ??}??
  • ??
  • ??/********************************************************/??
  • ??/**?(2)?Deliver?the?results?to?the?registered?listener?**/??
  • ??/********************************************************/??
  • ??
  • ??@Override??
  • ??public?void?deliverResult(List<SampleItem>?data)?{??
  • ????if?(isReset())?{??
  • ??????//?The?Loader?has?been?reset;?ignore?the?result?and?invalidate?the?data.??
  • ??????releaseResources(data);??
  • ??????return;??
  • ????}??
  • ??
  • ????//?Hold?a?reference?to?the?old?data?so?it?doesn't?get?garbage?collected.??
  • ????//?We?must?protect?it?until?the?new?data?has?been?delivered.??
  • ????List<SampleItem>?oldData?=?mData;??
  • ????mData?=?data;??
  • ??
  • ????if?(isStarted())?{??
  • ??????//?If?the?Loader?is?in?a?started?state,?deliver?the?results?to?the??
  • ??????//?client.?The?superclass?method?does?this?for?us.??
  • ??????super.deliverResult(data);??
  • ????}??
  • ??
  • ????//?Invalidate?the?old?data?as?we?don't?need?it?any?more.??
  • ????if?(oldData?!=?null?&&?oldData?!=?data)?{??
  • ??????releaseResources(oldData);??
  • ????}??
  • ??}??
  • ??
  • ??/*********************************************************/??
  • ??/**?(3)?Implement?the?Loader’s?state-dependent?behavior?**/??
  • ??/*********************************************************/??
  • ??
  • ??@Override??
  • ??protected?void?onStartLoading()?{??
  • ????if?(mData?!=?null)?{??
  • ??????//?Deliver?any?previously?loaded?data?immediately.??
  • ??????deliverResult(mData);??
  • ????}??
  • ??
  • ????//?Begin?monitoring?the?underlying?data?source.??
  • ????if?(mObserver?==?null)?{??
  • ??????mObserver?=?new?SampleObserver();??
  • ??????//?TODO:?register?the?observer??
  • ????}??
  • ??
  • ????if?(takeContentChanged()?||?mData?==?null)?{??
  • ??????//?When?the?observer?detects?a?change,?it?should?call?onContentChanged()??
  • ??????//?on?the?Loader,?which?will?cause?the?next?call?to?takeContentChanged()??
  • ??????//?to?return?true.?If?this?is?ever?the?case?(or?if?the?current?data?is??
  • ??????//?null),?we?force?a?new?load.??
  • ??????forceLoad();??
  • ????}??
  • ??}??
  • ??
  • ??@Override??
  • ??protected?void?onStopLoading()?{??
  • ????//?The?Loader?is?in?a?stopped?state,?so?we?should?attempt?to?cancel?the???
  • ????//?current?load?(if?there?is?one).??
  • ????cancelLoad();??
  • ??
  • ????//?Note?that?we?leave?the?observer?as?is.?Loaders?in?a?stopped?state??
  • ????//?should?still?monitor?the?data?source?for?changes?so?that?the?Loader??
  • ????//?will?know?to?force?a?new?load?if?it?is?ever?started?again.??
  • ??}??
  • ??
  • ??@Override??
  • ??protected?void?onReset()?{??
  • ????//?Ensure?the?loader?has?been?stopped.??
  • ????onStopLoading();??
  • ??
  • ????//?At?this?point?we?can?release?the?resources?associated?with?'mData'.??
  • ????if?(mData?!=?null)?{??
  • ??????releaseResources(mData);??
  • ??????mData?=?null;??
  • ????}??
  • ??
  • ????//?The?Loader?is?being?reset,?so?we?should?stop?monitoring?for?changes.??
  • ????if?(mObserver?!=?null)?{??
  • ??????//?TODO:?unregister?the?observer??
  • ??????mObserver?=?null;??
  • ????}??
  • ??}??
  • ??
  • ??@Override??
  • ??public?void?onCanceled(List<SampleItem>?data)?{??
  • ????//?Attempt?to?cancel?the?current?asynchronous?load.??
  • ????super.onCanceled(data);??
  • ??
  • ????//?The?load?has?been?canceled,?so?we?should?release?the?resources??
  • ????//?associated?with?'data'.??
  • ????releaseResources(data);??
  • ??}??
  • ??
  • ??private?void?releaseResources(List<SampleItem>?data)?{??
  • ????//?For?a?simple?List,?there?is?nothing?to?do.?For?something?like?a?Cursor,?we???
  • ????//?would?close?it?in?this?method.?All?resources?associated?with?the?Loader??
  • ????//?should?be?released?here.??
  • ??}??
  • ??
  • ??/*********************************************************************/??
  • ??/**?(4)?Observer?which?receives?notifications?when?the?data?changes?**/??
  • ??/*********************************************************************/??
  • ???
  • ??//?NOTE:?Implementing?an?observer?is?outside?the?scope?of?this?post?(this?example??
  • ??//?uses?a?made-up?"SampleObserver"?to?illustrate?when/where?the?observer?should???
  • ??//?be?initialized).???
  • ????
  • ??//?The?observer?could?be?anything?so?long?as?it?is?able?to?detect?content?changes??
  • ??//?and?report?them?to?the?loader?with?a?call?to?onContentChanged().?For?example,??
  • ??//?if?you?were?writing?a?Loader?which?loads?a?list?of?all?installed?applications??
  • ??//?on?the?device,?the?observer?could?be?a?BroadcastReceiver?that?listens?for?the??
  • ??//?ACTION_PACKAGE_ADDED?intent,?and?calls?onContentChanged()?on?the?particular???
  • ??//?Loader?whenever?the?receiver?detects?that?a?new?application?has?been?installed.??
  • ??//?Please?don’t?hesitate?to?leave?a?comment?if?you?still?find?this?confusing!?:)??
  • ??private?SampleObserver?mObserver;??
  • }??

  • 總結


    我希望本文對你有用,并且通過它可以很好的理解Loaders和LoaderManager 如何協同工作來執行異步任務,自動更新查詢結果。記住,Loader是你的朋友。。。如果你使用它們,你的app將從相應性能、所需代碼量中收益。我希望 通過把它們的細節列舉出來,可以減小它的學習曲線。

    附注

    1. 你不需要擔心為你的Loader注冊監聽器,除非你不準備跟LoaderManager協同使用。LoaderManager擔任的就是 “listener”的角色,并將Loader返回的任何結果傳給LoaderCallbacks#LoadFinished方法。 2. Loader也有可能處于“abandoned”狀態(譯者注:丟棄狀態?)。這個是一個可選的中間狀態,處于停止狀態和重置狀態之間。為了更簡明的理解,再這里不討論丟棄狀態。也就是說,以我的經驗來看,通常并無必要實現onAbandon()方法。

    轉載于:https://www.cnblogs.com/Free-Thinker/p/4378909.html

    總結

    以上是生活随笔為你收集整理的LoaderManager使用详解(三)---实现Loaders的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。