欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 3.0引入的異步加載機(jī)制Loader

 更新時(shí)間:2017年12月06日 08:55:09   作者:星泉毅  
Loader裝載器從android3.0開(kāi)始引進(jìn)。它使得在activity或fragment中異步加載數(shù)據(jù)變得簡(jiǎn)單。下面我們就來(lái)詳細(xì)講解下

Loader是谷歌在Android 3.0引入的異步加載機(jī)制,能夠?qū)?shù)據(jù)異步加載并顯示到Activity或Fragment上,使用者不需要對(duì)數(shù)據(jù)的生命周期進(jìn)行管理,而是交給Loader機(jī)制來(lái)管理。

使用Loader的優(yōu)點(diǎn)

假如我們需要從網(wǎng)絡(luò)上獲取數(shù)據(jù),通常的做法是使用子線程Thread+Handler或者是使用AsyncTask來(lái)處理。

Thread+Handler方法實(shí)現(xiàn)起來(lái)簡(jiǎn)單直觀,不過(guò)會(huì)麻煩點(diǎn),需要自己實(shí)現(xiàn)Handler子類,創(chuàng)建線程,還要管理Handler的生命周期。

AsyncTask實(shí)現(xiàn)起來(lái)會(huì)簡(jiǎn)單些,無(wú)需自己管理線程和Handler。但是要管理AsyncTask的生命周期,要對(duì)Activity退出時(shí)的情況進(jìn)行處理。否則可能會(huì)出現(xiàn)異?;騼?nèi)存泄露。

使用Loader無(wú)需關(guān)心線程和Handler的創(chuàng)建和銷(xiāo)毀,也無(wú)需自己管理數(shù)據(jù)整個(gè)的生命周期,Loader機(jī)制會(huì)自動(dòng)幫我們處理好。我們唯一要處理的就是數(shù)據(jù)本身。

Loader使用的步驟:

創(chuàng)建FragmentActivity或Fragment 持有LoaderManager的實(shí)例實(shí)現(xiàn)Loader,用來(lái)加載數(shù)據(jù)源返回的數(shù)據(jù)實(shí)現(xiàn)LoaderManager.LoaderCallbacks接口實(shí)現(xiàn)數(shù)據(jù)的展示提供數(shù)據(jù)的數(shù)據(jù)源,如ContentProvider,服務(wù)器下發(fā)的數(shù)據(jù)等 幾個(gè)相關(guān)的類 LoaderManager

管理Loader實(shí)例,并使之和FragmentActiivty或Fragment關(guān)聯(lián)上

一個(gè)Activity或Fragment有一個(gè)唯一的LoaderManager實(shí)例

一個(gè)LoaderManager實(shí)例可以管理多個(gè)Loader實(shí)例

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

可以使用 initLoader() 或 restartLoader() 方法開(kāi)始進(jìn)行數(shù)據(jù)的加載

//0,為唯一的ID,可以為任意整數(shù),為L(zhǎng)oader的唯一標(biāo)識(shí)
//null,為Bundle類型,可以向Loader傳遞構(gòu)造參數(shù)
//LoaderCallbacks,LoaderManager對(duì)Loader各事件的調(diào)用,參考下面講到的 LoaderManager.LoaderCallbacks
getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<D>());

LoaderManager.LoaderCallbacks

LoaderManager對(duì)Loader各種情況的回調(diào)接口,包含三個(gè)回調(diào)方法

onCreateLoader(int,Bundle)
在這里需要自己創(chuàng)建Loader對(duì)象,int 為L(zhǎng)oader的唯一標(biāo)識(shí),Bundle為L(zhǎng)oader的構(gòu)造參數(shù),可為空

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

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

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

onLoaderReset(Loader<D>)
當(dāng)之前創(chuàng)建的Loader實(shí)例被重置的時(shí)候會(huì)回調(diào)此方法,此時(shí)需要對(duì)相關(guān)的數(shù)據(jù)進(jìn)行清除處理

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

 Loader

從數(shù)據(jù)源獲取數(shù)據(jù),并對(duì)數(shù)據(jù)進(jìn)行加載,為抽象類,需要自己實(shí)現(xiàn)子類

或使用官方已經(jīng)實(shí)現(xiàn)的兩個(gè)子類

AsyncTaskLoader(繼承此類的時(shí)候會(huì)遇到一個(gè)坑,見(jiàn)下面的分析)
處理異步獲取數(shù)據(jù) CursorLoader
處理ContentProvider返回的數(shù)據(jù) 實(shí)現(xiàn)AsyncTaskLoader遇到的一個(gè)坑

首先自定義一個(gè) MyAsyncTaskLoader,繼承AsyncTaskLoader,會(huì)發(fā)現(xiàn)需要實(shí)現(xiàn)參數(shù)為Context的構(gòu)造方法和實(shí)現(xiàn) loadInBackground() 抽象方法

//繼承AsyncTaskLoader類,里面的泛型為返回的數(shù)據(jù)的類型,這里設(shè)為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) {

  }
}

當(dāng)運(yùn)行的時(shí)候發(fā)現(xiàn)日志值打印了onCreate,call,onCreateLoader,而預(yù)期中的 MyAsyncTaskLoader Test Result 并沒(méi)有輸出,也就是說(shuō) onLoadFinished 并未被回調(diào)。調(diào)試發(fā)現(xiàn) MyAsyncTaskLoader 中的 loadInBackground() 方法也未執(zhí)行。

這個(gè)是怎么回事呢?

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

查看 AsyncTaskLoader 源碼發(fā)現(xiàn) loadInBackground() 方法的確為 abstract 類型,其被調(diào)用的地方是在一個(gè)叫做 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的一個(gè)全局變量。

public abstract class AsyncTaskLoader<D> extends Loader<D> {
....
volatile LoadTask mTask;
....
}

mTask 實(shí)例化和被執(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 這兩個(gè)地方就是執(zhí)行 TaskLoader 的地方,并會(huì)調(diào)用到 doInBackground() 方法。

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

沿著這條線索查找看看這個(gè) onForceLoad() 是在哪里被調(diào)用的。發(fā)現(xiàn)其是在AsyncLoader 的父類 Loader 中的 forceLoad() 中被調(diào)用

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

然后又看到注釋發(fā)現(xiàn),此方法只能在 loader 開(kāi)始的時(shí)候調(diào)用,還是找不到什么頭緒。


突然想到好像 CursorLoader 沒(méi)有這個(gè)問(wèn)題,那么看看它是不是有調(diào)用 forceLoad(),找了下,發(fā)現(xiàn)還果然有!是在 onStartLoading() 這個(gè)方法里,并且只有這里調(diào)用!

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

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

//繼承AsyncTaskLoader類,里面的泛型為返回的數(shù)據(jù)的類型,這里設(shè)為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");
  }  
}

運(yùn)行后發(fā)現(xiàn)真的能夠輸出了!看來(lái)問(wèn)題是解決了。


 

最后一行為輸出的結(jié)果

問(wèn)題是解決了,但是還是有一個(gè)疑問(wèn),這個(gè) onStartLoading()是在哪里被調(diào)用的呢?看來(lái)還是得看看源碼。

從 getSupportLoaderManager().initLoader(0, null, this) 開(kāi)始分析,發(fā)現(xiàn)最后是會(huì)調(diào)用到 onStartLoading()。

簡(jiǎn)記如下,可自己對(duì)照著源碼查看:

LoaderManager的實(shí)現(xiàn)類為L(zhǎng)oaderManagerImpl
init()方法里面創(chuàng)建 LoaderInfo info
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback); 進(jìn)入 createAndInstallLoader 方法
mCallbacks.onLoadFinished(loader, data); 進(jìn)入 onLoadFinished 方法
createLoader(id, args, callback) 進(jìn)入 createLoader 方法
installLoader(info); 進(jìn)入 installLoader 方法
info.start(); 進(jìn)入 start 方法
mLoader.startLoading(); 進(jìn)入 startLoading 方法
onStartLoading();

相關(guān)文章

最新評(píng)論