国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 3.0引入的異步加載機制Loader

2019-10-22 18:21:15
字體:
來源:轉載
供稿:網友

Loader是谷歌在Android 3.0引入的異步加載機制,能夠對數據異步加載并顯示到Activity或Fragment上,使用者不需要對數據的生命周期進行管理,而是交給Loader機制來管理。

使用Loader的優點

假如我們需要從網絡上獲取數據,通常的做法是使用子線程Thread+Handler或者是使用AsyncTask來處理。

Thread+Handler方法實現起來簡單直觀,不過會麻煩點,需要自己實現Handler子類,創建線程,還要管理Handler的生命周期。

AsyncTask實現起來會簡單些,無需自己管理線程和Handler。但是要管理AsyncTask的生命周期,要對Activity退出時的情況進行處理。否則可能會出現異?;騼却嫘孤?。

使用Loader無需關心線程和Handler的創建和銷毀,也無需自己管理數據整個的生命周期,Loader機制會自動幫我們處理好。我們唯一要處理的就是數據本身。

Loader使用的步驟:

創建FragmentActivity或Fragment 持有LoaderManager的實例實現Loader,用來加載數據源返回的數據實現LoaderManager.LoaderCallbacks接口實現數據的展示提供數據的數據源,如ContentProvider,服務器下發的數據等 幾個相關的類 LoaderManager

管理Loader實例,并使之和FragmentActiivty或Fragment關聯上

一個Activity或Fragment有一個唯一的LoaderManager實例

一個LoaderManager實例可以管理多個Loader實例

可以在FragmentActivity或Fragmeng中使用getSupportLoaderManager()獲取到LoaderManager實例

可以使用 initLoader() 或 restartLoader() 方法開始進行數據的加載

//0,為唯一的ID,可以為任意整數,為Loader的唯一標識//null,為Bundle類型,可以向Loader傳遞構造參數//LoaderCallbacks,LoaderManager對Loader各事件的調用,參考下面講到的 LoaderManager.LoaderCallbacksgetSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<D>());

LoaderManager.LoaderCallbacks

LoaderManager對Loader各種情況的回調接口,包含三個回調方法

onCreateLoader(int,Bundle)
在這里需要自己創建Loader對象,int 為Loader的唯一標識,Bundle為Loader的構造參數,可為空

...new LoaderManager.LoaderCallbacks<String>() {      @Override      public Loader<String> onCreateLoader(int id, Bundle args) {        return new MyLoader();      }      ...}

onLoadFinished(Loader<D>,D)
當LoaderManager加載完數據時回調此方法,在這里用UI展示數據給用戶。D為泛型,根據實際情況設置為所需的數據類型。和initLoader()LoaderCallbacks<D>參數中的的泛型為同一類型

new LoaderManager.LoaderCallbacks<String>() {      ...      @Override      public void onLoadFinished(Loader<String> loader, String data) {          show(data);      }      ...}

onLoaderReset(Loader<D>)
當之前創建的Loader實例被重置的時候會回調此方法,此時需要對相關的數據進行清除處理

new LoaderManager.LoaderCallbacks<String>() {      ...      @Override      public void onLoaderReset(Loader<String> loader) {          show(null);      }      ...}

 Loader

從數據源獲取數據,并對數據進行加載,為抽象類,需要自己實現子類

或使用官方已經實現的兩個子類

AsyncTaskLoader(繼承此類的時候會遇到一個坑,見下面的分析)
處理異步獲取數據 CursorLoader
處理ContentProvider返回的數據 實現AsyncTaskLoader遇到的一個坑

首先自定義一個 MyAsyncTaskLoader,繼承AsyncTaskLoader,會發現需要實現參數為Context的構造方法和實現 loadInBackground() 抽象方法

 

//繼承AsyncTaskLoader類,里面的泛型為返回的數據的類型,這里設為Stringpublic class MyAsyncTaskLoader extends AsyncTaskLoader<String>{  public MyAsyncTaskLoader(Context context) {    super(context);  }  @Override   public String loadInBackground() {    //模擬加載    try {      Thread.sleep(3000);    } catch (InterruptedException e) {      e.printStackTrace();    }    //返回獲取到的數據    return new String("MyAsyncTaskLoader Test Result");  }  }

創建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) {  }}

當運行的時候發現日志值打印了onCreate,call,onCreateLoader,而預期中的 MyAsyncTaskLoader Test Result 并沒有輸出,也就是說 onLoadFinished 并未被回調。調試發現 MyAsyncTaskLoader 中的 loadInBackground() 方法也未執行。

這個是怎么回事呢?

那么只好查看源碼了,這里所使用的都是 support-v4 的包。

查看 AsyncTaskLoader 源碼發現 loadInBackground() 方法的確為 abstract 類型,其被調用的地方是在一個叫做 LoadTask 的內部類中。

 

//可以把 ModernAsyncTask 看做 AsyncTaskfinal 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 實例化和被執行的地方在 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 這兩個地方就是執行 TaskLoader 的地方,并會調用到 doInBackground() 方法。

那么到這里我們可以猜測我們自定義的 MyAsyncLoader 的 loadInBackground() 未被執行,那么 onForceLoad() 也應該未被執行。

沿著這條線索查找看看這個 onForceLoad() 是在哪里被調用的。發現其是在AsyncLoader 的父類 Loader 中的 forceLoad() 中被調用

 

public class Loader{...  public void forceLoad() {    onForceLoad();  }...}

然后又看到注釋發現,此方法只能在 loader 開始的時候調用,還是找不到什么頭緒。


Android,Loader異步裝載,Loader機制,Loader,異步加載

突然想到好像 CursorLoader 沒有這個問題,那么看看它是不是有調用 forceLoad(),找了下,發現還果然有!是在 onStartLoading() 這個方法里,并且只有這里調用!

 

public class CursorLoader extends AsyncTaskLoader<Cursor> {  ...  @Override  protected void onStartLoading() {    if (mCursor != null) {      deliverResult(mCursor);    }    if (takeContentChanged() || mCursor == null) {      forceLoad();    }  }  ...}

那么我模仿下這個看看是不是真的能行,MyAsyncLoader 的代碼修改如下:

 

//繼承AsyncTaskLoader類,里面的泛型為返回的數據的類型,這里設為Stringpublic 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();    }    //返回獲取到的數據    return new String("MyAsyncTaskLoader Test Result");  }  }

運行后發現真的能夠輸出了!看來問題是解決了。


Android,Loader異步裝載,Loader機制,Loader,異步加載

最后一行為輸出的結果

問題是解決了,但是還是有一個疑問,這個 onStartLoading()是在哪里被調用的呢?看來還是得看看源碼。

從 getSupportLoaderManager().initLoader(0, null, this) 開始分析,發現最后是會調用到 onStartLoading()。

簡記如下,可自己對照著源碼查看:

LoaderManager的實現類為LoaderManagerImplinit()方法里面創建 LoaderInfo infoinfo = 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開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 根河市| 蓬莱市| 尉犁县| 长寿区| 张家界市| 乾安县| 乌兰县| 剑阁县| 河源市| 林州市| 六安市| 清水县| 连城县| 石城县| 射洪县| 瑞丽市| 甘泉县| 玉屏| 米林县| 海口市| 沈丘县| 百色市| 阳谷县| 蒙山县| 宁武县| 阿图什市| 溆浦县| 城市| 瑞安市| 长武县| 博白县| 永州市| 巴彦淖尔市| 保定市| 托克托县| 达拉特旗| 南城县| 英吉沙县| 通城县| 二连浩特市| 托克逊县|