关于Android的Loader相关

作者: 我是昵称 | 来源:发表于2017-06-02 09:03 被阅读143次

    1 背景##

    在Android中任何耗时的操作都不能放在UI主线程中,所以耗时的操作都需要使用异步实现。同样的,在ContentProvider中也可能存在耗时操作,这时也该使用异步操作,而3.0之后最推荐的异步操作就是Loader。它可以方便我们在Activity和Fragment中异步加载数据,而不是用线程或AsyncTask,他的优点如下:

    提供异步加载数据机制;
    对数据源变化进行监听,实时更新数据;
    在Activity配置发生变化(如横竖屏切换)时不用重复加载数据;
    适用于任何Activity和Fragment;
    PS:由于在我们现在的项目中都使用了Loader来处理数据加载(而且由于粗心跳过几个坑,譬如Loader ID重复导致数据逻辑异常、多线程中restartLoader导致Loader抛出异常(最后保证都在UI线程中执行即可)等),所以接下来我们进行下使用及源码浅析。

    既然接下来准备要说说他的使用强大之处了,那不妨我们先来一张图直观的感性认识下不用Loader(左)与用Loader(右)对我们开发者及代码复杂度和框架的影响吧,如下:


    loaders.png

    2 基础使用实例##

    Loader API 摘要###

    在应用中使用加载器时,可能会涉及到多个类和接口。 下表汇总了这些类和接口:

    类/接口 说明
    LoaderManager 一种与 Activity 或 Fragment 相关联的的抽象类,用于管理一个或多个 Loader 实例。 这有助于应用管理与 Activity 或 Fragment 生命周期相关联的、运行时间较长的操作。它最常见的用法是与 CursorLoader 一起使用,但应用可自由写入其自己的加载器,用于加载其他类型的数据。 每个 Activity 或片段中只有一个 LoaderManager。但一个 LoaderManager 可以有多个加载器。
    LoaderManager.LoaderCallbacks 一种回调接口,用于客户端与 LoaderManager 进行交互。例如,您可使用 onCreateLoader() 回调方法创建新的加载器。
    Loader 一种执行异步数据加载的抽象类。这是加载器的基类。 您通常会使用 CursorLoader,但您也可以实现自己的子类。加载器处于活动状态时,应监控其数据源并在内容变化时传递新结果。
    AsyncTaskLoader 提供 AsyncTask 来执行工作的抽象加载器。
    CursorLoader AsyncTaskLoader 的子类,它将查询 ContentResolver 并返回一个 Cursor。此类采用标准方式为查询游标实现 Loader 协议。它是以 AsyncTaskLoader 为基础而构建,在后台线程中执行游标查询,以免阻塞应用的 UI。使用此加载器是从 ContentProvider 异步加载数据的最佳方式,而不用通过片段或 Activity 的 API 来执行托管查询。

    上表中的类和接口是您在应用中用于实现加载器的基本组件。 并非您创建的每个加载器都要用到上述所有类和接口。但是,为了初始化加载器以及实现一个 Loader 类(如 CursorLoader),您始终需要要引用 LoaderManager。 下文将为您展示如何在应用中使用这些类和接口。

    在应用中使用加载器###

    此部分描述如何在 Android 应用中使用加载器。使用加载器的应用通常包括:

    • Activity 或 Fragment。
    • LoaderManager 的实例。
    • 一个 CursorLoader,用于加载由 ContentProvider 支持的数据。您也可以实现自己的 Loader 或 AsyncTaskLoader 子类,从其他源中加载数据。
    • 一个 LoaderManager.LoaderCallbacks 实现。您可以使用它来创建新加载器,并管理对现有加载器的引用。
    • 一种显示加载器数据的方法,如 SimpleCursorAdapter。
    • 使用 CursorLoader 时的数据源,如 ContentProvider。

    启动加载器###

    LoaderManager 可在 Activity 或 Fragment 内管理一个或多个 Loader 实例。每个 Activity 或片段中只有一个 LoaderManager。

    通常,您会在 Activity 的 onCreate() 方法或片段的onActivityCreated() 方法内初始化 Loader。您执行操作如下:

    // Prepare the loader.  Either re-connect with an existing one,
    // or start a new one.
    getLoaderManager().initLoader(0, null, this);
    

    initLoader() 方法采用以下参数:

    • 用于标识加载器的唯一 ID。在此示例中,ID 为 0。

    • 在构建时提供给加载器的可选参数(在此示例中为 null)。

    • LoaderManager.LoaderCallbacks 实现, LoaderManager 将调用此实现来报告加载器事件。在此示例中,本地类实现 LoaderManager.LoaderCallbacks 接口,因此它会传递对自身的引用 this。
      initLoader() 调用确保加载器已初始化且处于活动状态。这可能会出现两种结果:

    • 如果 ID 指定的加载器已存在,则将重复使用上次创建的加载器。

    • 如果 ID 指定的加载器不存在,则 initLoader() 将触发 LoaderManager.LoaderCallbacks 方法 onCreateLoader()。在此方法中,您可以实现代码以实例化并返回新加载器。有关详细介绍,请参阅 onCreateLoader 部分。
      无论何种情况,给定的 LoaderManager.LoaderCallbacks 实现均与加载器相关联,且将在加载器状态变化时调用。如果在调用时,调用程序处于启动状态,且请求的加载器已存在并生成了数据,则系统将立即调用 onLoadFinished()(在 initLoader() 期间),因此您必须为此做好准备。 有关此回调的详细介绍,请参阅 onLoadFinished。

    请注意,initLoader() 方法将返回已创建的 Loader,但您不必捕获其引用。LoaderManager 将自动管理加载器的生命周期。LoaderManager 将根据需要启动和停止加载,并维护加载器的状态及其相关内容。 这意味着您很少直接与加载器进行交互(有关使用加载器方法调整加载器行为的示例,请参阅 LoaderThrottle 示例)。当特定事件发生时,您通常会使用 LoaderManager.LoaderCallbacks 方法干预加载进程。有关此主题的详细介绍,请参阅使用 LoaderManager 回调。

    重启加载器###

    当您使用 initLoader() 时(如上所述),它将使用含有指定 ID 的现有加载器(如有)。如果没有,则它会创建一个。但有时,您想舍弃这些旧数据并重新开始。

    要舍弃旧数据,请使用 restartLoader()。例如,当用户的查询更改时,此 SearchView.OnQueryTextListener 实现将重启加载器。 加载器需要重启,以便它能够使用修订后的搜索过滤器执行新查询:

    public boolean onQueryTextChanged(String newText) {
        // Called when the action bar search text has changed.  Update
        // the search filter, and restart the loader to do a new query
        // with this filter.
        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
        getLoaderManager().restartLoader(0, null, this);
        return true;
    }
    
    

    使用 LoaderManager 回调###

    LoaderManager.LoaderCallbacks 是一个支持客户端与 LoaderManager 交互的回调接口。

    加载器(特别是 CursorLoader)在停止运行后,仍需保留其数据。这样,应用即可保留 Activity 或片段的 onStop() 和 onStart() 方法中的数据。当用户返回应用时,无需等待它重新加载这些数据。您可使用 LoaderManager.LoaderCallbacks 方法了解何时创建新加载器,并告知应用何时停止使用加载器的数据。

    LoaderManager.LoaderCallbacks 包括以下方法:

    • onCreateLoader():针对指定的 ID 进行实例化并返回新的 Loader
    • onLoadFinished() :将在先前创建的加载器完成加载时调用
    • onLoaderReset():将在先前创建的加载器重置且其数据因此不可用时调用
      下文更详细地描述了这些方法。

    onCreateLoader
    当您尝试访问加载器时(例如,通过 initLoader()),该方法将检查是否已存在由该 ID 指定的加载器。 如果没有,它将触发 LoaderManager.LoaderCallbacks 方法 onCreateLoader()。在此方法中,您可以创建新加载器。 通常,这将是 CursorLoader,但您也可以实现自己的 Loader 子类。

    在此示例中,onCreateLoader() 回调方法创建了 CursorLoader。您必须使用其构造函数方法来构建 CursorLoader。该方法需要对 ContentProvider 执行查询时所需的一系列完整信息。具体地说,它需要:

    • uri:用于检索内容的 URI
    • projection:要返回的列的列表。传递 null 时,将返回所有列,这样会导致效率低下
    • selection:一种用于声明要返回哪些行的过滤器,采用 SQL WHERE 子句格式(WHERE 本身除外)。传递 null 时,将为指定的 URI 返回所有行
    • selectionArgs:您可以在 selection 中包含 ?s,它将按照在 selection 中显示的顺序替换为 selectionArgs 中的值。该值将绑定为字串符
    • sortOrder:行的排序依据,采用 SQL ORDER BY 子句格式(ORDER BY 自身除外)。传递 null 时,将使用默认排序顺序(可能并未排序)
      例如:
     // If non-null, this is the current filter the user has provided.
    String mCurFilter;
    ...
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // This is called when a new Loader needs to be created.  This
        // sample only has one Loader, so we don't care about the ID.
        // First, pick the base URI to use depending on whether we are
        // currently filtering.
        Uri baseUri;
        if (mCurFilter != null) {
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                      Uri.encode(mCurFilter));
        } else {
            baseUri = Contacts.CONTENT_URI;
        }
    
        // Now create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                + Contacts.DISPLAY_NAME + " != '' ))";
        return new CursorLoader(getActivity(), baseUri,
                CONTACTS_SUMMARY_PROJECTION, select, null,
                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
    }
    

    onLoadFinished###

    当先前创建的加载器完成加载时,将调用此方法。该方法必须在为此加载器提供的最后一个数据释放之前调用。 此时,您应移除所有使用的旧数据(因为它们很快会被释放),但不要自行释放这些数据,因为这些数据归其加载器所有,其加载器会处理它们。

    当加载器发现应用不再使用这些数据时,即会释放它们。 例如,如果数据是来自 CursorLoader 的一个游标,则您不应手动对其调用 close()。如果游标放置在 CursorAdapter 中,则应使用 swapCursor() 方法,使旧 Cursor 不会关闭。例如:

    // This is the Adapter being used to display the list's data.
    SimpleCursorAdapter mAdapter;
    ...
    
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in.  (The framework will take care of closing the
        // old cursor once we return.)
        mAdapter.swapCursor(data);
    }
    

    onLoaderReset###

    此方法将在先前创建的加载器重置且其数据因此不可用时调用。 通过此回调,您可以了解何时将释放数据,因而能够及时移除其引用。

    此实现调用值为 null 的swapCursor():

    // This is the Adapter being used to display the list's data.
    SimpleCursorAdapter mAdapter;
    ...
    
    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished()
        // above is about to be closed.  We need to make sure we are no
        // longer using it.
        mAdapter.swapCursor(null);
    }
    
    

    3 源码浅析###

    和上面的基本使用介绍一样,关于Loader的源码浅析过程会涉及到Activity、Fragment、LoaderManager、Loader、AsyncLoader、CursorLoader等类。所以我们分析的过程还是和以前一样,依据使用顺序进行分析。

    我们在分析之前先来看一个Loader框架概要图,如下: loadermanager.jpg

    通过上面图和前面的基础实例我们可以发现Loader的框架和各个类的职责都很明确。Activity和Fragment管理LoaderManager,LoaderManager管理Loader,Loader得到数据后触发在LoaderManager中实现的Loader的callback接口,LoaderManager在接收到Loader的callback回传调运时触发我们Activity或Fragment中实现的LoaderManager回调callback接口,就这样就实现了Loader的所有功能,而我们平时写代码一般只用关心LoaderManager的callback实现即可;对于自定义Loader可能还需要关心AsyncTaskLoader子类的实现。

    看看Activity中的LoaderManager#####
    image.png

    恢复所有LoaderManagers的保存状态。 给定的LoaderManager列表是跨配置更改保留的LoaderManager实例。


    onCreateLoaderConfig.png onStart.png
    performOnstop.png
    performDestroy.png

    --------------------上面是Activity里对Loader的生命周期管理---------------------


    onstart2.png onstart3.png LoaderManagerStart.png

    通过上面的分析可以发现,Activity其实真正的管理了Activity及Fragment的LoaderManager(Fragment也会管理一部分自己LoaderManager的周期),而LoaderManager又管理了Loader,可以发现他们各自的管理范围都是十分的清晰明了的。

    LoadManager及其实现类LoadManagerImpl的浅析#####
    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);
        }
        
        /**
         * Ensures a loader is initialized and active.  If the loader doesn't
         * already exist, one is created and (if the activity/fragment is currently
         * started) starts the loader.  Otherwise the last created
         * loader is re-used.
         *
         * <p>In either case, the given callback is associated with the loader, and
         * will be called as the loader state changes.  If at the point of call
         * the caller is in its started state, and the requested loader
         * already exists and has generated its data, then
         * callback {@link LoaderCallbacks#onLoadFinished} will
         * be called immediately (inside of this function), so you must be prepared
         * for this to happen.
         *
         * @param id A unique identifier for this loader.  Can be whatever you want.
         * Identifiers are scoped to a particular LoaderManager instance.
         * @param args Optional arguments to supply to the loader at construction.
         * If a loader already exists (a new one does not need to be created), this
         * parameter will be ignored and the last arguments continue to be used.
         * @param callback Interface the LoaderManager will call to report about
         * changes in the state of the loader.  Required.
         */
        public abstract <D> Loader<D> initLoader(int id, Bundle args,
                LoaderManager.LoaderCallbacks<D> callback);
    
        /**
         * Starts a new or restarts an existing {@link android.content.Loader} in
         * this manager, registers the callbacks to it,
         * and (if the activity/fragment is currently started) starts loading it.
         * If a loader with the same id has previously been
         * started it will automatically be destroyed when the new loader completes
         * its work. The callback will be delivered before the old loader
         * is destroyed.
         *
         * @param id A unique identifier for this loader.  Can be whatever you want.
         * Identifiers are scoped to a particular LoaderManager instance.
         * @param args Optional arguments to supply to the loader at construction.
         * @param callback Interface the LoaderManager will call to report about
         * changes in the state of the loader.  Required.
         */
        public abstract <D> Loader<D> restartLoader(int id, Bundle args,
                LoaderManager.LoaderCallbacks<D> callback);
    
        /**
         * Stops and removes the loader with the given ID.  If this loader
         * had previously reported data to the client through
         * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call
         * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}.
         */
        public abstract void destroyLoader(int id);
    
        /**
         * Return the Loader with the given id or null if no matching Loader
         * is found.
         */
        public abstract <D> Loader<D> getLoader(int id);
    
        /**
         * Print the LoaderManager's state into the given stream.
         *
         * @param prefix Text to print at the front of each line.
         * @param fd The raw file descriptor that the dump is being sent to.
         * @param writer A PrintWriter to which the dump is to be set.
         * @param args Additional arguments to the dump request.
         */
        public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
    
        /**
         * Control whether the framework's internal loader manager debugging
         * logs are turned on.  If enabled, you will see output in logcat as
         * the framework performs loader operations.
         */
        public static void enableDebugLogging(boolean enabled) {
            LoaderManagerImpl.DEBUG = enabled;
        }
    
        /** @hide for internal testing only */
        public FragmentHostCallback getFragmentHostCallback() { return null; }
    }
    
    
        /**
         * Returns a {@link LoaderManager}.
         */
        public LoaderManager getLoaderManager() {
            return mHost.getLoaderManagerImpl();
        }
    
    

    我们获取的LoaderManager实例其实就是LoaderManagerImpl对象,而LoaderManagerImpl又是LoaderManager类的子类.

    这十分类似于我们现在的框架结构,VRL和具体的ViewMng的实现关系,把各自的功能单一化。


    CursorLoader###

    关于用到的这个,就得层层剥茧去一探究竟了
    public class CursorLoader extends AsyncTaskLoader<Cursor>
    CursorLoader继承于AsyncTaskLoader
    public abstract class AsyncTaskLoader<D> extends Loader<D> {
    而AsyncTaskLoader是抽象类并继承于Loader

    我们就先看看这个Loader基类吧,该类核心方法及内部类结构图如下:

    Loader.png
    public class Loader<D> {
        int mId;
        OnLoadCompleteListener<D> mListener;
        OnLoadCanceledListener<D> mOnLoadCanceledListener;
        Context mContext;
        boolean mStarted = false;
        boolean mAbandoned = false;
        boolean mReset = true;
        boolean mContentChanged = false;
        boolean mProcessingChange = false;
    
        /**
         * An implementation of a ContentObserver that takes care of connecting
         * it to the Loader to have the loader re-load its data when the observer
         * is told it has changed.  You do not normally need to use this yourself;
         * it is used for you by {@link CursorLoader} to take care of executing
         * an update when the cursor's backing data changes.
         */
        //数据源变化监听器(观察者模式),实现了ContentObserver类
        public final class ForceLoadContentObserver extends ContentObserver {
            public ForceLoadContentObserver() {
                super(new Handler());
            }
    
            @Override
            public boolean deliverSelfNotifications() {
                return true;
            }
    
            @Override
            public void onChange(boolean selfChange) {
            //实质是调运Loader的forceLoad方法
                onContentChanged();
            }
        }
    
        /**
         * Interface that is implemented to discover when a Loader has finished
         * loading its data.  You do not normally need to implement this yourself;
         * it is used in the implementation of {@link android.app.LoaderManager}
         * to find out when a Loader it is managing has completed so that this can
         * be reported to its client.  This interface should only be used if a
         * Loader is not being used in conjunction with LoaderManager.
         * Loader加载完成接口,当加载完成时Loader通知
         * loaderManager,loaderManager再回调我们initLoader方法的callback
    */
        public interface OnLoadCompleteListener<D> {
            /**
             * Called on the thread that created the Loader when the load is complete.
             *
             * @param loader the loader that completed the load
             * @param data the result of the load
             */
            public void onLoadComplete(Loader<D> loader, D data);
        }
    
        /**
         * Interface that is implemented to discover when a Loader has been canceled
         * before it finished loading its data.  You do not normally need to implement
         * this yourself; it is used in the implementation of {@link android.app.LoaderManager}
         * to find out when a Loader it is managing has been canceled so that it
         * can schedule the next Loader.  This interface should only be used if a
         * Loader is not being used in conjunction with LoaderManager.
         */
        public interface OnLoadCanceledListener<D> {
            /**
             * Called on the thread that created the Loader when the load is canceled.
             *
             * @param loader the loader that canceled the load
             */
            public void onLoadCanceled(Loader<D> loader);
        }
    
        /**
         * Stores away the application context associated with context.
         * Since Loaders can be used across multiple activities it's dangerous to
         * store the context directly; always use {@link #getContext()} to retrieve
         * the Loader's Context, don't use the constructor argument directly.
         * The Context returned by {@link #getContext} is safe to use across
         * Activity instances.
         *
         * @param context used to retrieve the application context.
         */
        public Loader(Context context) {
            mContext = context.getApplicationContext();
        }
    
        /**
         * Sends the result of the load to the registered listener. Should only be called by subclasses.
         *
         * Must be called from the process's main thread.
         *
         * @param data the result of the load
         */
    //加载完成时回调传递加载数据结果,实质是对OnLoadCompleteListener接口方法的封装
        public void deliverResult(D data) {
            if (mListener != null) {
                mListener.onLoadComplete(this, data);
            }
        }
    
        /**
         * Informs the registered {@link OnLoadCanceledListener} that the load has been canceled.
         * Should only be called by subclasses.
         *
         * Must be called from the process's main thread.
         */
        public void deliverCancellation() {
            if (mOnLoadCanceledListener != null) {
                mOnLoadCanceledListener.onLoadCanceled(this);
            }
        }
    
        /**
         * @return an application context retrieved from the Context passed to the constructor.
         */
        public Context getContext() {
            return mContext;
        }
    
        /**
         * @return the ID of this loader
         */
        public int getId() {
            return mId;
        }
    
        /**
         * Registers a class that will receive callbacks when a load is complete.
         * The callback will be called on the process's main thread so it's safe to
         * pass the results to widgets.
         *
         * <p>Must be called from the process's main thread.
         */
        public void registerListener(int id, OnLoadCompleteListener<D> listener) {
            if (mListener != null) {
                throw new IllegalStateException("There is already a listener registered");
            }
            mListener = listener;
            mId = id;
        }
    
        /**
         * Remove a listener that was previously added with {@link #registerListener}.
         *
         * Must be called from the process's main thread.
         */
        public void unregisterListener(OnLoadCompleteListener<D> listener) {
            if (mListener == null) {
                throw new IllegalStateException("No listener register");
            }
            if (mListener != listener) {
                throw new IllegalArgumentException("Attempting to unregister the wrong listener");
            }
            mListener = null;
        }
    
        /**
         * Registers a listener that will receive callbacks when a load is canceled.
         * The callback will be called on the process's main thread so it's safe to
         * pass the results to widgets.
         *
         * Must be called from the process's main thread.
         *
         * @param listener The listener to register.
         */
        public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
            if (mOnLoadCanceledListener != null) {
                throw new IllegalStateException("There is already a listener registered");
            }
            mOnLoadCanceledListener = listener;
        }
    
        /**
         * Unregisters a listener that was previously added with
         * {@link #registerOnLoadCanceledListener}.
         *
         * Must be called from the process's main thread.
         *
         * @param listener The listener to unregister.
         */
        public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
            if (mOnLoadCanceledListener == null) {
                throw new IllegalStateException("No listener register");
            }
            if (mOnLoadCanceledListener != listener) {
                throw new IllegalArgumentException("Attempting to unregister the wrong listener");
            }
            mOnLoadCanceledListener = null;
        }
    
        /**
         * Return whether this load has been started.  That is, its {@link #startLoading()}
         * has been called and no calls to {@link #stopLoading()} or
         * {@link #reset()} have yet been made.
         */
        public boolean isStarted() {
            return mStarted;
        }
    
        /**
         * Return whether this loader has been abandoned.  In this state, the
         * loader <em>must not</em> report any new data, and <em>must</em> keep
         * its last reported data valid until it is finally reset.
         */
        public boolean isAbandoned() {
            return mAbandoned;
        }
    
        /**
         * Return whether this load has been reset.  That is, either the loader
         * has not yet been started for the first time, or its {@link #reset()}
         * has been called.
         */
        public boolean isReset() {
            return mReset;
        }
    
        /**
         * This function will normally be called for you automatically by
         * {@link android.app.LoaderManager} when the associated fragment/activity
         * is being started.  When using a Loader with {@link android.app.LoaderManager},
         * you <em>must not</em> call this method yourself, or you will conflict
         * with its management of the Loader.
         *
         * Starts an asynchronous load of the Loader's data. When the result
         * is ready the callbacks will be called on the process's main thread.
         * If a previous load has been completed and is still valid
         * the result may be passed to the callbacks immediately.
         * The loader will monitor the source of
         * the data set and may deliver future callbacks if the source changes.
         * Calling {@link #stopLoading} will stop the delivery of callbacks.
         *
         * <p>This updates the Loader's internal state so that
         * {@link #isStarted()} and {@link #isReset()} will return the correct
         * values, and then calls the implementation's {@link #onStartLoading()}.
         *
         * <p>Must be called from the process's main thread.
         */
        public final void startLoading() {
            mStarted = true;
            mReset = false;
            mAbandoned = false;
            onStartLoading();
        }
    
        /**
         * Subclasses must implement this to take care of loading their data,
         * as per {@link #startLoading()}.  This is not called by clients directly,
         * but as a result of a call to {@link #startLoading()}.
         */
       //真正开始加载数据的地方-----空方法,子类实现
        protected void onStartLoading() {
        }
    
        /**
         * Attempt to cancel the current load task.
         * Must be called on the main thread of the process.
         *
         * <p>Cancellation is not an immediate operation, since the load is performed
         * in a background thread.  If there is currently a load in progress, this
         * method requests that the load be canceled, and notes this is the case;
         * once the background thread has completed its work its remaining state
         * will be cleared.  If another load request comes in during this time,
         * it will be held until the canceled load is complete.
         *
         * @return Returns <tt>false</tt> if the task could not be canceled,
         * typically because it has already completed normally, or
         * because {@link #startLoading()} hasn't been called; returns
         * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
         * is still running and the {@link OnLoadCanceledListener} will be called
         * when the task completes.
         */
        public boolean cancelLoad() {
            return onCancelLoad();
        }
    
        /**
         * Subclasses must implement this to take care of requests to {@link #cancelLoad()}.
         * This will always be called from the process's main thread.
         *
         * @return Returns <tt>false</tt> if the task could not be canceled,
         * typically because it has already completed normally, or
         * because {@link #startLoading()} hasn't been called; returns
         * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
         * is still running and the {@link OnLoadCanceledListener} will be called
         * when the task completes.
         */
        //真正取消的地方-----,子类实现!!!!!!return false表示取消失败(已完成或未开始)
        protected boolean onCancelLoad() {
            return false;
        }
    
        /**
         * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
         * loaded data set and load a new one.  This simply calls through to the
         * implementation's {@link #onForceLoad()}.  You generally should only call this
         * when the loader is started -- that is, {@link #isStarted()} returns true.
         *
         * <p>Must be called from the process's main thread.
         */
        public void forceLoad() {
            onForceLoad();
        }
    
        /**
         * Subclasses must implement this to take care of requests to {@link #forceLoad()}.
         * This will always be called from the process's main thread.
         */
        protected void onForceLoad() {
        }
    
        /**
         * This function will normally be called for you automatically by
         * {@link android.app.LoaderManager} when the associated fragment/activity
         * is being stopped.  When using a Loader with {@link android.app.LoaderManager},
         * you <em>must not</em> call this method yourself, or you will conflict
         * with its management of the Loader.
         *
         * <p>Stops delivery of updates until the next time {@link #startLoading()} is called.
         * Implementations should <em>not</em> invalidate their data at this point --
         * clients are still free to use the last data the loader reported.  They will,
         * however, typically stop reporting new data if the data changes; they can
         * still monitor for changes, but must not report them to the client until and
         * if {@link #startLoading()} is later called.
         *
         * <p>This updates the Loader's internal state so that
         * {@link #isStarted()} will return the correct
         * value, and then calls the implementation's {@link #onStopLoading()}.
         *
         * <p>Must be called from the process's main thread.
         */
        public void stopLoading() {
            mStarted = false;
            onStopLoading();
        }
    
        /**
         * Subclasses must implement this to take care of stopping their loader,
         * as per {@link #stopLoading()}.  This is not called by clients directly,
         * but as a result of a call to {@link #stopLoading()}.
         * This will always be called from the process's main thread.
         */
        protected void onStopLoading() {
        }
    
        /**
         * This function will normally be called for you automatically by
         * {@link android.app.LoaderManager} when restarting a Loader.  When using
         * a Loader with {@link android.app.LoaderManager},
         * you <em>must not</em> call this method yourself, or you will conflict
         * with its management of the Loader.
         *
         * Tell the Loader that it is being abandoned.  This is called prior
         * to {@link #reset} to have it retain its current data but not report
         * any new data.
         */
        public void abandon() {
            mAbandoned = true;
            onAbandon();
        }
        
        /**
         * Subclasses implement this to take care of being abandoned.  This is
         * an optional intermediate state prior to {@link #onReset()} -- it means that
         * the client is no longer interested in any new data from the loader,
         * so the loader must not report any further updates.  However, the
         * loader <em>must</em> keep its last reported data valid until the final
         * {@link #onReset()} happens.  You can retrieve the current abandoned
         * state with {@link #isAbandoned}.
         */
        protected void onAbandon() {
        }
        
        /**
         * This function will normally be called for you automatically by
         * {@link android.app.LoaderManager} when destroying a Loader.  When using
         * a Loader with {@link android.app.LoaderManager},
         * you <em>must not</em> call this method yourself, or you will conflict
         * with its management of the Loader.
         *
         * Resets the state of the Loader.  The Loader should at this point free
         * all of its resources, since it may never be called again; however, its
         * {@link #startLoading()} may later be called at which point it must be
         * able to start running again.
         *
         * <p>This updates the Loader's internal state so that
         * {@link #isStarted()} and {@link #isReset()} will return the correct
         * values, and then calls the implementation's {@link #onReset()}.
         *
         * <p>Must be called from the process's main thread.
         */
        public void reset() {
            onReset();
            mReset = true;
            mStarted = false;
            mAbandoned = false;
            mContentChanged = false;
            mProcessingChange = false;
        }
    
        /**
         * Subclasses must implement this to take care of resetting their loader,
         * as per {@link #reset()}.  This is not called by clients directly,
         * but as a result of a call to {@link #reset()}.
         * This will always be called from the process's main thread.
         */
        protected void onReset() {
        }
    
        /**
         * Take the current flag indicating whether the loader's content had
         * changed while it was stopped.  If it had, true is returned and the
         * flag is cleared.
         */
        public boolean takeContentChanged() {
            boolean res = mContentChanged;
            mContentChanged = false;
            mProcessingChange |= res;
            return res;
        }
    
        /**
         * Commit that you have actually fully processed a content change that
         * was returned by {@link #takeContentChanged}.  This is for use with
         * {@link #rollbackContentChanged()} to handle situations where a load
         * is cancelled.  Call this when you have completely processed a load
         * without it being cancelled.
         */
        public void commitContentChanged() {
            mProcessingChange = false;
        }
    
        /**
         * Report that you have abandoned the processing of a content change that
         * was returned by {@link #takeContentChanged()} and would like to rollback
         * to the state where there is again a pending content change.  This is
         * to handle the case where a data load due to a content change has been
         * canceled before its data was delivered back to the loader.
         */
        public void rollbackContentChanged() {
            if (mProcessingChange) {
                onContentChanged();
            }
        }
    
        /**
         * Called when {@link ForceLoadContentObserver} detects a change.  The
         * default implementation checks to see if the loader is currently started;
         * if so, it simply calls {@link #forceLoad()}; otherwise, it sets a flag
         * so that {@link #takeContentChanged()} returns true.
         *
         * <p>Must be called from the process's main thread.
         */
        //上面ForceLoadContentObserver内部类的onChange方法调运
        public void onContentChanged() {
            if (mStarted) {
                forceLoad();
            } else {
                // This loader has been stopped, so we don't want to load
                // new data right now...  but keep track of it changing to
                // refresh later if we start again.
                mContentChanged = true;
            }
        }
    
        /**
         * For debugging, converts an instance of the Loader's data class to
         * a string that can be printed.  Must handle a null data.
         */
        public String dataToString(D data) {
            StringBuilder sb = new StringBuilder(64);
            DebugUtils.buildShortClassTag(data, sb);
            sb.append("}");
            return sb.toString();
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder(64);
            DebugUtils.buildShortClassTag(this, sb);
            sb.append(" id=");
            sb.append(mId);
            sb.append("}");
            return sb.toString();
        }
    
        /**
         * Print the Loader's state into the given stream.
         *
         * @param prefix Text to print at the front of each line.
         * @param fd The raw file descriptor that the dump is being sent to.
         * @param writer A PrintWriter to which the dump is to be set.
         * @param args Additional arguments to the dump request.
         */
        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
            writer.print(prefix); writer.print("mId="); writer.print(mId);
                    writer.print(" mListener="); writer.println(mListener);
            if (mStarted || mContentChanged || mProcessingChange) {
                writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
                        writer.print(" mContentChanged="); writer.print(mContentChanged);
                        writer.print(" mProcessingChange="); writer.println(mProcessingChange);
            }
            if (mAbandoned || mReset) {
                writer.print(prefix); writer.print("mAbandoned="); writer.print(mAbandoned);
                        writer.print(" mReset="); writer.println(mReset);
            }
        }
    }
    

    通过上面粗略的分析可以发现,Loader基类无非也就是一个方法接口的定义类,组织预留了一些方法供LoaderManager去调运处理,同时需要子类实现其提供的一些onXXX方法,以便LoaderManager调运Loader的方法时可以触发Loader子类的实现逻辑。

    AsyncTaskLoader抽象子类源码#####
    public abstract class AsyncTaskLoader<D> extends Loader<D> {
        static final String TAG = "AsyncTaskLoader";
        static final boolean DEBUG = false;
      //LoadTask内部类是对AsyncTask的封装,实现了Runnable接口
        final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
            private final CountDownLatch mDone = new CountDownLatch(1);
    
            // Set to true to indicate that the task has been posted to a handler for
            // execution at a later time.  Used to throttle updates.
            boolean waiting;
    
           //AsyncTask的子线程中执行AsyncTaskLoader的onLoadInBackground方法!!!!
            /* Runs on a worker thread */
            @Override
            protected D doInBackground(Void... params) {
                if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
                try {
                    D data = AsyncTaskLoader.this.onLoadInBackground();
                    if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
               //把执行结果数据D返回到UI线程
                    return data;
                } catch (OperationCanceledException ex) {
                    if (!isCancelled()) {
                        // onLoadInBackground threw a canceled exception spuriously.
                        // This is problematic because it means that the LoaderManager did not
                        // cancel the Loader itself and still expects to receive a result.
                        // Additionally, the Loader's own state will not have been updated to
                        // reflect the fact that the task was being canceled.
                        // So we treat this case as an unhandled exception.
                        throw ex;
                    }
                    if (DEBUG) Log.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
                    return null;
                }
            }
    
            /* Runs on the UI thread */
            @Override
            protected void onPostExecute(D data) {
                if (DEBUG) Log.v(TAG, this + " onPostExecute");
                try {
              //AsyncTask子线程执行完毕后回调AsyncTaskLoader的dispatchOnLoadComplete方法
                    AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
                } finally {
                    mDone.countDown();
                }
            }
    
            /* Runs on the UI thread */
            @Override
            protected void onCancelled(D data) {
                if (DEBUG) Log.v(TAG, this + " onCancelled");
                try {
            //取消AsyncTask时调运
                    AsyncTaskLoader.this.dispatchOnCancelled(this, data);
                } finally {
                    mDone.countDown();
                }
            }
    
            /* Runs on the UI thread, when the waiting task is posted to a handler.
             * This method is only executed when task execution was deferred (waiting was true). */
          //Runnable的实现方法
            @Override
            public void run() {
                waiting = false;
                AsyncTaskLoader.this.executePendingTask();
            }
    
            /* Used for testing purposes to wait for the task to complete. */
            public void waitForLoader() {
                try {
                    mDone.await();
                } catch (InterruptedException e) {
                    // Ignore
                }
            }
        }
    
        private final Executor mExecutor;
    
        volatile LoadTask mTask;
        volatile LoadTask mCancellingTask;
    
        long mUpdateThrottle;
        long mLastLoadCompleteTime = -10000;
        Handler mHandler;
    
        public AsyncTaskLoader(Context context) {
            this(context, AsyncTask.THREAD_POOL_EXECUTOR);
        }
    
        /** {@hide} */
        public AsyncTaskLoader(Context context, Executor executor) {
            super(context);
            mExecutor = executor;
        }
    
        /**
         * Set amount to throttle updates by.  This is the minimum time from
         * when the last {@link #loadInBackground()} call has completed until
         * a new load is scheduled.
         *
         * @param delayMS Amount of delay, in milliseconds.
         */
        public void setUpdateThrottle(long delayMS) {
            mUpdateThrottle = delayMS;
            if (delayMS != 0) {
                mHandler = new Handler();
            }
        }
    
        @Override
        protected void onForceLoad() {
            super.onForceLoad();
            cancelLoad();
            mTask = new LoadTask();
            if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
            executePendingTask();
        }
    
        @Override
        protected boolean onCancelLoad() {
            if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask);
            if (mTask != null) {
                if (mCancellingTask != null) {
                    // There was a pending task already waiting for a previous
                    // one being canceled; just drop it.
                    if (DEBUG) Log.v(TAG,
                            "cancelLoad: still waiting for cancelled task; dropping next");
                    if (mTask.waiting) {
                        mTask.waiting = false;
                        mHandler.removeCallbacks(mTask);
                    }
                    mTask = null;
                    return false;
                } else if (mTask.waiting) {
                    // There is a task, but it is waiting for the time it should
                    // execute.  We can just toss it.
                    if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it");
                    mTask.waiting = false;
                    mHandler.removeCallbacks(mTask);
                    mTask = null;
                    return false;
                } else {
                    boolean cancelled = mTask.cancel(false);
                    if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled);
                    if (cancelled) {
                        mCancellingTask = mTask;
                        cancelLoadInBackground();
                    }
                    mTask = null;
                    return cancelled;
                }
            }
            return false;
        }
    
        /**
         * Called if the task was canceled before it was completed.  Gives the class a chance
         * to clean up post-cancellation and to properly dispose of the result.
         *
         * @param data The value that was returned by {@link #loadInBackground}, or null
         * if the task threw {@link OperationCanceledException}.
         */
        public void onCanceled(D data) {
        }
     //LoadTask的Runnable方法run中执行
        void executePendingTask() {
            if (mCancellingTask == null && mTask != null) {
                if (mTask.waiting) {
                    mTask.waiting = false;
                    mHandler.removeCallbacks(mTask);
                }
                if (mUpdateThrottle > 0) {
                    long now = SystemClock.uptimeMillis();
                    if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {
                        // Not yet time to do another load.
                        if (DEBUG) Log.v(TAG, "Waiting until "
                                + (mLastLoadCompleteTime+mUpdateThrottle)
                                + " to execute: " + mTask);
                        mTask.waiting = true;
                        mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
                        return;
                    }
                }
                if (DEBUG) Log.v(TAG, "Executing: " + mTask);
               //真正的触发执行AsyncTask方法
                mTask.executeOnExecutor(mExecutor, (Void[]) null);
            }
        }
    
        void dispatchOnCancelled(LoadTask task, D data) {
            onCanceled(data);
            if (mCancellingTask == task) {
                if (DEBUG) Log.v(TAG, "Cancelled task is now canceled!");
                rollbackContentChanged();
                mLastLoadCompleteTime = SystemClock.uptimeMillis();
                mCancellingTask = null;
                if (DEBUG) Log.v(TAG, "Delivering cancellation");
                //触发Loader的接口方法onLoadCanceled,在LoaderManager中实现
                deliverCancellation();
                executePendingTask();
            }
        }
    
        void dispatchOnLoadComplete(LoadTask task, D data) {
            if (mTask != task) {
                if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel");
                dispatchOnCancelled(task, data);
            } else {
                if (isAbandoned()) {
                    // This cursor has been abandoned; just cancel the new data.
                    onCanceled(data);
                } else {
                    commitContentChanged();
                    mLastLoadCompleteTime = SystemClock.uptimeMillis();
                    mTask = null;
                    if (DEBUG) Log.v(TAG, "Delivering result");
                  //触发Loader的接口方法onLoadComplete,在LoaderManager中实现
                    deliverResult(data);
                }
            }
        }
    
        /**
         * Called on a worker thread to perform the actual load and to return
         * the result of the load operation.
         *
         * Implementations should not deliver the result directly, but should return them
         * from this method, which will eventually end up calling {@link #deliverResult} on
         * the UI thread.  If implementations need to process the results on the UI thread
         * they may override {@link #deliverResult} and do so there.
         *
         * To support cancellation, this method should periodically check the value of
         * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
         * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
         * directly instead of polling {@link #isLoadInBackgroundCanceled}.
         *
         * When the load is canceled, this method may either return normally or throw
         * {@link OperationCanceledException}.  In either case, the {@link Loader} will
         * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
         * result object, if any.
         *
         * @return The result of the load operation.
         *
         * @throws OperationCanceledException if the load is canceled during execution.
         *
         * @see #isLoadInBackgroundCanceled
         * @see #cancelLoadInBackground
         * @see #onCanceled
         */
        //需要子类实现!!!!!在子线程中执行
        public abstract D loadInBackground();
    
        /**
         * Calls {@link #loadInBackground()}.
         *
         * This method is reserved for use by the loader framework.
         * Subclasses should override {@link #loadInBackground} instead of this method.
         *
         * @return The result of the load operation.
         *
         * @throws OperationCanceledException if the load is canceled during execution.
         *
         * @see #loadInBackground
         */
      //LoadTask(AsyncTask的子线程中回调)中调运
        protected D onLoadInBackground() {
            return loadInBackground();
        }
    
        /**
         * Called on the main thread to abort a load in progress.
         *
         * Override this method to abort the current invocation of {@link #loadInBackground}
         * that is running in the background on a worker thread.
         *
         * This method should do nothing if {@link #loadInBackground} has not started
         * running or if it has already finished.
         *
         * @see #loadInBackground
         */
        public void cancelLoadInBackground() {
        }
    
        /**
         * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
         *
         * @return True if the current invocation of {@link #loadInBackground} is being canceled.
         *
         * @see #loadInBackground
         */
        public boolean isLoadInBackgroundCanceled() {
            return mCancellingTask != null;
        }
    
        /**
         * Locks the current thread until the loader completes the current load
         * operation. Returns immediately if there is no load operation running.
         * Should not be called from the UI thread: calling it from the UI
         * thread would cause a deadlock.
         * <p>
         * Use for testing only.  <b>Never</b> call this from a UI thread.
         *
         * @hide
         */
        public void waitForLoader() {
            LoadTask task = mTask;
            if (task != null) {
                task.waitForLoader();
            }
        }
    
        @Override
        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
            super.dump(prefix, fd, writer, args);
            if (mTask != null) {
                writer.print(prefix); writer.print("mTask="); writer.print(mTask);
                        writer.print(" waiting="); writer.println(mTask.waiting);
            }
            if (mCancellingTask != null) {
                writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask);
                        writer.print(" waiting="); writer.println(mCancellingTask.waiting);
            }
            if (mUpdateThrottle != 0) {
                writer.print(prefix); writer.print("mUpdateThrottle=");
                        TimeUtils.formatDuration(mUpdateThrottle, writer);
                        writer.print(" mLastLoadCompleteTime=");
                        TimeUtils.formatDuration(mLastLoadCompleteTime,
                                SystemClock.uptimeMillis(), writer);
                        writer.println();
            }
        }
    }
    

    上面继承Loader的AsyncTaskLoader其实质是提供了一个基于AsyncTask工作机制的Loader(子类LoadTask继承AsyncTask<Void, Void, D>,并且实现了Runable接口,功能十分强大。),但是不可直接用,因为其为abstract抽象类,所以我们需要继承实现它才可以使用,然而好在系统API已经帮我们提供了他现成的子类CursorLoader,但CursorLoader同时也限制了Loader的泛型数据为Cursor类型。

    public class CursorLoader extends AsyncTaskLoader<Cursor> {
        final ForceLoadContentObserver mObserver;
    
        Uri mUri;
        String[] mProjection;
        String mSelection;
        String[] mSelectionArgs;
        String mSortOrder;
    
        Cursor mCursor;
        CancellationSignal mCancellationSignal;
    
        /* Runs on a worker thread */
    //最核心的实现方法,在这里查询获取数据
        @Override
        public Cursor loadInBackground() {
            synchronized (this) {
                if (isLoadInBackgroundCanceled()) {
                    throw new OperationCanceledException();
                }
                mCancellationSignal = new CancellationSignal();
            }
            try {
              //耗时的查询操作
                Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
                        mSelectionArgs, mSortOrder, mCancellationSignal);
                if (cursor != null) {
                    try {
                        // Ensure the cursor window is filled.
                        cursor.getCount();
    /*给Cursor设置观察者;
    * ContentProvider通知Cursor的观察者数据发生了改变,
    * Cursor通知CursorLoader的观察者数据发生了改变,CursorLoader通过
    * ContentProvider重新加载新的数据*/
                        cursor.registerContentObserver(mObserver);
                    } catch (RuntimeException ex) {
                        cursor.close();
                        throw ex;
                    }
                }
                return cursor;
            } finally {
                synchronized (this) {
                    mCancellationSignal = null;
                }
            }
        }
    
        @Override
        public void cancelLoadInBackground() {
            super.cancelLoadInBackground();
    
            synchronized (this) {
                if (mCancellationSignal != null) {
                    mCancellationSignal.cancel();
                }
            }
        }
    
        /* Runs on the UI thread */
        @Override
        public void deliverResult(Cursor cursor) {
            if (isReset()) {
                // An async query came in while the loader is stopped
                if (cursor != null) {
                    cursor.close();
                }
                return;
            }
            Cursor oldCursor = mCursor;
            mCursor = cursor;
    
            if (isStarted()) {
                super.deliverResult(cursor);
            }
    
            if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
                oldCursor.close();
            }
        }
    
        /**
         * Creates an empty unspecified CursorLoader.  You must follow this with
         * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
         * to specify the query to perform.
         */
        public CursorLoader(Context context) {
            super(context);
            mObserver = new ForceLoadContentObserver();
        }
    
        /**
         * Creates a fully-specified CursorLoader.  See
         * {@link ContentResolver#query(Uri, String[], String, String[], String)
         * ContentResolver.query()} for documentation on the meaning of the
         * parameters.  These will be passed as-is to that call.
         */
        public CursorLoader(Context context, Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            super(context);
    /*新建一个当前类(Loader)的内部类对象,数据库变化时调运
    * ForceLoadContentObserver的onChange方法,onChange调运Loader的
    * onContentChanged方法,onContentChanged调运Loader的forceLoad方法*/
            mObserver = new ForceLoadContentObserver();
            mUri = uri;
            mProjection = projection;
            mSelection = selection;
            mSelectionArgs = selectionArgs;
            mSortOrder = sortOrder;
        }
    
        /**
         * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
         * will be called on the UI thread. If a previous load has been completed and is still valid
         * the result may be passed to the callbacks immediately.
         *
         * Must be called from the UI thread
         */
        @Override
        protected void onStartLoading() {
            if (mCursor != null) {
                deliverResult(mCursor);
            }
            if (takeContentChanged() || mCursor == null) {
                forceLoad();
            }
        }
    
        /**
         * Must be called from the UI thread
         */
        @Override
        protected void onStopLoading() {
            // Attempt to cancel the current load task if possible.
            cancelLoad();
        }
    
        @Override
        public void onCanceled(Cursor cursor) {
            if (cursor != null && !cursor.isClosed()) {
                cursor.close();
            }
        }
    
        @Override
        protected void onReset() {
            super.onReset();
            
            // Ensure the loader is stopped
            onStopLoading();
    
            if (mCursor != null && !mCursor.isClosed()) {
                mCursor.close();
            }
            mCursor = null;
        }
    
        public Uri getUri() {
            return mUri;
        }
    
        public void setUri(Uri uri) {
            mUri = uri;
        }
    
        public String[] getProjection() {
            return mProjection;
        }
    
        public void setProjection(String[] projection) {
            mProjection = projection;
        }
    
        public String getSelection() {
            return mSelection;
        }
    
        public void setSelection(String selection) {
            mSelection = selection;
        }
    
        public String[] getSelectionArgs() {
            return mSelectionArgs;
        }
    
        public void setSelectionArgs(String[] selectionArgs) {
            mSelectionArgs = selectionArgs;
        }
    
        public String getSortOrder() {
            return mSortOrder;
        }
    
        public void setSortOrder(String sortOrder) {
            mSortOrder = sortOrder;
        }
    
        @Override
        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
            super.dump(prefix, fd, writer, args);
            writer.print(prefix); writer.print("mUri="); writer.println(mUri);
            writer.print(prefix); writer.print("mProjection=");
                    writer.println(Arrays.toString(mProjection));
            writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);
            writer.print(prefix); writer.print("mSelectionArgs=");
                    writer.println(Arrays.toString(mSelectionArgs));
            writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);
            writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);
            writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged);
        }
    }
    

    CursorLoader的封装大大简化了应用开发者代码的复杂度;它完全就是一个异步的数据库查询工具。

    Loaders相关总结###

    • 一次完整的数据加载流程为Activity调用LoaderManager的doStart()方法,然后LoaderManager调用Loader的startLoading()方法,然后Loader调运AsyncTaskLoader的doingBackground()方法进行耗时数据加载,然后AsyncTaskLoader回调LoaderManager的complete数据加载完成方法,接着LoaderManager回调我们在Activity中实现的callback中的onLoadFinish()方法。

    • Acivity和Fragment的生命周期主动管理了LoaderManager,每个Activity用一个ArrayMap的mAllLoaderManager来保存当前Activity及其附属Frament的唯一LoaderManager;在Activity配置发生变化时,Activity在destory前会保存mAllLoaderManager,当Activity再重新创建时,会在Activity的onAttcach()、onCreate()、performStart()方法中恢复mAllLoaderManager。

    • 由于整个Activity和Fragment主动管理了Loader,所以关于Loader的释放(譬如CursorLoader的Cursor关闭等)不需要我们人为处理,Loader框架会帮我们很好的处理的;同时特别注意,对于CursorLoader,当我们数据源发生变化时Loader框架会通过ContentObserver调用onContentChanged的forceLoad方法重新请求数据进行回调刷新。

    细节点睛
    • 对于毕竟敏感操作的cursor,AsyncTaskLoader在封装中onPostExecute方法内,完成数据操作之后就对应的通过dispatchOnLoadComplete调用父类Loader中的deliverResult方法,CursorLoader子类实现了这个方法,便在里面做出了对cursor的关闭操作。

    ——未完待续#

    参考以及引用资料:
    1、Google Loader官方指导文档
    2、Loader源码解析
    3、LoaderManager详解

    相关文章

      网友评论

        本文标题:关于Android的Loader相关

        本文链接:https://www.haomeiwen.com/subject/jxsqattx.html