首先说一下 这个例子是干嘛的,他主要是监听手机里app list的变化,比如你删除了一个应用安装了一个应用,马上能捕捉到你的手机里app list的变化 并显示在界面,大家都知道 监听app list是通过监听系统广播来完成的。 我主要讲一下 这个官方demo里 是如何在监听到系统广播以后和loader结合起来然后自动回调方法的。
  /**
  * Helper class to look for interesting changes to the installed apps
  * so that the loader can be updated.
  */
  public static class PackageIntentReceiver extends BroadcastReceiver {
  final AppListLoader mLoader;
  //这个构造函数是很重要的 他接收的 是自定义的loader
  public PackageIntentReceiver(AppListLoader loader) {
  mLoader = loader;
  IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
  filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
  filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
  filter.addDataScheme("package");
  mLoader.getContext().registerReceiver(this, filter);
  // Register for events related to sdcard installation.
  IntentFilter sdFilter = new IntentFilter();
  sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
  sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
  //在这个地方 直接用loader来注册这个广播接收器
  mLoader.getContext().registerReceiver(this, sdFilter);
  }
  //在收到广播以后 什么事情都没有做,而是调用了loader的onContentChanged方法
  @Override public void onReceive(Context context, Intent intent) {
  // Tell the loader about the change.
  mLoader.onContentChanged();
  }
  }
  你看这里的25-26行 调用了 loader的onContentChanged方法。继续看下面的loader
  /**
  * A custom Loader that loads all of the installed applications.
  */
  public static class AppListLoader extends AsyncTaskLoader<List<AppEntry>> {
  final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
  final PackageManager mPm;
  List<AppEntry> mApps;
  PackageIntentReceiver mPackageObserver;
  public AppListLoader(Context context) {
  super(context);
  // Retrieve the package manager for later use; note we don't
  // use 'context' directly but instead the save global application
  // context returned by getContext().
  mPm = getContext().getPackageManager();
  }
  //实际上重要的是这个方法了,每当这个回调方法被调用的时候 去取applist 然后将结果返回到
  //onLoadFinished 这个回调方法里面!
  @Override public List<AppEntry> loadInBackground() {
  // Retrieve all known applications.
  List<ApplicationInfo> apps = mPm.getInstalledApplications(
  PackageManager.GET_UNINSTALLED_PACKAGES |
  PackageManager.GET_DISABLED_COMPONENTS);
  if (apps == null) {
  apps = new ArrayList<ApplicationInfo>();
  }
  final Context context = getContext();
  // Create corresponding array of entries and load their labels.
  List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
  for (int i=0; i<apps.size(); i++) {
  AppEntry entry = new AppEntry(this, apps.get(i));
  entry.loadLabel(context);
  entries.add(entry);
  }
  // Sort the list.
  Collections.sort(entries, ALPHA_COMPARATOR);
  // Done!
  return entries;
  }
  /**
  * Called when there is new data to deliver to the client.  The
  * super class will take care of delivering it; the implementation
  * here just adds a little more logic.
  */
  @Override public void deliverResult(List<AppEntry> apps) {
  if (isReset()) {
  // An async query came in while the loader is stopped.  We
  // don't need the result.
  if (apps != null) {
  onReleaseResources(apps);
  }
  }
  List<AppEntry> oldApps = mApps;
  mApps = apps;
  if (isStarted()) {
  // If the Loader is currently started, we can immediately
  // deliver its results.
  super.deliverResult(apps);
  }
  // At this point we can release the resources associated with
  // 'oldApps' if needed; now that the new result is delivered we
  // know that it is no longer in use.
  if (oldApps != null) {
  onReleaseResources(oldApps);
  }
  }
  /**
  * Handles a request to start the Loader.
  */
  @Override protected void onStartLoading() {
  if (mApps != null) {
  // If we currently have a result available, deliver it
  // immediately.
  deliverResult(mApps);
  }
  // Start watching for changes in the app data.
  if (mPackageObserver == null) {
  mPackageObserver = new PackageIntentReceiver(this);
  }
  // Has something interesting in the configuration changed since we
  // last built the app list?
  boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
  if (takeContentChanged() || mApps == null || configChange) {
  // If the data has changed since the last time it was loaded
  // or is not currently available, start a load.
  forceLoad();
  }
  }
  /**
  * Handles a request to stop the Loader.
  */
  @Override protected void onStopLoading() {
  // Attempt to cancel the current load task if possible.
  cancelLoad();
  }
  /**
  * Handles a request to cancel a load.
  */
  @Override public void onCanceled(List<AppEntry> apps) {
  super.onCanceled(apps);
  // At this point we can release the resources associated with 'apps'
  // if needed.
  onReleaseResources(apps);
  }
  /**
  * Handles a request to completely reset the Loader.
  */
  @Override protected void onReset() {
  super.onReset();
  // Ensure the loader is stopped
  onStopLoading();
  // At this point we can release the resources associated with 'apps'
  // if needed.
  if (mApps != null) {
  onReleaseResources(mApps);
  mApps = null;
  }
  // Stop monitoring for changes.
  if (mPackageObserver != null) {
  getContext().unregisterReceiver(mPackageObserver);
  mPackageObserver = null;
  }
  }
  /**
  * Helper function to take care of releasing resources associated
  * with an actively loaded data set.
  */
  protected void onReleaseResources(List<AppEntry> apps) {
  // For a simple List<> there is nothing to do.  For something
  // like a Cursor, we would close it here.
  }
  }
  好,到这里流程很明显了,在loader里 注册广播接收器,当广播接收器 收到广播以后 调用loader的onContentChanged方法,这个方法一调用 AppListLoader里的loadInBackGround会被调用,然后当loadInBackGround执行完毕以后 会把结果传递给onLoadFinished方法了。 搞清楚这个流程 你真正学会了使用loader这个大杀器了。当然了,我们并不满足于此,loader还有一个特性是可以自动管理他自己的生命周期 等等。我们现在去看看他的源码,是如何完成这一点的。 并且上述几个方法之间是如何相互调用的,顺序如何。
  首先 我们要搞清楚几个类之间的关系:
  public class CursorLoader extends AsyncTaskLoader<Cursor> {
  public abstract class AsyncTaskLoader<D> extends Loader<D> {
  public class Loader<D> {
  这样很清晰。首先由一个实体类作为基础的基类,Loader 注意他可以接受一个泛型为参数,然后有一个抽象类:AsyncTaskLoader 也是泛型作为参数。
  后实际调用运作的类是CursorLoader类了,这里可以看出来 传进去的泛型是一个Cursor。你在自定义Loader的时候,这个泛型参数 当然是可以自己决定的,
  比如官方demo里 传的是一个List。
  搞清楚 他们三者之间的关系,剩下的简单多了。可以逐步分析了。
  在前面的3个demo里,我们分别演示了在fragment和activity里 调用loader的方法。 那我们看看 这两者之间有什么异同点。先来看fragment。
  fragment里 我们是这样调用的:
  //这个地方初始化了我们的loader
  getLoaderManager().initLoader(0, null, this);
  直接get了一个manager 然后init他。我们进去看fragment的源码:
  //这边能看出来一个fragment只能有一个loadermanager了。
  public LoaderManager getLoaderManager() {
  if (mLoaderManager != null) {
  return mLoaderManager;
  }
  //mHost很好理解 是fragment的宿主,也是跟fragment 相关联的activity。
  if (mHost == null) {
  throw new IllegalStateException("Fragment " + this + " not attached to Activity");
  }
  mCheckedForLoaderManager = true;
  mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, true);
  return mLoaderManager;
  }
  既然 我们知道 fragment的getLoaderManager也是通过activity的getLoader去调用的,那我们去activity里的源码看看 :
  //在activty中终实际上调用的是他了 是这个方法
  LoaderManagerImpl getLoaderManagerImpl() {
  if (mLoaderManager != null) {
  return mLoaderManager;
  }
  mCheckedForLoaderManager = true;
  mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
  return mLoaderManager;
  }
  //这个地方能看到 主要的第一个参数 who,你到这能发现 如果是activity自己调用的话,传进去的who的值是root
  //也是说一个actvity 只能有一个loadermanger 但是我们可以发现在fragment里 传进去的值是下面这个:
  // Internal unique name for this fragment;
  //String mWho;
  //也是说每一个fragment的mWho的值都是的,而在activty中,是维护了一个map,一个key 对应一个loadermanager
  //key是fragment的那个的标示,或者是activity自己,activity自己的标示是(root)了
  LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
  if (mAllLoaderManagers == null) {
  mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
  }
  LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
  if (lm == null) {
  if (create) {
  lm = new LoaderManagerImpl(who, this, started);
  mAllLoaderManagers.put(who, lm);
  }
  } else {
  lm.updateHostController(this);
  }
  return lm;
  }
  好 一直到这里 ,我们可以下一个结论了,真正的loadermanager都是存储在activity中的,包括fragment的loadermanager也是,通过一个map来保证 get的时候取的manager是自己对应的,并且全局。继续往下看:
  public abstract class LoaderManager {
  /**
  * Callback interface for a client to interact with the manager.
  */
  public interface LoaderCallbacks<D> {
  /**
  * Instantiate and return a new Loader for the given ID.
  *
  * @param id The ID whose loader is to be created.
  * @param args Any arguments supplied by the caller.
  * @return Return a new Loader instance that is ready to start loading.
  */
  public Loader<D> onCreateLoader(int id, Bundle args);
  /**
  * Called when a previously created loader has finished its load.  Note
  * that normally an application is <em>not</em> allowed to commit fragment
  * transactions while in this call, since it can happen after an
  * activity's state is saved.  See {@link FragmentManager#beginTransaction()
  * FragmentManager.openTransaction()} for further discussion on this.
  *
  * <p>This function is guaranteed to be called prior to the release of
  * the last data that was supplied for this Loader.  At this point
  * you should remove all use of the old data (since it will be released
  * soon), but should not do your own release of the data since its Loader
  * owns it and will take care of that.  The Loader will take care of
  * management of its data so you don't have to.  In particular:
  *
  * <ul>
  * <li> <p>The Loader will monitor for changes to the data, and report
  * them to you through new calls here.  You should not monitor the
  * data yourself.  For example, if the data is a {@link android.database.Cursor}
  * and you place it in a {@link android.widget.CursorAdapter}, use
  * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context,
  * android.database.Cursor, int)} constructor <em>without</em> passing
  * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY}
  * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER}
  * (that is, use 0 for the flags argument).  This prevents the CursorAdapter
  * from doing its own observing of the Cursor, which is not needed since
  * when a change happens you will get a new Cursor throw another call
  * here.
  * <li> The Loader will release the data once it knows the application
  * is no longer using it.  For example, if the data is
  * a {@link android.database.Cursor} from a {@link android.content.CursorLoader},
  * you should not call close() on it yourself.  If the Cursor is being placed in a
  * {@link android.widget.CursorAdapter}, you should use the
  * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)}
  * method so that the old Cursor is not closed.
  * </ul>
  *
  * @param loader The Loader that has finished.
  * @param data The data generated by the Loader.
  */
  public void onLoadFinished(Loader<D> loader, D data);
  /**
  * Called when a previously created loader is being reset, and thus
  * making its data unavailable.  The application should at this point
  * remove any references it has to the Loader's data.
  *
  * @param loader The Loader that is being reset.
  */
  public void onLoaderReset(Loader<D> loader);
  }
  一看知道 loadermanger 其实是一个抽象类。是定义了一些 我们需要的接口而已,这些接口方法的含义和用法 在那3个demo里 相信大家都有了解,不多说。
  我们去看看这个抽象类的实现类,为什么要看他,因为你在get到这个maganger以后 马上去调用了他的init方法 我们看看这部分的逻辑是怎么样的:
  public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
  if (mCreatingLoader) {
  throw new IllegalStateException("Called while creating a loader");
  }
  //这个是先看看是否有活动的loader 有的话取出来 没有的话 创建一个
  LoaderInfo info = mLoaders.get(id);
  if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
  if (info == null) {
  // Loader doesn't already exist; create.
  info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
  if (DEBUG) Log.v(TAG, "  Created new loader " + info);
  } else {
  if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
  info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
  }
  if (info.mHaveData && mStarted) {
  // If the loader has already generated its data, report it now.
  info.callOnLoadFinished(info.mLoader, info.mData);
  }
  return (Loader<D>)info.mLoader;
  }
  //这个是现在存活的loader
  final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);
  //这个是已经运行结束的loader
  final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);
  //其实这个创建loader的过程特别简单,我们主要看第三个参数,callback 这个参数
  //一想明白,在前面3个demo里我们是直接在fragemet和activity里实现的callback
  //所以传进去的是this,也是说 回调是在这个函数里 真正的和loader 发生了关联了
  private LoaderInfo createAndInstallLoader(int id, Bundle args,
  LoaderManager.LoaderCallbacks<Object> callback) {
  try {
  mCreatingLoader = true;
  LoaderInfo info = createLoader(id, args, callback);
  installLoader(info);
  return info;
  } finally {
  mCreatingLoader = false;
  }
  }
  你看 一直到这里,我们明白了 callback是怎么和loadermageer本身发生关联的。 我们继续往下看。这次我们要搞明白当数据源发生变化的时候 是怎么一步步回调我们子类loader的方法的。
  我们先看Loader这个基类的主要方法:
  //这个是一个观察者 当发生变化的时候 他调用了onContentChanged方法
  public final class ForceLoadContentObserver extends ContentObserver {
  public ForceLoadContentObserver() {
  super(new Handler());
  }
  @Override
  public boolean deliverSelfNotifications() {
  return true;
  }
  @Override
  public void onChange(boolean selfChange) {
  onContentChanged();
  }
  }
  //下面这2个方法一看明白 终当数据源发生变化的时候 会通知这个观察者,然后这个观察者会终调用
  //onForceLoad这个方法 而onForceLoad是交给子类去实现的 也是AsyncTaskLoader的onForceLoad方法了