loader机制

loader机制

一. 概述

  • 对每个activity或者fragment都有效
  • 提供了异步加载数据的能力
  • 监视数据源并在内容改变的时候传递新的结果
  • 在Activity配置发生变化(如横竖屏切换)时不重复加载数据
  • Loader一般用在Activity和fragment异步加载数据,无需重新启动一个线程来执行数据加载,异步加载可以用asyncTask, 但是loader自带数据结果监听机制,可以方便优雅的进行UI更新

相关类

LoaderManager
每个activity或者fragment都只有一个LoaderManager,但是一个LoaderManager可以管理多个Loader

LoaderCallbacks
客户端用于和LoaderManager交互的回调接口

Loader
加载器的基类

AyncTaskLoader
提供一个AsyncTask来执行异步任务的抽象类

CursorLoader
AyncTaskLoader的子类,它查询ContentResolver然后返回一个Cursor,是从一个ContentProvider异步加载数据的最好方式。

二. 启动Loader

getLoaderManager().initLoader(id,args, callback);  
  • id:用来标志loader
  • args:可选参数,用于loader的初始化
  • callback:回调
    initLoader保证一个loader被激活,它可能有两种结果
    一种是:id所指示的loader已经存在,那么这个loader将被重用
    另一种是:loader不存在,会触发callback的onCreateLoader方法。

三.重启和回调

重启

 getLoaderManager().restartLoader(id, args, callback);  

回调

onCreateLoader
onLoadFinished
onLoaderReset

四. 应用

public static class CursorLoaderListFragment extends ListFragment
        implements OnQueryTextListener, LoaderManager.LoaderCallbacks {

    // 这是用于显示列表数据的Adapter
    SimpleCursorAdapter mAdapter;

    // 如果非null,这是当前的搜索过虑器
    String mCurFilter;

    @Override public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // 如果列表中没有数据,就给控件一些文字去显示.在一个真正的应用
        // 中这应用资源中取得.
        setEmptyText("No phone numbers");

        // 我们在动作栏中有一个菜单项.
        setHasOptionsMenu(true);

        // 创建一个空的adapter,我们将用它显示加载后的数据
        mAdapter = new SimpleCursorAdapter(getActivity(),
                android.R.layout.simple_list_item_2, null,
                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
                new int[] { android.R.id.text1, android.R.id.text2 }, 0);
        setListAdapter(mAdapter);

        // 准备loader.可能是重连到一个已存在的或开始一个新的
        getLoaderManager().initLoader(0, null, this);
    }

    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // 放置一个动作栏项用于搜索.
        MenuItem item = menu.add("Search");
        item.setIcon(android.R.drawable.ic_menu_search);
        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        SearchView sv = new SearchView(getActivity());
        sv.setOnQueryTextListener(this);
        item.setActionView(sv);
    }

    public boolean onQueryTextChange(String newText) {
        // 在动作栏上的搜索字串改变时被调用.更新
        //搜索过滤器,并重启loader来执行一个新的查询
        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
        getLoaderManager().restartLoader(0, null, this);
        return true;
    }

    @Override public boolean onQueryTextSubmit(String query) {
        // 我们不关心这个方法
        return true;
    }

    @Override public void onListItemClick(ListView l, View v, int position, long id) {
        // 写入你想写的代码
        Log.i("FragmentComplexList", "Item clicked: " + id);
    }

    // 这是我们想获取的联系人中一行的数据.
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
        Contacts._ID,
        Contacts.DISPLAY_NAME,
        Contacts.CONTACT_STATUS,
        Contacts.CONTACT_PRESENCE,
        Contacts.PHOTO_ID,
        Contacts.LOOKUP_KEY,
    };
    public Loader onCreateLoader(int id, Bundle args) {
        // 当一个新的loader需被创建时调用.本例仅有一个Loader,
        //所以我们不需关心ID.首先设置base URI,URI指向的是联系人
        Uri baseUri;
        if (mCurFilter != null) {
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                    Uri.encode(mCurFilter));
        } else {
            baseUri = Contacts.CONTENT_URI;
        }

        // 现在创建并返回一个CursorLoader,它将负责创建一个
        // Cursor用于显示数据
        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");
    }

    public void onLoadFinished(Loader loader, Cursor data) {
        // 将新的cursor换进来.(框架将在我们返回时关心一下旧cursor的关闭)
        mAdapter.swapCursor(data);
    }

    public void onLoaderReset(Loader loader) {
        //在最后一个Cursor准备进入上面的onLoadFinished()之前.
        // Cursor要被关闭了,我们需要确保不再使用它.
        mAdapter.swapCursor(null);
    }
}

利用loader查询通讯录

public class MainActivity extends ListActivity implements LoaderManager.LoaderCallbacks, SearchView.OnQueryTextListener {
private  SimpleCursorAdapter cursorAdapter;
    private String filterName=null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv= (TextView) findViewById(android.R.id.empty);
        tv.setText("请稍后");
 
        cursorAdapter=new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_2,
                null,
                new String[]{ContactsContract.Contacts.DISPLAY_NAME},
                new int[]{android.R.id.text1},0);
         setListAdapter(cursorAdapter);
        //初始化Loader
          getLoaderManager().initLoader(0,null,this);
    }
 
 
    @Override
    public Loader onCreateLoader(int id, Bundle args) {
        Uri uri;
        String[] pro=new String[]{ ContactsContract.Contacts.DISPLAY_NAME,ContactsContract.Contacts._ID};
        if(TextUtils.isEmpty(filterName)){
            uri= ContactsContract.Contacts.CONTENT_URI;
        }else{
            uri=Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,Uri.encode(filterName));
        }
        //创建Loader对象,开始异步加载数据
        return new CursorLoader(this,uri,pro, null, null,null);
    }
 
    @Override
    public void onLoadFinished(Loader loader, Cursor data) {
        //得到异步加载数据,更新Adapter
        cursorAdapter.swapCursor(data);
    }
 
    @Override
    public void onLoaderReset(Loader loader) {
        //移除adapter使用的Loader,系统会释放不再使用的Loader
        cursorAdapter.swapCursor(null);
    }
 
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main,menu);
        SearchView v= (SearchView) menu.findItem(R.id.menu_search).getActionView();
        v.setOnQueryTextListener(this);
        return true;
    }
 
    @Override
    public boolean onQueryTextSubmit(String query) {
        return true;
    }
 
    @Override
    public boolean onQueryTextChange(String newText) {
        filterName=newText;
        //使用新的Loader(清空旧的数据)
        getLoaderManager().restartLoader(0,null,this);
        return false;
    }
}

应用列表的获取

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();
    }
}
public static class AppListLoader extends AsyncTaskLoader> {
    final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
    final PackageManager mPm;

    List 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 loadInBackground() {
        // Retrieve all known applications.
        List apps = mPm
                .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
                        | PackageManager.GET_DISABLED_COMPONENTS);
        if (apps == null) {
            apps = new ArrayList();
        }

        final Context context = getContext();

        // Create corresponding array of entries and load their labels.
        List entries = new ArrayList(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 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 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 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 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方法了

五.源码分析

5.1 getLoaderManager的源码:每个activity和fragment都对应一个LoaderManager。

fragment getLoaderManager的源码

fragment的getLoaderManager也是通过activity的getLoader去调用的

//这边就能看出来一个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;
}

activity中getLoaderManager的源码

**结论:
**真正的loadermanager都是存储在activity中的,包括fragment的loadermanager也是,通过一个map来保证 get的时候取的manager是自己对应的,并且全局唯一

//在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();
        }
        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;
    }

5.2 回调发生关系的源码(LoaderManger与LoaderCallback的联系)

//这个就是现在存活的loader
final SparseArray mLoaders = new SparseArray(0);

//这个是已经运行结束的loader
final SparseArray mInactiveLoaders = new SparseArray(0);

public  Loader initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks 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)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)callback;
        } 
        if (info.mHaveData && mStarted) {
            // If the loader has already generated its data, report it now.
            info.callOnLoadFinished(info.mLoader, info.mData);
        } 
        return (Loader)info.mLoader;
    }

//其实这个创建loader的过程特别简单,我们主要看第三个参数,callback 这个参数
//一想就明白,在前面3个demo里我们是直接在fragemet和activity里实现的callback
//所以传进去的就是this,也就是说 回调就是在这个函数里 真正的和loader 发生了关联了
private LoaderInfo createAndInstallLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks callback) {
        try {
            mCreatingLoader = true;
            LoaderInfo info = createLoader(id, args, callback);
            installLoader(info);
            return info;
        } finally {
            mCreatingLoader = false;
        }
    }
 
 

5.3 数据观察者

//这个是一个观察者 当发生变化的时候 他调用了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方法了
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;
        }
    }

 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() {
    }

5.4 AsyncTaskLoader加载数据

//这边一目了然 asynacTaskLoader 里面 正好是有一个AsyncTask对象的!实现了runnabele接口
//注意着参数d 这个d是干嘛的,这个d就是用来传递参数的一个泛型,可以是系统实现的loader里的cursor
//也可以是我们自己实现的loader里的list类型
final class LoadTask extends AsyncTask 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;

        /* Runs on a worker thread */
        @Override
        protected D doInBackground(Void... params) {
            if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
            try {
                //这个地方就很明显了,他调用了自己的onLoadInBackGround方法
                D data = AsyncTaskLoader.this.onLoadInBackground();
                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
                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;
            }
        }
        //后面还有很多代码 略过
}

//你看这里下面的2个函数 一看就明白了 最终task里调用的是这个抽象方法,那这个抽象方法
//就是留给我们子类自己去实现的,我们在自定义loader的时候最重要的就是重写这个方法。
 protected D onLoadInBackground() {
        return loadInBackground();
    }

 public abstract D loadInBackground();

//你看这个地方 就是当数据源发生变化的时候 就会调用这个方法了,启动了我们的laodtask 
//也是最终调用子类 也就是CursorLoader这样的子类的loadInBackground方法了
@Override
    protected void onForceLoad() {
        super.onForceLoad();
        cancelLoad();
        mTask = new LoadTask();
        if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
        executePendingTask();
    }


//在那个asynctask里面 走完是肯定要走这个方法的 相信大家都能理解。
        @Override
        protected void onPostExecute(D data) {
            if (DEBUG) Log.v(TAG, this + " onPostExecute");
            try {
                AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
            } finally {
                mDone.countDown();
            }
        }
//实际上走的就是这个方法。看26行-
        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");
                deliverResult(data);
            }
        }
    }

//这边一下就看出来是调用的mListtenr的回调方法
     public void deliverResult(D data) {
        if (mListener != null) {
            mListener.onLoadComplete(this, data);
        }
    }

public interface OnLoadCompleteListener {
        /**
         * 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 loader, D data);
    }

//并且通过这个注册
 public void registerListener(int id, OnLoadCompleteListener listener) {
        if (mListener != null) {
            throw new IllegalStateException("There is already a listener registered");
        }
        mListener = listener;
        mId = id;
    }

5.5 listener的注册和回调

    void installLoader(LoaderInfo info) {
        mLoaders.put(info.mId, info);
        if (mStarted) {
            //跳转到51行
            info.start();
        }
    }

   void start() {
            if (mRetaining && mRetainingStarted) {
                // Our owner is started, but we were being retained from a
                // previous instance in the started state...  so there is really
                // nothing to do here, since the loaders are still started.
                mStarted = true;
                return;
            } 
            if (mStarted) {
                // If loader already started, don't restart.
                return;
            } 
            mStarted = true; 
            if (DEBUG) Log.v(TAG, "  Starting: " + this);
            if (mLoader == null && mCallbacks != null) {
               //回调onCreateLoader
               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
            }
            if (mLoader != null) {
                if (mLoader.getClass().isMemberClass()
                        && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
                    throw new IllegalArgumentException(
                            "Object returned from onCreateLoader must not be a non-static inner member class: "
                            + mLoader);
                }
                if (!mListenerRegistered) {
                    //就是在这里注册的mloader里的回调了,注意这里的参数是this 也就是loaderInfo这个类 注意这个类就是loadermanger里的内部类了 再继续往下看
                    //我们前面说到 在asynctask里面最终调用的是mLoader里的onLoadComplete方法 所以我们就看看loaderInfo这个类里的这个方法做了什么看91行
                    mLoader.registerListener(mId, this);
                    mLoader.registerOnLoadCanceledListener(this);
                    mListenerRegistered = true;
                }
                mLoader.startLoading();
            }
        }

         @Override
        public void onLoadComplete(Loader loader, Object data) {
            if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);

            if (mDestroyed) {
                if (DEBUG) Log.v(TAG, "  Ignoring load complete -- destroyed");
                return;
            }

            if (mLoaders.get(mId) != this) {
                // This data is not coming from the current active loader.
                // We don't care about it.
                if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
                return;
            }

            LoaderInfo pending = mPendingLoader;
            if (pending != null) {
                // There is a new request pending and we were just
                // waiting for the old one to complete before starting
                // it.  So now it is time, switch over to the new loader.
                if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
                mPendingLoader = null;
                mLoaders.put(mId, null);
                destroy();
                installLoader(pending);
                return;
            }

            // Notify of the new data so the app can switch out the old data before
            // we try to destroy it.
            if (mData != data || !mHaveData) {
                mData = data;
                mHaveData = true;
                if (mStarted) {
                    //继续往下 看第149行 
                    callOnLoadFinished(loader, data);
                }
            }

            //if (DEBUG) Log.v(TAG, "  onLoadFinished returned: " + this);

            // We have now given the application the new loader with its
            // loaded data, so it should have stopped using the previous
            // loader.  If there is a previous loader on the inactive list,
            // clean it up.
            LoaderInfo info = mInactiveLoaders.get(mId);
            if (info != null && info != this) {
                info.mDeliveredData = false;
                info.destroy();
                mInactiveLoaders.remove(mId);
            }

            if (mHost != null && !hasRunningLoaders()) {
                mHost.mFragmentManager.startPendingDeferredFragments();
            }
        }

         void callOnLoadFinished(Loader loader, Object data) {
            if (mCallbacks != null) {
                String lastBecause = null;
                if (mHost != null) {
                    lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
                    mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
                }
                try {
                    if (DEBUG) Log.v(TAG, "  onLoadFinished in " + loader + ": "
                            + loader.dataToString(data));
                    //到这里就真相大白了,最终callback是在这里调用的onLoadFinished方法也就是我们经常重写的方法
                    mCallbacks.onLoadFinished(loader, data);
                } finally {
                    if (mHost != null) {
                        mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
                    }
                }
                mDeliveredData = true;
            }
        }
 
 

5.6 activity中声明周期方法里关于loader的源码分析

onStart

/看activity的onStart方法
protected void onStart() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
        mCalled = true;
        //继续看12行 这个地方mFragements 你就理解成activity本身即可,不多做解释 这个地方要搞清楚 又是另外一块了 有兴趣的可以自行谷歌activity和fragment如何建立关系
        mFragments.doLoaderStart();

        getApplication().dispatchActivityStarted(this);
    }

    //这个函数就很明显了 调用了manager的dostart函数
     void doLoaderStart() {
        if (mLoadersStarted) {
            return;
        }
        mLoadersStarted = true;

        if (mLoaderManager != null) {
            //跳转到30行
            mLoaderManager.doStart();
        } else if (!mCheckedForLoaderManager) {
            mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
        }
        mCheckedForLoaderManager = true;
    }

//------------------注意上面的代码都在activity里,下面的开始 都在LoaderManger类里了

     void doStart() {
        if (DEBUG) Log.v(TAG, "Starting in " + this);
        if (mStarted) {
            RuntimeException e = new RuntimeException("here");
            e.fillInStackTrace();
            Log.w(TAG, "Called doStart when already started: " + this, e);
            return;
        }

        mStarted = true;

        // Call out to sub classes so they can start their loaders
        // Let the existing loaders know that we want to be notified when a load is complete
        for (int i = mLoaders.size()-1; i >= 0; i--) {
            //跳转到50行
            mLoaders.valueAt(i).start();
        }
    }

     void start() {
            if (mRetaining && mRetainingStarted) {
                // Our owner is started, but we were being retained from a
                // previous instance in the started state...  so there is really
                // nothing to do here, since the loaders are still started.
                mStarted = true;
                return;
            }

            if (mStarted) {
                // If loader already started, don't restart.
                return;
            }

            mStarted = true;

            if (DEBUG) Log.v(TAG, "  Starting: " + this);
            if (mLoader == null && mCallbacks != null) {
                //原来onCreateLoader这个回调方法 是在这里调用的 怪不得谷歌说这个方法是必定会被执行并且只会被执行一次的方法!
               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
            }
            if (mLoader != null) {
                if (mLoader.getClass().isMemberClass()
                        && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
                    throw new IllegalArgumentException(
                            "Object returned from onCreateLoader must not be a non-static inner member class: "
                            + mLoader);
                }
                if (!mListenerRegistered) {
                    mLoader.registerListener(mId, this);
                    mLoader.registerOnLoadCanceledListener(this);
                    mListenerRegistered = true;
                }
                //你看这里调用了startLoading方法 这个方法是属于mLoader的 跳转到88行
                mLoader.startLoading();
            }
        }

//88- 98行是loader这个类里的
    public final void startLoading() {
        mStarted = true;
        mReset = false;
        mAbandoned = false;
        onStartLoading();
    }

    //你看最终是调用的这个方法,注意他是空方法 是交给子类去实现的,我们去看看cursorloader这个子类是怎么实现的吧。
    protected void onStartLoading() {
    }
//99-  112行 是cursorLoader这个类的代码

//你看这个地方 直接调用了forceload方法 这个方法大家前面肯定有印象  他最终会启动那个asynctask 去执行background方法
//这也就解释了 第一次我们的数据是怎么来的,比如说 假设我们的数据源还没有被更新的时候,为什么会自动去查找数据源 并返回数据
//到这里就明白了,原来是activity的onStart函数为开端 一步步走到Loader的子类的onStartLoading方法里的,当然你如果觉得
//Loader不需要初始加载 只要在有变化的时候再加载 那这个方法你就可以保持为空了。
     protected void onStartLoading() {
        if (mCursor != null) {
            deliverResult(mCursor);
        }
        if (takeContentChanged() || mCursor == null) {
            forceLoad();
        }
    }

//114-139行 为 http://developer.android.com/intl/zh-cn/reference/android/content/AsyncTaskLoader.html 这个里面 AppListLoader  的一段源码
//你看138行 也是直接调用的forceLoad 这样当我们的applist没有变化的时候 第一次也能显示出列表 
 /**
     * 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();
        }
    }

onDestroy

 /我们来看看fragment的onDestroy方法 都做了什么
public void onDestroy() {
        mCalled = true;
        //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
        //        + " mLoaderManager=" + mLoaderManager);
        if (!mCheckedForLoaderManager) {
            mCheckedForLoaderManager = true;
            mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
        }
        if (mLoaderManager != null) {
            //跳转到16行
            mLoaderManager.doDestroy();
        }
    }
//上面的代码 是在fragment里 下面的代码在loadermanger里
     void doDestroy() {
        if (!mRetaining) {
            if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
            for (int i = mLoaders.size()-1; i >= 0; i--) {
                mLoaders.valueAt(i).destroy();
            }
            mLoaders.clear();
        }

        if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
        for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
            mInactiveLoaders.valueAt(i).destroy();
        }
        mInactiveLoaders.clear();
    }
//下面这个destroy流程 可以清晰的看到很多东西 包括clear所有回调等
 void destroy() {
            if (DEBUG) Log.v(TAG, "  Destroying: " + this);
            mDestroyed = true;
            boolean needReset = mDeliveredData;
            mDeliveredData = false;
            if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
                if (DEBUG) Log.v(TAG, "  Reseting: " + this);
                String lastBecause = null;
                if (mHost != null) {
                    lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
                    mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset";
                }
                try {
                    mCallbacks.onLoaderReset(mLoader);
                } finally {
                    if (mHost != null) {
                        mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
                    }
                }
            }
            mCallbacks = null;
            mData = null;
            mHaveData = false;
            if (mLoader != null) {
                if (mListenerRegistered) {
                    mListenerRegistered = false;
                    mLoader.unregisterListener(this);
                    mLoader.unregisterOnLoadCanceledListener(this);
                }
                //在这调用了rest
                mLoader.reset();
            }
            if (mPendingLoader != null) {
                mPendingLoader.destroy();
            }
        }
//最后我们来看看loader里的代码 就能明白了 当fragement destroy的时候最终的调用来到了子类的onReset方法
         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() {
    }

//这里是cURSORLOADER的代码了 你看这里关闭了cursor
    @Override
    protected void onReset() {
        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();

        if (mCursor != null && !mCursor.isClosed()) {
            mCursor.close();
        }
        mCursor = null;
    }

//同样的 我们也能看到applistloader源码里面 也是在这个函数里清除了广播接收器。
//所以读到这里 我们就知道 loader的强大了。你只需要搞清楚这些生命周期的函数的意义
//就可以重写他们,至于什么时候调用 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;
        }
    }

参考:

http://www.cnblogs.com/punkisnotdead/p/4861376.html
http://coderrobin.com/2015/02/05/Android-LoaderManager%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/

你可能感兴趣的:(loader机制)