• Android 异步加载神器Loader全解析


    在之前呢,我们经常会有这种需求,比如在某个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     }

    ---恢复内容结束---

  • 相关阅读:
    python 读写文件
    input 默认值为灰色,输入时清楚默认值
    openstack security group and rules python api use
    centos7 ssh 设置key认证
    联通烽火hg220桥接tplink路由器
    windows,linux,mac生成ssh public key 和 private key
    bootstrap的编辑标记 angularjs input 弹出框
    sqlalchemy多表联合查询(join)
    python urllib2 发起http请求post
    openstack新建虚机、网络、路由时候对应的ovs网桥的变化
  • 原文地址:https://www.cnblogs.com/punkisnotdead/p/4861376.html
Copyright © 2020-2023  润新知