转载

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 }

最后我们看下运行的效果:

Android 异步加载神器Loader全解析

好,那到这里 又有人要说了,你这个说来说去 还不是只能支持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     }

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

正文到此结束
Loading...