您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Android 3.0中怎么引入Loader異步加載機制,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
Loader是谷歌在Android 3.0引入的異步加載機制,能夠?qū)?shù)據(jù)異步加載并顯示到Activity或Fragment上,使用者不需要對數(shù)據(jù)的生命周期進行管理,而是交給Loader機制來管理。
使用Loader的優(yōu)點
假如我們需要從網(wǎng)絡上獲取數(shù)據(jù),通常的做法是使用子線程Thread+Handler或者是使用AsyncTask來處理。
Thread+Handler方法實現(xiàn)起來簡單直觀,不過會麻煩點,需要自己實現(xiàn)Handler子類,創(chuàng)建線程,還要管理Handler的生命周期。
AsyncTask實現(xiàn)起來會簡單些,無需自己管理線程和Handler。但是要管理AsyncTask的生命周期,要對Activity退出時的情況進行處理。否則可能會出現(xiàn)異常或內(nèi)存泄露。
使用Loader無需關心線程和Handler的創(chuàng)建和銷毀,也無需自己管理數(shù)據(jù)整個的生命周期,Loader機制會自動幫我們處理好。我們唯一要處理的就是數(shù)據(jù)本身。
Loader使用的步驟:
創(chuàng)建FragmentActivity或Fragment 持有LoaderManager的實例實現(xiàn)Loader,用來加載數(shù)據(jù)源返回的數(shù)據(jù)實現(xiàn)LoaderManager.LoaderCallbacks接口實現(xiàn)數(shù)據(jù)的展示提供數(shù)據(jù)的數(shù)據(jù)源,如ContentProvider,服務器下發(fā)的數(shù)據(jù)等 幾個相關的類 LoaderManager
管理Loader實例,并使之和FragmentActiivty或Fragment關聯(lián)上
一個Activity或Fragment有一個唯一的LoaderManager實例
一個LoaderManager實例可以管理多個Loader實例
可以在FragmentActivity或Fragmeng中使用getSupportLoaderManager()獲取到LoaderManager實例
可以使用 initLoader() 或 restartLoader() 方法開始進行數(shù)據(jù)的加載
//0,為唯一的ID,可以為任意整數(shù),為Loader的唯一標識 //null,為Bundle類型,可以向Loader傳遞構(gòu)造參數(shù) //LoaderCallbacks,LoaderManager對Loader各事件的調(diào)用,參考下面講到的 LoaderManager.LoaderCallbacks getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<D>());
LoaderManager.LoaderCallbacks
LoaderManager對Loader各種情況的回調(diào)接口,包含三個回調(diào)方法
onCreateLoader(int,Bundle)
在這里需要自己創(chuàng)建Loader對象,int 為Loader的唯一標識,Bundle為Loader的構(gòu)造參數(shù),可為空
... new LoaderManager.LoaderCallbacks<String>() { @Override public Loader<String> onCreateLoader(int id, Bundle args) { return new MyLoader(); } ... }
onLoadFinished(Loader<D>,D)
當LoaderManager加載完數(shù)據(jù)時回調(diào)此方法,在這里用UI展示數(shù)據(jù)給用戶。D為泛型,根據(jù)實際情況設置為所需的數(shù)據(jù)類型。和initLoader()LoaderCallbacks<D>參數(shù)中的的泛型為同一類型
new LoaderManager.LoaderCallbacks<String>() { ... @Override public void onLoadFinished(Loader<String> loader, String data) { show(data); } ... }
onLoaderReset(Loader<D>)
當之前創(chuàng)建的Loader實例被重置的時候會回調(diào)此方法,此時需要對相關的數(shù)據(jù)進行清除處理
new LoaderManager.LoaderCallbacks<String>() { ... @Override public void onLoaderReset(Loader<String> loader) { show(null); } ... }
Loader
從數(shù)據(jù)源獲取數(shù)據(jù),并對數(shù)據(jù)進行加載,為抽象類,需要自己實現(xiàn)子類
或使用官方已經(jīng)實現(xiàn)的兩個子類
AsyncTaskLoader(繼承此類的時候會遇到一個坑,見下面的分析)
處理異步獲取數(shù)據(jù) CursorLoader
處理ContentProvider返回的數(shù)據(jù) 實現(xiàn)AsyncTaskLoader遇到的一個坑
首先自定義一個 MyAsyncTaskLoader,繼承AsyncTaskLoader,會發(fā)現(xiàn)需要實現(xiàn)參數(shù)為Context的構(gòu)造方法和實現(xiàn) loadInBackground() 抽象方法
//繼承AsyncTaskLoader類,里面的泛型為返回的數(shù)據(jù)的類型,這里設為String public class MyAsyncTaskLoader extends AsyncTaskLoader<String>{ public MyAsyncTaskLoader(Context context) { super(context); } @Override public String loadInBackground() { //模擬加載 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } //返回獲取到的數(shù)據(jù) return new String("MyAsyncTaskLoader Test Result"); } }
創(chuàng)建FragmentActivity
public class BaseActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks{ @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.base_activity_layout); // addFragment(); log("onCreate"); loadData(); } protected void loadData(){ Log.e(getClassName(),"call"); getSupportLoaderManager().initLoader(0, null, this); } protected String getClassName(){ return getClass().getSimpleName(); } @Override public Loader onCreateLoader(int id, Bundle args) { Log.e(getClassName(),"onCreateLoader"); return new MyAsyncTaskLoader(BaseActivity.this); } @Override public void onLoadFinished(Loader loader, Object data) { Log.e(getClassName(),"data:"+data); } @Override public void onLoaderReset(Loader loader) { } }
當運行的時候發(fā)現(xiàn)日志值打印了onCreate,call,onCreateLoader,而預期中的 MyAsyncTaskLoader Test Result 并沒有輸出,也就是說 onLoadFinished 并未被回調(diào)。調(diào)試發(fā)現(xiàn) MyAsyncTaskLoader 中的 loadInBackground() 方法也未執(zhí)行。
這個是怎么回事呢?
那么只好查看源碼了,這里所使用的都是 support-v4 的包。
查看 AsyncTaskLoader 源碼發(fā)現(xiàn) loadInBackground() 方法的確為 abstract 類型,其被調(diào)用的地方是在一個叫做 LoadTask 的內(nèi)部類中。
//可以把 ModernAsyncTask 看做 AsyncTask final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable { .... @Override protected D doInBackground(Void... params) { ... D data = AsyncTaskLoader.this.onLoadInBackground(); ... } ..... }
并且作為AsyncTaskLoader的一個全局變量。
public abstract class AsyncTaskLoader<D> extends Loader<D> { .... volatile LoadTask mTask; .... }
mTask 實例化和被執(zhí)行的地方在 onForceLoad() 方法里
... @Override protected void onForceLoad() { ... mTask = new LoadTask(); ... executePendingTask(); } ... void executePendingTask() { ... if (mUpdateThrottle > 0) { ... mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle); return; } } ... mTask.executeOnExecutor(mExecutor, (Void[]) null); } }
mHandler.postAtTime 或者是 mTask.executeOnExecutor 這兩個地方就是執(zhí)行 TaskLoader 的地方,并會調(diào)用到 doInBackground() 方法。
那么到這里我們可以猜測我們自定義的 MyAsyncLoader 的 loadInBackground() 未被執(zhí)行,那么 onForceLoad() 也應該未被執(zhí)行。
沿著這條線索查找看看這個 onForceLoad() 是在哪里被調(diào)用的。發(fā)現(xiàn)其是在AsyncLoader 的父類 Loader 中的 forceLoad() 中被調(diào)用
public class Loader{ ... public void forceLoad() { onForceLoad(); } ... }
然后又看到注釋發(fā)現(xiàn),此方法只能在 loader 開始的時候調(diào)用,還是找不到什么頭緒。
突然想到好像 CursorLoader 沒有這個問題,那么看看它是不是有調(diào)用 forceLoad(),找了下,發(fā)現(xiàn)還果然有!是在 onStartLoading() 這個方法里,并且只有這里調(diào)用!
public class CursorLoader extends AsyncTaskLoader<Cursor> { ... @Override protected void onStartLoading() { if (mCursor != null) { deliverResult(mCursor); } if (takeContentChanged() || mCursor == null) { forceLoad(); } } ... }
那么我模仿下這個看看是不是真的能行,MyAsyncLoader 的代碼修改如下:
//繼承AsyncTaskLoader類,里面的泛型為返回的數(shù)據(jù)的類型,這里設為String public class MyAsyncTaskLoader extends AsyncTaskLoader<String>{ public MyAsyncTaskLoader(Context context) { super(context); } //添加了這段代碼 @Override protected void onStartLoading() { forceLoad(); } @Override public String loadInBackground() { //模擬加載 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } //返回獲取到的數(shù)據(jù) return new String("MyAsyncTaskLoader Test Result"); } }
運行后發(fā)現(xiàn)真的能夠輸出了!看來問題是解決了。
最后一行為輸出的結(jié)果
問題是解決了,但是還是有一個疑問,這個 onStartLoading()是在哪里被調(diào)用的呢?看來還是得看看源碼。
從 getSupportLoaderManager().initLoader(0, null, this) 開始分析,發(fā)現(xiàn)最后是會調(diào)用到 onStartLoading()。
簡記如下,可自己對照著源碼查看:
LoaderManager的實現(xiàn)類為LoaderManagerImpl init()方法里面創(chuàng)建 LoaderInfo info info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback); 進入 createAndInstallLoader 方法 mCallbacks.onLoadFinished(loader, data); 進入 onLoadFinished 方法 createLoader(id, args, callback) 進入 createLoader 方法 installLoader(info); 進入 installLoader 方法 info.start(); 進入 start 方法 mLoader.startLoading(); 進入 startLoading 方法 onStartLoading();
以上就是Android 3.0中怎么引入Loader異步加載機制,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。