Android 非同步載入神器Loader全解析

希爾瓦娜斯女神發表於2015-10-08

在之前呢,我們經常會有這種需求,比如在某個activity,或者某個fragment裡面,我們需要查詢某個資料來源,並且顯示出來,當資料來源自己更新的時候,介面也要及時響應。

當然咯,查詢資料這個過程可能很短,但是也可能很漫長,為了避免anr,我們都是開啟一個子執行緒去查詢,然後通過handler來更新我們的ui介面。但是,考慮到activity和

fragment 複雜的生命週期,上述的方法 使用起來會很不方便,畢竟你要考慮到儲存現場 還原現場 等等複雜的工作來保證你的app無懈可擊。所以後來呢谷歌就幫我們推出了一個

新的東西---Loader。他可以幫我們完成上述所有功能!實在是很強大。

如果你有閱讀英文技術文件的習慣 那麼谷歌官方的文件 也許比我所說的更加完美。具體可以參考如下:

http://developer.android.com/intl/zh-cn/reference/android/app/LoaderManager.html

http://developer.android.com/intl/zh-cn/reference/android/content/AsyncTaskLoader.html

http://developer.android.com/intl/zh-cn/guide/components/loaders.html

我所述的內容也是主要基於上述三篇文件。

首先呢,我們來看第一個例子,這個例子也是官方的推薦了,我給簡化了一下,主要是監聽手機裡 聯絡人這個資料來源。當資料來源改變的時候 自動update 我們的ui。

  1 package com.example.administrator.modifytestview;
  2 
  3 import android.app.Activity;
  4 import android.app.FragmentManager;
  5 import android.app.ListFragment;
  6 import android.app.LoaderManager;
  7 import android.content.CursorLoader;
  8 import android.content.Loader;
  9 import android.database.Cursor;
 10 import android.net.Uri;
 11 import android.os.Bundle;
 12 import android.provider.ContactsContract.Contacts;
 13 import android.util.Log;
 14 import android.view.View;
 15 import android.widget.ListView;
 16 import android.widget.SimpleCursorAdapter;
 17 
 18 public class MainActivity extends Activity {
 19 
 20 
 21     @Override
 22     protected void onCreate(Bundle savedInstanceState) {
 23         super.onCreate(savedInstanceState);
 24         setContentView(R.layout.activity_main);
 25         FragmentManager fm = getFragmentManager();
 26         CursorLoaderListFragment list = new CursorLoaderListFragment();
 27         fm.beginTransaction().replace(R.id.root, list).commit();
 28 
 29     }
 30 
 31 
 32 
 33     public static class CursorLoaderListFragment extends ListFragment
 34             implements LoaderManager.LoaderCallbacks<Cursor> {
 35 
 36         // This is the Adapter being used to display the list's data.
 37         SimpleCursorAdapter mAdapter;
 38 
 39         // If non-null, this is the current filter the user has provided.
 40         String mCurFilter;
 41 
 42         @Override
 43         public void onActivityCreated(Bundle savedInstanceState) {
 44 
 45 
 46             mAdapter = new SimpleCursorAdapter(getActivity(),
 47                     android.R.layout.simple_list_item_2, null,
 48                     new String[]{Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS},
 49                     new int[]{android.R.id.text1, android.R.id.text2}, 0);
 50             setListAdapter(mAdapter);
 51 
 52             //這個地方初始化了我們的loader
 53             getLoaderManager().initLoader(0, null, this);
 54 
 55             super.onActivityCreated(savedInstanceState);
 56         }
 57 
 58 
 59         @Override
 60         public void onListItemClick(ListView l, View v, int position, long id) {
 61             // Insert desired behavior here.
 62             Log.i("FragmentComplexList", "Item clicked: " + id);
 63         }
 64 
 65         // These are the Contacts rows that we will retrieve.
 66         static final String[] CONTACTS_SUMMARY_PROJECTION = new String[]{
 67                 Contacts._ID,
 68                 Contacts.DISPLAY_NAME,
 69                 Contacts.CONTACT_STATUS,
 70                 Contacts.CONTACT_PRESENCE,
 71                 Contacts.PHOTO_ID,
 72                 Contacts.LOOKUP_KEY,
 73         };
 74 
 75         //只會呼叫一次
 76         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
 77             // This is called when a new Loader needs to be created.  This
 78             // sample only has one Loader, so we don't care about the ID.
 79             // First, pick the base URI to use depending on whether we are
 80             // currently filtering.
 81             Uri baseUri;
 82             if (mCurFilter != null) {
 83                 baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
 84                         Uri.encode(mCurFilter));
 85             } else {
 86                 baseUri = Contacts.CONTENT_URI;
 87             }
 88 
 89             // Now create and return a CursorLoader that will take care of
 90             // creating a Cursor for the data being displayed.
 91             String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
 92                     + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
 93                     + Contacts.DISPLAY_NAME + " != '' ))";
 94             //返回的是對這個資料來源的監控
 95             return new CursorLoader(getActivity(), baseUri,
 96                     CONTACTS_SUMMARY_PROJECTION, select, null,
 97                     Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
 98         }
 99 
100         //每次資料來源都有更新的時候,就會回撥這個方法,然後update 我們的ui了。
101         public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
103 
104             // Swap the new cursor in.  (The framework will take care of closing the
105             // old cursor once we return.)
106             mAdapter.swapCursor(data);
107 
108             // The list should now be shown.
109             if (isResumed()) {
110                 setListShown(true);
111             } else {
112                 setListShownNoAnimation(true);
113             }
114         }
115 
116         public void onLoaderReset(Loader<Cursor> loader) {
117             // This is called when the last Cursor provided to onLoadFinished()
118             // above is about to be closed.  We need to make sure we are no
119             // longer using it.
120             mAdapter.swapCursor(null);
121         }
122     }
123 
124 }

可以仔細的觀察一下這個程式碼,我們能發現 使用loader所需要的一些步驟:

1.需要一個activity或者是fragment,當然在上述的例子裡 我們使用的是fragment。

2.一個LoaderManger的例項,注意看53行,我們get了一個loadermanager。這個地方就是獲取例項了。

3.需要一個CursorLoader,並且從contentProvider獲取資料來源,90-97行 就是這麼做的。

4.需要實現一個LoaderCallBack的這個介面,然後在幾個回撥方法裡 寫上我們自己業務的邏輯 即可。你看34行就是繼承的介面。

還有3個回撥方法在那,我們都在裡面實現了自己的邏輯。

 

到這,其實一看,思路還是很清晰的。那到這裡 有人肯定要說了。你這個沒用啊,要實現contentprovider,我們的app不需要做

資料共享的,能否直接運算元據庫呢?答案是可以的。在這裡我們也可以構造出一個場景。假設有一張學生表。我們點選add

按鈕,就自動往這個表裡面增加一個資料,然後下面有個listview 會自動捕捉到 這個資料來源的變化,然後自動更新列表。

我們可以知道 上面那個demo裡面 CursorLoader的定義是這樣的

1 public class CursorLoader extends AsyncTaskLoader<Cursor> {

我們現在要實現一個不用contentProvider的Loader 也是基於AsyncTaskLoader來的。

先給出一個抽象類:

 1 package com.example.administrator.activeandroidtest3;
 2 
 3 
 4 import android.content.AsyncTaskLoader;
 5 import android.content.Context;
 6 import android.database.Cursor;
 7 
 8 
 9 public abstract class SimpleCursorLoader extends AsyncTaskLoader<Cursor> {
10     private Cursor mCursor;
11 
12     public SimpleCursorLoader(Context context) {
13         super(context);
14     }
15 
16     /* 在子執行緒裡運作 */
17     @Override
18     public abstract Cursor loadInBackground();
19 
20     /* 在ui 執行緒裡運作 */
21     @Override
22     public void deliverResult(Cursor cursor) {
23         if (isReset()) {
24             // An async query came in while the loader is stopped
25             if (cursor != null) {
26                 cursor.close();
27             }
28             return;
29         }
30         Cursor oldCursor = mCursor;
31         mCursor = cursor;
32 
33         if (isStarted()) {
34             super.deliverResult(cursor);
35         }
36 
37         if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
38             oldCursor.close();
39         }
40     }
41 
42     @Override
43     protected void onStartLoading() {
44         if (mCursor != null) {
45             deliverResult(mCursor);
46         }
47         if (takeContentChanged() || mCursor == null) {
48             forceLoad();
49         }
50     }
51 
52     @Override
53     protected void onStopLoading() {
54         cancelLoad();
55     }
56 
57     @Override
58     public void onCanceled(Cursor cursor) {
59         if (cursor != null && !cursor.isClosed()) {
60             cursor.close();
61         }
62     }
63 
64     @Override
65     protected void onReset() {
66         super.onReset();
67 
68         onStopLoading();
69 
70         if (mCursor != null && !mCursor.isClosed()) {
71             mCursor.close();
72         }
73         mCursor = null;
74     }
75 }

然後我們再接著定義我們最終的 不需要provider的loader實現類(注意你如果想寫的比較完美的話 cursor記得用抽象類的,抽象類的那個就不要寫成private的了,我這裡為了圖簡單 直接用自己構造的)。

 1 package com.example.administrator.activeandroidtest3;
 2 
 3 import android.content.Context;
 4 import android.database.Cursor;
 5 import android.database.sqlite.SQLiteDatabase;
 6 
 7 /**
 8  * Created by Administrator on 2015/10/7.
 9  */
10 public class SpecialLoader extends SimpleCursorLoader {
11 
12     ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
13     private Context context;
14 
15     public SpecialLoader(Context context) {
16         super(context);
17         this.context = context;
18 
19     }
20 
21     @Override
22     public Cursor loadInBackground() {
23         DatabaseHelper dh = new DatabaseHelper(context, "Test.db");
24         SQLiteDatabase database = dh.getReadableDatabase();
25         String table = "Student";
26         String[] columns = new String[]{"Name", "No"};
27         //這個地方因為我用的是activeandroid 的orm 框架,所以預設的自增長主鍵是Id,但是SimpleCursorAdapter
28         //需要的是_id 否則會報錯,所以這裡要重新命名一下
29         Cursor cursor = database.rawQuery("SELECT Id AS _id,Name,No FROM Student", null);
30         if (database != null) {
31             if (cursor != null) {
32                 //註冊一下這個觀察者
33                 cursor.registerContentObserver(mObserver);
34                 //這邊也要注意 一定要監聽這個uri的變化。但是如果你這個uri沒有對應的provider的話
35                 //記得在你運算元據庫的時候 通知一下這個uri
36                 cursor.setNotificationUri(context.getContentResolver(), MainActivity.uri);
37             }
38 
39         }
40         return cursor;
41     }
42 }

然後我們在簡單看下activity 主類裡的程式碼:

  1 package com.example.administrator.activeandroidtest3;
  2 
  3 import android.app.Activity;
  4 import android.app.LoaderManager;
  5 import android.content.Loader;
  6 import android.database.Cursor;
  7 import android.net.Uri;
  8 import android.os.Bundle;
  9 import android.util.Log;
 10 import android.view.Menu;
 11 import android.view.MenuItem;
 12 import android.view.View;
 13 import android.widget.ListView;
 14 import android.widget.SimpleCursorAdapter;
 15 import android.widget.TextView;
 16 
 17 import com.activeandroid.query.Select;
 18 
 19 import java.util.List;
 20 import java.util.Random;
 21 
 22 public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks {
 23 
 24     public static final Uri uri = Uri.parse("content://com.example.student");
 25     private TextView addTv;
 26     private ListView lv;
 27     private SimpleCursorAdapter adapter;
 28 
 29     @Override
 30     protected void onCreate(Bundle savedInstanceState) {
 31         super.onCreate(savedInstanceState);
 32         setContentView(R.layout.activity_main);
 33         addTv = (TextView) this.findViewById(R.id.add);
 34         addTv.setOnClickListener(new View.OnClickListener() {
 35             @Override
 36             public void onClick(View v) {
 37                 Student student = new Student();
 38                 student.name = getRandomString(5);
 39                 student.no = (int) (Math.random() * 1000) + "";
 40                 student.sex = (int) (Math.random() * 1);
 41                 student.save();
 42                 //操作完資料庫要notify 不然loader那邊收不到哦
 43                 getContentResolver().notifyChange(uri, null);
 44 
 45             }
 46         });
 47         lv = (ListView) this.findViewById(R.id.lv);
 48         adapter = new SimpleCursorAdapter(MainActivity.this,
 49                 android.R.layout.simple_list_item_2, null,
 50                 new String[]{"Name", "No"},
 51                 new int[]{android.R.id.text1, android.R.id.text2}, 0);
 52         lv.setAdapter(adapter);
 53         getLoaderManager().initLoader(0, null, this);
 54     }
 55 
 56     @Override
 57     public boolean onCreateOptionsMenu(Menu menu) {
 58         // Inflate the menu; this adds items to the action bar if it is present.
 59         getMenuInflater().inflate(R.menu.menu_main, menu);
 60         return true;
 61     }
 62 
 63     @Override
 64     public boolean onOptionsItemSelected(MenuItem item) {
 65         // Handle action bar item clicks here. The action bar will
 66         // automatically handle clicks on the Home/Up button, so long
 67         // as you specify a parent activity in AndroidManifest.xml.
 68         int id = item.getItemId();
 69 
 70         //noinspection SimplifiableIfStatement
 71         if (id == R.id.action_settings) {
 72             return true;
 73         }
 74 
 75         return super.onOptionsItemSelected(item);
 76     }
 77 
 78 
 79     public static String getRandomString(int length) { //length表示生成字串的長度
 80         String base = "abcdefghijklmnopqrstuvwxyz0123456789";
 81         Random random = new Random();
 82         StringBuffer sb = new StringBuffer();
 83         for (int i = 0; i < length; i++) {
 84             int number = random.nextInt(base.length());
 85             sb.append(base.charAt(number));
 86         }
 87         return sb.toString();
 88     }
 89 
 90 
 91     @Override
 92     public Loader onCreateLoader(int id, Bundle args) {
 93         SpecialLoader loader = new SpecialLoader(MainActivity.this);
 94         return loader;
 95     }
 96 
 97     @Override
 98     public void onLoadFinished(Loader loader, Object data) {
 99         adapter.swapCursor((Cursor) data);
100     }
101 
102     @Override
103     public void onLoaderReset(Loader loader) {
104 
105     }
106 }

最後我們看下執行的效果:

 

 

 

 好,那到這裡 又有人要說了,你這個說來說去 還不是隻能支援provider或者db型別的資料來源嗎?好 接著往下,

我們給出另外一個例子,不過這個例子是谷歌官方的例子,我就取其中重要的部分給予註釋講解。

http://developer.android.com/intl/zh-cn/reference/android/content/AsyncTaskLoader.html

首先說一下 這個例子是幹嘛的,他主要是監聽手機裡app list的變化,比如你刪除了一個應用

安裝了一個應用,馬上就能捕捉到你的手機裡app list的變化 並顯示在介面,大家都知道 監聽app list

是通過監聽系統廣播來完成的。 我就主要講一下 這個官方demo裡 是如何在監聽到系統廣播以後和loader結合起來

然後自動回撥方法的。

 1 /**
 2  * Helper class to look for interesting changes to the installed apps
 3  * so that the loader can be updated.
 4  */
 5 public static class PackageIntentReceiver extends BroadcastReceiver {
 6     final AppListLoader mLoader;
 7 
 8     //這個建構函式是很重要的 他接收的 就是自定義的loader
 9     public PackageIntentReceiver(AppListLoader loader) {
10         mLoader = loader;
11         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
12         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
13         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
14         filter.addDataScheme("package");
15         mLoader.getContext().registerReceiver(this, filter);
16         // Register for events related to sdcard installation.
17         IntentFilter sdFilter = new IntentFilter();
18         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
19         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
20         //在這個地方 直接用loader來註冊這個廣播接收器
21         mLoader.getContext().registerReceiver(this, sdFilter);
22     }
23 
24     //在收到廣播以後 什麼事情都沒有做,而是呼叫了loader的onContentChanged方法
25     @Override public void onReceive(Context context, Intent intent) {
26         // Tell the loader about the change.
27         mLoader.onContentChanged();
28     }
29 }

你看這裡的25-26行 呼叫了 loader的onContentChanged方法。繼續看下面的loader

  1 /**
  2  * A custom Loader that loads all of the installed applications.
  3  */
  4 public static class AppListLoader extends AsyncTaskLoader<List<AppEntry>> {
  5     final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
  6     final PackageManager mPm;
  7 
  8     List<AppEntry> mApps;
  9     PackageIntentReceiver mPackageObserver;
 10 
 11     public AppListLoader(Context context) {
 12         super(context);
 13 
 14         // Retrieve the package manager for later use; note we don't
 15         // use 'context' directly but instead the save global application
 16         // context returned by getContext().
 17         mPm = getContext().getPackageManager();
 18     }
 19 
 20     //實際上最重要的就是這個方法了,每當這個回撥方法被呼叫的時候 就去取applist 然後將結果返回到
 21     //onLoadFinished 這個回撥方法裡面!
 22     @Override public List<AppEntry> loadInBackground() {
 23         // Retrieve all known applications.
 24         List<ApplicationInfo> apps = mPm.getInstalledApplications(
 25                 PackageManager.GET_UNINSTALLED_PACKAGES |
 26                 PackageManager.GET_DISABLED_COMPONENTS);
 27         if (apps == null) {
 28             apps = new ArrayList<ApplicationInfo>();
 29         }
 30 
 31         final Context context = getContext();
 32 
 33         // Create corresponding array of entries and load their labels.
 34         List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
 35         for (int i=0; i<apps.size(); i++) {
 36             AppEntry entry = new AppEntry(this, apps.get(i));
 37             entry.loadLabel(context);
 38             entries.add(entry);
 39         }
 40 
 41         // Sort the list.
 42         Collections.sort(entries, ALPHA_COMPARATOR);
 43 
 44         // Done!
 45         return entries;
 46     }
 47 
 48     /**
 49      * Called when there is new data to deliver to the client.  The
 50      * super class will take care of delivering it; the implementation
 51      * here just adds a little more logic.
 52      */
 53     @Override public void deliverResult(List<AppEntry> apps) {
 54         if (isReset()) {
 55             // An async query came in while the loader is stopped.  We
 56             // don't need the result.
 57             if (apps != null) {
 58                 onReleaseResources(apps);
 59             }
 60         }
 61         List<AppEntry> oldApps = mApps;
 62         mApps = apps;
 63 
 64         if (isStarted()) {
 65             // If the Loader is currently started, we can immediately
 66             // deliver its results.
 67             super.deliverResult(apps);
 68         }
 69 
 70         // At this point we can release the resources associated with
 71         // 'oldApps' if needed; now that the new result is delivered we
 72         // know that it is no longer in use.
 73         if (oldApps != null) {
 74             onReleaseResources(oldApps);
 75         }
 76     }
 77 
 78     /**
 79      * Handles a request to start the Loader.
 80      */
 81     @Override protected void onStartLoading() {
 82         if (mApps != null) {
 83             // If we currently have a result available, deliver it
 84             // immediately.
 85             deliverResult(mApps);
 86         }
 87 
 88         // Start watching for changes in the app data.
 89         if (mPackageObserver == null) {
 90             mPackageObserver = new PackageIntentReceiver(this);
 91         }
 92 
 93         // Has something interesting in the configuration changed since we
 94         // last built the app list?
 95         boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
 96 
 97         if (takeContentChanged() || mApps == null || configChange) {
 98             // If the data has changed since the last time it was loaded
 99             // or is not currently available, start a load.
100             forceLoad();
101         }
102     }
103 
104     /**
105      * Handles a request to stop the Loader.
106      */
107     @Override protected void onStopLoading() {
108         // Attempt to cancel the current load task if possible.
109         cancelLoad();
110     }
111 
112     /**
113      * Handles a request to cancel a load.
114      */
115     @Override public void onCanceled(List<AppEntry> apps) {
116         super.onCanceled(apps);
117 
118         // At this point we can release the resources associated with 'apps'
119         // if needed.
120         onReleaseResources(apps);
121     }
122 
123     /**
124      * Handles a request to completely reset the Loader.
125      */
126     @Override protected void onReset() {
127         super.onReset();
128 
129         // Ensure the loader is stopped
130         onStopLoading();
131 
132         // At this point we can release the resources associated with 'apps'
133         // if needed.
134         if (mApps != null) {
135             onReleaseResources(mApps);
136             mApps = null;
137         }
138 
139         // Stop monitoring for changes.
140         if (mPackageObserver != null) {
141             getContext().unregisterReceiver(mPackageObserver);
142             mPackageObserver = null;
143         }
144     }
145 
146     /**
147      * Helper function to take care of releasing resources associated
148      * with an actively loaded data set.
149      */
150     protected void onReleaseResources(List<AppEntry> apps) {
151         // For a simple List<> there is nothing to do.  For something
152         // like a Cursor, we would close it here.
153     }
154 }

好,到這裡流程就很明顯了,在loader裡 註冊廣播接收器,當廣播接收器 收到廣播以後 就呼叫loader的onContentChanged方法,

這個方法一呼叫 AppListLoader裡的loadInBackGround就會被呼叫,然後當loadInBackGround執行完畢以後 就會把結果

傳遞給onLoadFinished方法了。 搞清楚這個流程 你就真正學會了使用loader這個大殺器了。當然了,我們並不滿足於此,loader

還有一個特性就是可以自動管理他自己的生命週期 等等。我們現在就去看看他的原始碼,是如何完成這一點的。 並且上述幾個方法

之間是如何相互呼叫的,順序如何。

 

首先 我們要搞清楚幾個類之間的關係:

1 public class CursorLoader extends AsyncTaskLoader<Cursor> {
2 
3 
4 public abstract class AsyncTaskLoader<D> extends Loader<D> {
5 
6 public class Loader<D> {

這樣就很清晰。首先由一個實體類作為最基礎的基類,Loader 注意他可以接受一個泛型為引數,然後有一個抽象類:AsyncTaskLoader 也是泛型作為引數。

最後實際呼叫運作的類就是CursorLoader類了,這裡就可以看出來 傳進去的泛型是一個Cursor。你在自定義Loader的時候,這個泛型引數 當然是可以自己決定的,

比如官方demo裡 傳的就是一個List。

搞清楚 他們三者之間的關係,剩下的就簡單多了。可以逐步分析了。

在前面的3個demo裡,我們分別演示了在fragment和activity裡 呼叫loader的方法。 那我們就看看 這兩者之間有什麼異同點。先來看fragment。

fragment裡 我們是這樣呼叫的:

1  //這個地方初始化了我們的loader
2             getLoaderManager().initLoader(0, null, this);

直接get了一個manager 然後init他。我們進去看fragment的原始碼:

 1 //這邊就能看出來一個fragment只能有一個loadermanager了。
 2 public LoaderManager getLoaderManager() {
 3 
 4         if (mLoaderManager != null) {
 5             return mLoaderManager;
 6         }
 7         //mHost很好理解 就是fragment的宿主,也就是跟fragment 相關聯的activity。
 8         if (mHost == null) {
 9             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
10         }
11         mCheckedForLoaderManager = true;
12         mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, true);
13         return mLoaderManager;
14     }

既然 我們知道 fragment的getLoaderManager也是通過activity的getLoader去呼叫的,那我們就去activity裡的原始碼看看 :

 1   //在activty中最終實際上呼叫的就是他了 是這個方法
 2   LoaderManagerImpl getLoaderManagerImpl() {
 3         if (mLoaderManager != null) {
 4             return mLoaderManager;
 5         }
 6         mCheckedForLoaderManager = true;
 7         mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
 8         return mLoaderManager;
 9     }
10 
11 //這個地方就能看到 主要的第一個引數 who,你到這就能發現 如果是activity自己呼叫的話,傳進去的who的值就是root
12 //也就是說一個actvity 只能有一個loadermanger 但是我們可以發現在fragment裡 傳進去的值是下面這個:
13 // Internal unique name for this fragment;
14 //String mWho;
15 //也就是說每一個fragment的mWho的值都是唯一的,而在activty中,是維護了一個map,一個key 對應一個loadermanager
16 //key就是fragment的那個唯一的標示,或者是activity自己,activity自己的標示就是(root)了
17     LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
18         if (mAllLoaderManagers == null) {
19             mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
20         }
21         LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
22         if (lm == null) {
23             if (create) {
24                 lm = new LoaderManagerImpl(who, this, started);
25                 mAllLoaderManagers.put(who, lm);
26             }
27         } else {
28             lm.updateHostController(this);
29         }
30         return lm;
31     }

好 一直到這裡 ,我們就可以下一個結論了,真正的loadermanager都是儲存在activity中的,包括fragment的loadermanager也是,通過一個map來保證 get的時候

取的manager是自己對應的,並且全域性唯一。繼續往下看:

 1 public abstract class LoaderManager {
 2     /**
 3      * Callback interface for a client to interact with the manager.
 4      */
 5     public interface LoaderCallbacks<D> {
 6         /**
 7          * Instantiate and return a new Loader for the given ID.
 8          *
 9          * @param id The ID whose loader is to be created.
10          * @param args Any arguments supplied by the caller.
11          * @return Return a new Loader instance that is ready to start loading.
12          */
13         public Loader<D> onCreateLoader(int id, Bundle args);
14 
15         /**
16          * Called when a previously created loader has finished its load.  Note
17          * that normally an application is <em>not</em> allowed to commit fragment
18          * transactions while in this call, since it can happen after an
19          * activity's state is saved.  See {@link FragmentManager#beginTransaction()
20          * FragmentManager.openTransaction()} for further discussion on this.
21          * 
22          * <p>This function is guaranteed to be called prior to the release of
23          * the last data that was supplied for this Loader.  At this point
24          * you should remove all use of the old data (since it will be released
25          * soon), but should not do your own release of the data since its Loader
26          * owns it and will take care of that.  The Loader will take care of
27          * management of its data so you don't have to.  In particular:
28          *
29          * <ul>
30          * <li> <p>The Loader will monitor for changes to the data, and report
31          * them to you through new calls here.  You should not monitor the
32          * data yourself.  For example, if the data is a {@link android.database.Cursor}
33          * and you place it in a {@link android.widget.CursorAdapter}, use
34          * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context,
35          * android.database.Cursor, int)} constructor <em>without</em> passing
36          * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY}
37          * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER}
38          * (that is, use 0 for the flags argument).  This prevents the CursorAdapter
39          * from doing its own observing of the Cursor, which is not needed since
40          * when a change happens you will get a new Cursor throw another call
41          * here.
42          * <li> The Loader will release the data once it knows the application
43          * is no longer using it.  For example, if the data is
44          * a {@link android.database.Cursor} from a {@link android.content.CursorLoader},
45          * you should not call close() on it yourself.  If the Cursor is being placed in a
46          * {@link android.widget.CursorAdapter}, you should use the
47          * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)}
48          * method so that the old Cursor is not closed.
49          * </ul>
50          *
51          * @param loader The Loader that has finished.
52          * @param data The data generated by the Loader.
53          */
54         public void onLoadFinished(Loader<D> loader, D data);
55 
56         /**
57          * Called when a previously created loader is being reset, and thus
58          * making its data unavailable.  The application should at this point
59          * remove any references it has to the Loader's data.
60          *
61          * @param loader The Loader that is being reset.
62          */
63         public void onLoaderReset(Loader<D> loader);
64     }

一看就知道 loadermanger 其實是一個抽象類。就是定義了一些 我們需要的介面而已,這些介面方法的含義和用法 在那3個demo裡 相信大家都有了解,不多說。

我們去看看這個抽象類的實現類,為什麼要看他,因為你在get到這個maganger以後 馬上就去呼叫了他的init方法 我們就看看這部分的邏輯是怎麼樣的:

 1 public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
 2         if (mCreatingLoader) {
 3             throw new IllegalStateException("Called while creating a loader");
 4         }
 5 
 6         //這個就是先看看是否有活動的loader 有的話就取出來 沒有的話 就建立一個
 7         LoaderInfo info = mLoaders.get(id);
 8         
 9         if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
10 
11         if (info == null) {
12             // Loader doesn't already exist; create.
13             info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
14             if (DEBUG) Log.v(TAG, "  Created new loader " + info);
15         } else {
16             if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
17             info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
18         }
19         
20         if (info.mHaveData && mStarted) {
21             // If the loader has already generated its data, report it now.
22             info.callOnLoadFinished(info.mLoader, info.mData);
23         }
24         
25         return (Loader<D>)info.mLoader;
26     }
27 
28     //這個就是現在存活的loader
29     final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);
30 
31     //這個是已經執行結束的loader
32     final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);
33 
34     //其實這個建立loader的過程特別簡單,我們主要看第三個引數,callback 這個引數
35     //一想就明白,在前面3個demo裡我們是直接在fragemet和activity裡實現的callback
36     //所以傳進去的就是this,也就是說 回撥就是在這個函式裡 真正的和loader 發生了關聯了
37     private LoaderInfo createAndInstallLoader(int id, Bundle args,
38             LoaderManager.LoaderCallbacks<Object> callback) {
39         try {
40             mCreatingLoader = true;
41             LoaderInfo info = createLoader(id, args, callback);
42             installLoader(info);
43             return info;
44         } finally {
45             mCreatingLoader = false;
46         }
47     }

你看 一直到這裡,我們就明白了 callback是怎麼和loadermageer本身發生關聯的。 我們繼續往下看。這次我們要搞明白

當資料來源發生變化的時候 是怎麼一步步回撥我們子類loader的方法的。

我們先看Loader這個基類的主要方法:

 1  
 2 
 3 //這個是一個觀察者 當發生變化的時候 他呼叫了onContentChanged方法
 4  public final class ForceLoadContentObserver extends ContentObserver {
 5         public ForceLoadContentObserver() {
 6             super(new Handler());
 7         }
 8 
 9         @Override
10         public boolean deliverSelfNotifications() {
11             return true;
12         }
13 
14         @Override
15         public void onChange(boolean selfChange) {
16             onContentChanged();
17         }
18     }
19 
20 //下面這2個方法一看就明白 最終當資料來源發生變化的時候 會通知這個觀察者,然後這個觀察者會最終呼叫
21 //onForceLoad這個方法 而onForceLoad是交給子類去實現的 也就是AsyncTaskLoader的onForceLoad方法了
22 public void onContentChanged() {
23         if (mStarted) {
24             forceLoad();
25         } else {
26             // This loader has been stopped, so we don't want to load
27             // new data right now...  but keep track of it changing to
28             // refresh later if we start again.
29             mContentChanged = true;
30         }
31     }
32 
33  public void forceLoad() {
34         onForceLoad();
35     }
36 
37     /**
38      * Subclasses must implement this to take care of requests to {@link #forceLoad()}.
39      * This will always be called from the process's main thread.
40      */
41     protected void onForceLoad() {
42     }

然後看看AsyncTaskLoader的幾個主要方法:

 1 //這邊一目瞭然 asynacTaskLoader 裡面 正好是有一個AsyncTask物件的!實現了runnabele介面
 2 //注意著引數d 這個d是幹嘛的,這個d就是用來傳遞引數的一個泛型,可以是系統實現的loader裡的cursor
 3 //也可以是我們自己實現的loader裡的list型別
 4 final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
 5         private final CountDownLatch mDone = new CountDownLatch(1);
 6 
 7         // Set to true to indicate that the task has been posted to a handler for
 8         // execution at a later time.  Used to throttle updates.
 9         boolean waiting;
10 
11         /* Runs on a worker thread */
12         @Override
13         protected D doInBackground(Void... params) {
14             if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
15             try {
16                 //這個地方就很明顯了,他呼叫了自己的onLoadInBackGround方法
17                 D data = AsyncTaskLoader.this.onLoadInBackground();
18                 if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
19                 return data;
20             } catch (OperationCanceledException ex) {
21                 if (!isCancelled()) {
22                     // onLoadInBackground threw a canceled exception spuriously.
23                     // This is problematic because it means that the LoaderManager did not
24                     // cancel the Loader itself and still expects to receive a result.
25                     // Additionally, the Loader's own state will not have been updated to
26                     // reflect the fact that the task was being canceled.
27                     // So we treat this case as an unhandled exception.
28                     throw ex;
29                 }
30                 if (DEBUG) Log.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
31                 return null;
32             }
33         }
34         //後面還有很多程式碼 略過
35 }
36 
37 //你看這裡下面的2個函式 一看就明白了 最終task裡呼叫的是這個抽象方法,那這個抽象方法
38 //就是留給我們子類自己去實現的,我們在自定義loader的時候最重要的就是重寫這個方法。
39  protected D onLoadInBackground() {
40         return loadInBackground();
41     }
42 
43  public abstract D loadInBackground();
44 
45 //你看這個地方 就是當資料來源發生變化的時候 就會呼叫這個方法了,啟動了我們的laodtask 
46 //也是最終呼叫子類 也就是CursorLoader這樣的子類的loadInBackground方法了
47 @Override
48     protected void onForceLoad() {
49         super.onForceLoad();
50         cancelLoad();
51         mTask = new LoadTask();
52         if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
53         executePendingTask();
54     }

相信到這裡 大家一定能搞明白資料來源變化的時候 是怎麼一步步呼叫我們的loader裡的回撥方法的,那有人肯定要繼續問

當你這個方法呼叫完畢的時候 是怎麼通知最後updateUI呢,也就是當你background方法結束以後是怎麼呼叫的

onLoadFinished方法的呢?

我們繼續看AsyncTaskLoader這個類

 1  
 2  //在那個asynctask裡面 走完是肯定要走這個方法的 相信大家都能理解。
 3         @Override
 4         protected void onPostExecute(D data) {
 5             if (DEBUG) Log.v(TAG, this + " onPostExecute");
 6             try {
 7                 AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
 8             } finally {
 9                 mDone.countDown();
10             }
11         }
12 //實際上走的就是這個方法。看26行-
13         void dispatchOnLoadComplete(LoadTask task, D data) {
14         if (mTask != task) {
15             if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel");
16             dispatchOnCancelled(task, data);
17         } else {
18             if (isAbandoned()) {
19                 // This cursor has been abandoned; just cancel the new data.
20                 onCanceled(data);
21             } else {
22                 commitContentChanged();
23                 mLastLoadCompleteTime = SystemClock.uptimeMillis();
24                 mTask = null;
25                 if (DEBUG) Log.v(TAG, "Delivering result");
26                 deliverResult(data);
27             }
28         }
29     }
30 
31 //這邊一下就看出來是呼叫的mListtenr的回撥方法
32      public void deliverResult(D data) {
33         if (mListener != null) {
34             mListener.onLoadComplete(this, data);
35         }
36     }

實際上這個Listener就是在Loader這個基類裡:

 1     OnLoadCompleteListener<D> mListener;
 2 
 3 public interface OnLoadCompleteListener<D> {
 4         /**
 5          * Called on the thread that created the Loader when the load is complete.
 6          *
 7          * @param loader the loader that completed the load
 8          * @param data the result of the load
 9          */
10         public void onLoadComplete(Loader<D> loader, D data);
11     }
12 
13 //並且通過這個註冊
14  public void registerListener(int id, OnLoadCompleteListener<D> listener) {
15         if (mListener != null) {
16             throw new IllegalStateException("There is already a listener registered");
17         }
18         mListener = listener;
19         mId = id;
20     }

那就好了 我們就是要看一下 是在哪個地方呼叫的registerlistener這個方法 註冊他的

  1   
  2 //回到initLoader的這個方法 注意這個方法是在LoaderManger裡面
  3   public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
  4         if (mCreatingLoader) {
  5             throw new IllegalStateException("Called while creating a loader");
  6         }
  7         
  8         LoaderInfo info = mLoaders.get(id);
  9         
 10         if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
 11 
 12         if (info == null) {
 13 //下面的程式碼跳轉到30行
 14             info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
 15             if (DEBUG) Log.v(TAG, "  Created new loader " + info);
 16         } else {
 17             if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
 18             info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
 19         }
 20         
 21         if (info.mHaveData && mStarted) {
 22             // If the loader has already generated its data, report it now.
 23             info.callOnLoadFinished(info.mLoader, info.mData);
 24         }
 25         
 26         return (Loader<D>)info.mLoader;
 27     }
 28     
 29 
 30     private LoaderInfo createAndInstallLoader(int id, Bundle args,
 31             LoaderManager.LoaderCallbacks<Object> callback) {
 32         try {
 33             mCreatingLoader = true;
 34             LoaderInfo info = createLoader(id, args, callback);
 35             //這裡跳轉到43行
 36             installLoader(info);
 37             return info;
 38         } finally {
 39             mCreatingLoader = false;
 40         }
 41     }
 42 
 43     void installLoader(LoaderInfo info) {
 44         mLoaders.put(info.mId, info);
 45         if (mStarted) {
 46             //跳轉到51行
 47             info.start();
 48         }
 49     }
 50 
 51    void start() {
 52             if (mRetaining && mRetainingStarted) {
 53                 // Our owner is started, but we were being retained from a
 54                 // previous instance in the started state...  so there is really
 55                 // nothing to do here, since the loaders are still started.
 56                 mStarted = true;
 57                 return;
 58             }
 59 
 60             if (mStarted) {
 61                 // If loader already started, don't restart.
 62                 return;
 63             }
 64 
 65             mStarted = true;
 66             
 67             if (DEBUG) Log.v(TAG, "  Starting: " + this);
 68             if (mLoader == null && mCallbacks != null) {
 69                mLoader = mCallbacks.onCreateLoader(mId, mArgs);
 70             }
 71             if (mLoader != null) {
 72                 if (mLoader.getClass().isMemberClass()
 73                         && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
 74                     throw new IllegalArgumentException(
 75                             "Object returned from onCreateLoader must not be a non-static inner member class: "
 76                             + mLoader);
 77                 }
 78                 if (!mListenerRegistered) {
 79                     //就是在這裡註冊的mloader裡的回撥了,注意這裡的引數是this 也就是loaderInfo這個類 注意這個類就是loadermanger裡的內部類了 再繼續往下看
 80                     //我們前面說到 在asynctask裡面最終呼叫的是mLoader裡的onLoadComplete方法 所以我們就看看loaderInfo這個類裡的這個方法做了什麼看91行
 81                     mLoader.registerListener(mId, this);
 82                     mLoader.registerOnLoadCanceledListener(this);
 83                     mListenerRegistered = true;
 84                 }
 85                 mLoader.startLoading();
 86             }
 87         }
 88 
 89 
 90 
 91          @Override
 92         public void onLoadComplete(Loader<Object> loader, Object data) {
 93             if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
 94             
 95             if (mDestroyed) {
 96                 if (DEBUG) Log.v(TAG, "  Ignoring load complete -- destroyed");
 97                 return;
 98             }
 99 
100             if (mLoaders.get(mId) != this) {
101                 // This data is not coming from the current active loader.
102                 // We don't care about it.
103                 if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
104                 return;
105             }
106             
107             LoaderInfo pending = mPendingLoader;
108             if (pending != null) {
109                 // There is a new request pending and we were just
110                 // waiting for the old one to complete before starting
111                 // it.  So now it is time, switch over to the new loader.
112                 if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
113                 mPendingLoader = null;
114                 mLoaders.put(mId, null);
115                 destroy();
116                 installLoader(pending);
117                 return;
118             }
119             
120             // Notify of the new data so the app can switch out the old data before
121             // we try to destroy it.
122             if (mData != data || !mHaveData) {
123                 mData = data;
124                 mHaveData = true;
125                 if (mStarted) {
126                     //繼續往下 看第149行 
127                     callOnLoadFinished(loader, data);
128                 }
129             }
130 
131             //if (DEBUG) Log.v(TAG, "  onLoadFinished returned: " + this);
132 
133             // We have now given the application the new loader with its
134             // loaded data, so it should have stopped using the previous
135             // loader.  If there is a previous loader on the inactive list,
136             // clean it up.
137             LoaderInfo info = mInactiveLoaders.get(mId);
138             if (info != null && info != this) {
139                 info.mDeliveredData = false;
140                 info.destroy();
141                 mInactiveLoaders.remove(mId);
142             }
143 
144             if (mHost != null && !hasRunningLoaders()) {
145                 mHost.mFragmentManager.startPendingDeferredFragments();
146             }
147         }
148 
149          void callOnLoadFinished(Loader<Object> loader, Object data) {
150             if (mCallbacks != null) {
151                 String lastBecause = null;
152                 if (mHost != null) {
153                     lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
154                     mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
155                 }
156                 try {
157                     if (DEBUG) Log.v(TAG, "  onLoadFinished in " + loader + ": "
158                             + loader.dataToString(data));
159                     //到這裡就真相大白了,最終callback是在這裡呼叫的onLoadFinished方法也就是我們經常重寫的方法
160                     mCallbacks.onLoadFinished(loader, data);
161                 } finally {
162                     if (mHost != null) {
163                         mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
164                     }
165                 }
166                 mDeliveredData = true;
167             }
168         }

好,到這裡 我們就把Loader框架中的 資料傳遞 整個流程給摸清楚了。最後我們再來看看 他的生命週期是如何管理的吧。

我們可以先看看activity的:

  1 //看activity的onStart方法
  2 protected void onStart() {
  3         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
  4         mCalled = true;
  5         //繼續看12行 這個地方mFragements 你就理解成activity本身即可,不多做解釋 這個地方要搞清楚 又是另外一塊了 有興趣的可以自行谷歌activity和fragment如何建立關係
  6         mFragments.doLoaderStart();
  7 
  8         getApplication().dispatchActivityStarted(this);
  9     }
 10 
 11     //這個函式就很明顯了 呼叫了manager的dostart函式
 12      void doLoaderStart() {
 13         if (mLoadersStarted) {
 14             return;
 15         }
 16         mLoadersStarted = true;
 17 
 18         if (mLoaderManager != null) {
 19             //跳轉到30行
 20             mLoaderManager.doStart();
 21         } else if (!mCheckedForLoaderManager) {
 22             mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
 23         }
 24         mCheckedForLoaderManager = true;
 25     }
 26 
 27 //------------------注意上面的程式碼都在activity裡,下面的開始 都在LoaderManger類裡了
 28 
 29      void doStart() {
 30         if (DEBUG) Log.v(TAG, "Starting in " + this);
 31         if (mStarted) {
 32             RuntimeException e = new RuntimeException("here");
 33             e.fillInStackTrace();
 34             Log.w(TAG, "Called doStart when already started: " + this, e);
 35             return;
 36         }
 37         
 38         mStarted = true;
 39 
 40         // Call out to sub classes so they can start their loaders
 41         // Let the existing loaders know that we want to be notified when a load is complete
 42         for (int i = mLoaders.size()-1; i >= 0; i--) {
 43             //跳轉到50行
 44             mLoaders.valueAt(i).start();
 45         }
 46     }
 47 
 48 
 49      void start() {
 50             if (mRetaining && mRetainingStarted) {
 51                 // Our owner is started, but we were being retained from a
 52                 // previous instance in the started state...  so there is really
 53                 // nothing to do here, since the loaders are still started.
 54                 mStarted = true;
 55                 return;
 56             }
 57 
 58             if (mStarted) {
 59                 // If loader already started, don't restart.
 60                 return;
 61             }
 62 
 63             mStarted = true;
 64             
 65             if (DEBUG) Log.v(TAG, "  Starting: " + this);
 66             if (mLoader == null && mCallbacks != null) {
 67                 //原來onCreateLoader這個回撥方法 是在這裡呼叫的 怪不得谷歌說這個方法是必定會被執行並且只會被執行一次的方法!
 68                mLoader = mCallbacks.onCreateLoader(mId, mArgs);
 69             }
 70             if (mLoader != null) {
 71                 if (mLoader.getClass().isMemberClass()
 72                         && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
 73                     throw new IllegalArgumentException(
 74                             "Object returned from onCreateLoader must not be a non-static inner member class: "
 75                             + mLoader);
 76                 }
 77                 if (!mListenerRegistered) {
 78                     mLoader.registerListener(mId, this);
 79                     mLoader.registerOnLoadCanceledListener(this);
 80                     mListenerRegistered = true;
 81                 }
 82                 //你看這裡呼叫了startLoading方法 這個方法是屬於mLoader的 跳轉到88行
 83                 mLoader.startLoading();
 84             }
 85         }
 86 
 87 //88- 98行是loader這個類裡的
 88     public final void startLoading() {
 89         mStarted = true;
 90         mReset = false;
 91         mAbandoned = false;
 92         onStartLoading();
 93     }
 94 
 95     //你看最終是呼叫的這個方法,注意他是空方法 是交給子類去實現的,我們去看看cursorloader這個子類是怎麼實現的吧。
 96     protected void onStartLoading() {
 97     }
 98 //99-  112行 是cursorLoader這個類的程式碼
 99      
100 //你看這個地方 直接呼叫了forceload方法 這個方法大家前面肯定有印象  他最終會啟動那個asynctask 去執行background方法
101 //這也就解釋了 第一次我們的資料是怎麼來的,比如說 假設我們的資料來源還沒有被更新的時候,為什麼會自動去查詢資料來源 並返回資料
102 //到這裡就明白了,原來是activity的onStart函式為開端 一步步走到Loader的子類的onStartLoading方法裡的,當然你如果覺得
103 //Loader不需要初始載入 只要在有變化的時候再載入 那這個方法你就可以保持為空了。
104      protected void onStartLoading() {
105         if (mCursor != null) {
106             deliverResult(mCursor);
107         }
108         if (takeContentChanged() || mCursor == null) {
109             forceLoad();
110         }
111     }
112 
113 //114-139行 為 http://developer.android.com/intl/zh-cn/reference/android/content/AsyncTaskLoader.html 這個裡面 AppListLoader  的一段原始碼
114 //你看138行 也是直接呼叫的forceLoad 這樣當我們的applist沒有變化的時候 第一次也能顯示出列表 
115  /**
116      * Handles a request to start the Loader.
117      */
118     @Override protected void onStartLoading() {
119         if (mApps != null) {
120             // If we currently have a result available, deliver it
121             // immediately.
122             deliverResult(mApps);
123         }
124 
125         // Start watching for changes in the app data.
126         if (mPackageObserver == null) {
127             mPackageObserver = new PackageIntentReceiver(this);
128         }
129 
130         // Has something interesting in the configuration changed since we
131         // last built the app list?
132         boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
133 
134         if (takeContentChanged() || mApps == null || configChange) {
135             // If the data has changed since the last time it was loaded
136             // or is not currently available, start a load.
137             forceLoad();
138         }
139     }

start流程 我們分析完畢了 最後我們再看看stop流程吧 看完這個 其他生命週期 我們就不分析了留給讀者自己感興趣的話自己分析試試看。

  1 //我們來看看fragment的onDestroy方法 都做了什麼
  2 public void onDestroy() {
  3         mCalled = true;
  4         //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
  5         //        + " mLoaderManager=" + mLoaderManager);
  6         if (!mCheckedForLoaderManager) {
  7             mCheckedForLoaderManager = true;
  8             mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
  9         }
 10         if (mLoaderManager != null) {
 11             //跳轉到16行
 12             mLoaderManager.doDestroy();
 13         }
 14     }
 15 //上面的程式碼 是在fragment裡 下面的程式碼在loadermanger裡
 16      void doDestroy() {
 17         if (!mRetaining) {
 18             if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
 19             for (int i = mLoaders.size()-1; i >= 0; i--) {
 20                 mLoaders.valueAt(i).destroy();
 21             }
 22             mLoaders.clear();
 23         }
 24         
 25         if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
 26         for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
 27             mInactiveLoaders.valueAt(i).destroy();
 28         }
 29         mInactiveLoaders.clear();
 30     }
 31 //下面這個destroy流程 可以清晰的看到很多東西 包括clear所有回撥等
 32  void destroy() {
 33             if (DEBUG) Log.v(TAG, "  Destroying: " + this);
 34             mDestroyed = true;
 35             boolean needReset = mDeliveredData;
 36             mDeliveredData = false;
 37             if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
 38                 if (DEBUG) Log.v(TAG, "  Reseting: " + this);
 39                 String lastBecause = null;
 40                 if (mHost != null) {
 41                     lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
 42                     mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset";
 43                 }
 44                 try {
 45                     mCallbacks.onLoaderReset(mLoader);
 46                 } finally {
 47                     if (mHost != null) {
 48                         mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
 49                     }
 50                 }
 51             }
 52             mCallbacks = null;
 53             mData = null;
 54             mHaveData = false;
 55             if (mLoader != null) {
 56                 if (mListenerRegistered) {
 57                     mListenerRegistered = false;
 58                     mLoader.unregisterListener(this);
 59                     mLoader.unregisterOnLoadCanceledListener(this);
 60                 }
 61                 //在這呼叫了rest
 62                 mLoader.reset();
 63             }
 64             if (mPendingLoader != null) {
 65                 mPendingLoader.destroy();
 66             }
 67         }
 68 //最後我們來看看loader裡的程式碼 就能明白了 當fragement destroy的時候最終的呼叫來到了子類的onReset方法
 69          public void reset() {
 70         onReset();
 71         mReset = true;
 72         mStarted = false;
 73         mAbandoned = false;
 74         mContentChanged = false;
 75         mProcessingChange = false;
 76     }
 77 
 78     /**
 79      * Subclasses must implement this to take care of resetting their loader,
 80      * as per {@link #reset()}.  This is not called by clients directly,
 81      * but as a result of a call to {@link #reset()}.
 82      * This will always be called from the process's main thread.
 83      */
 84     protected void onReset() {
 85     }
 86 
 87 //這裡是cURSORLOADER的程式碼了 你看這裡關閉了cursor
 88     @Override
 89     protected void onReset() {
 90         super.onReset();
 91         
 92         // Ensure the loader is stopped
 93         onStopLoading();
 94 
 95         if (mCursor != null && !mCursor.isClosed()) {
 96             mCursor.close();
 97         }
 98         mCursor = null;
 99     }
100 
101 //同樣的 我們也能看到applistloader原始碼裡面 也是在這個函式裡清除了廣播接收器。
102 //所以讀到這裡 我們就知道 loader的強大了。你只需要搞清楚這些生命週期的函式的意義
103 //就可以重寫他們,至於什麼時候呼叫 loader都幫你做好了 你只需要在裡面實現你自己的邏輯即可!非常強大 非常好用
104     @Override protected void onReset() {
105         super.onReset();
106 
107         // Ensure the loader is stopped
108         onStopLoading();
109 
110         // At this point we can release the resources associated with 'apps'
111         // if needed.
112         if (mApps != null) {
113             onReleaseResources(mApps);
114             mApps = null;
115         }
116 
117         // Stop monitoring for changes.
118         if (mPackageObserver != null) {
119             getContext().unregisterReceiver(mPackageObserver);
120             mPackageObserver = null;
121         }
122     }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---恢復內容結束---

相關文章