美文网首页
loader机制

loader机制

作者: 81bad73e9053 | 来源:发表于2016-10-09 21:33 被阅读632次

    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<Cursor> {
    
        // 这是用于显示列表数据的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<Cursor> 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<Cursor> loader, Cursor data) {
            // 将新的cursor换进来.(框架将在我们返回时关心一下旧cursor的关闭)
            mAdapter.swapCursor(data);
        }
    
        public void onLoaderReset(Loader<Cursor> loader) {
            //在最后一个Cursor准备进入上面的onLoadFinished()之前.
            // Cursor要被关闭了,我们需要确保不再使用它.
            mAdapter.swapCursor(null);
        }
    }
    

    利用loader查询通讯录

    public class MainActivity extends ListActivity implements LoaderManager.LoaderCallbacks<cursor>, 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<cursor> 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<cursor> loader, Cursor data) {
            //得到异步加载数据,更新Adapter
            cursorAdapter.swapCursor(data);
        }
     
        @Override
        public void onLoaderReset(Loader<cursor> 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<List<AppEntry>> {
        final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
        final PackageManager mPm;
    
        List<AppEntry> mApps;
        PackageIntentReceiver mPackageObserver;
    
        public AppListLoader(Context context) {
            super(context);
    
            // Retrieve the package manager for later use; note we don't
            // use 'context' directly but instead the save global application
            // context returned by getContext().
            mPm = getContext().getPackageManager();
        }
    
        // 实际上最重要的就是这个方法了,每当这个回调方法被调用的时候 就去取applist 然后将结果返回到
        // onLoadFinished 这个回调方法里面!
        @Override
        public List<AppEntry> loadInBackground() {
            // Retrieve all known applications.
            List<ApplicationInfo> apps = mPm
                    .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
                            | PackageManager.GET_DISABLED_COMPONENTS);
            if (apps == null) {
                apps = new ArrayList<ApplicationInfo>();
            }
    
            final Context context = getContext();
    
            // Create corresponding array of entries and load their labels.
            List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
            for (int i = 0; i < apps.size(); i++) {
                AppEntry entry = new AppEntry(this, apps.get(i));
                entry.loadLabel(context);
                entries.add(entry);
            }
    
            // Sort the list.
            Collections.sort(entries, ALPHA_COMPARATOR);
    
            // Done!
            return entries;
        }
    
        /**
         * Called when there is new data to deliver to the client. The super class
         * will take care of delivering it; the implementation here just adds a
         * little more logic.
         */
        @Override
        public void deliverResult(List<AppEntry> apps) {
            if (isReset()) {
                // An async query came in while the loader is stopped. We
                // don't need the result.
                if (apps != null) {
                    onReleaseResources(apps);
                }
            }
            List<AppEntry> oldApps = mApps;
            mApps = apps;
    
            if (isStarted()) {
                // If the Loader is currently started, we can immediately
                // deliver its results.
                super.deliverResult(apps);
            }
    
            // At this point we can release the resources associated with
            // 'oldApps' if needed; now that the new result is delivered we
            // know that it is no longer in use.
            if (oldApps != null) {
                onReleaseResources(oldApps);
            }
        }
    
        /**
         * Handles a request to start the Loader.
         */
        @Override
        protected void onStartLoading() {
            if (mApps != null) {
                // If we currently have a result available, deliver it
                // immediately.
                deliverResult(mApps);
            }
    
            // Start watching for changes in the app data.
            if (mPackageObserver == null) {
                mPackageObserver = new PackageIntentReceiver(this);
            }
    
            // Has something interesting in the configuration changed since we
            // last built the app list?
            boolean configChange = mLastConfig.applyNewConfig(getContext()
                    .getResources());
    
            if (takeContentChanged() || mApps == null || configChange) {
                // If the data has changed since the last time it was loaded
                // or is not currently available, start a load.
                forceLoad();
            }
        }
    
        /**
         * Handles a request to stop the Loader.
         */
        @Override
        protected void onStopLoading() {
            // Attempt to cancel the current load task if possible.
            cancelLoad();
        }
    
        /**
         * Handles a request to cancel a load.
         */
        @Override
        public void onCanceled(List<AppEntry> apps) {
            super.onCanceled(apps);
    
            // At this point we can release the resources associated with 'apps'
            // if needed.
            onReleaseResources(apps);
        }
    
        /**
         * Handles a request to completely reset the Loader.
         */
        @Override
        protected void onReset() {
            super.onReset();
    
            // Ensure the loader is stopped
            onStopLoading();
    
            // At this point we can release the resources associated with 'apps'
            // if needed.
            if (mApps != null) {
                onReleaseResources(mApps);
                mApps = null;
            }
    
            // Stop monitoring for changes.
            if (mPackageObserver != null) {
                getContext().unregisterReceiver(mPackageObserver);
                mPackageObserver = null;
            }
        }
    
        /**
         * Helper function to take care of releasing resources associated with an
         * actively loaded data set.
         */
        protected void onReleaseResources(List<AppEntry> apps) {
            // For a simple List<> there is nothing to do. For something
            // like a Cursor, we would close it here.
        }
    }
    

    在loader里 注册广播接收器,当广播接收器 收到广播以后 就调用loader的onContentChanged方法,这个方法一调用 AppListLoader里的loadInBackGround就会被调用,然后当loadInBackGround执行完毕以后 就会把结果传递给onLoadFinished方法了

    五.源码分析

    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<String, LoaderManager>();
            }
            LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
            if (lm == null) {
                if (create) {
                    lm = new LoaderManagerImpl(who, this, started);
                    mAllLoaderManagers.put(who, lm);
                }
            } else {
                lm.updateHostController(this);
            }
            return lm;
        }
    

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

    //这个就是现在存活的loader
    final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);
    
    //这个是已经运行结束的loader
    final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);
    
    public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
            if (mCreatingLoader) {
                throw new IllegalStateException("Called while creating a loader");
            } 
            //这个就是先看看是否有活动的loader 有的话就取出来 没有的话 就创建一个
            LoaderInfo info = mLoaders.get(id); 
            if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args); 
            if (info == null) {
                // Loader doesn't already exist; create.
                info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
                if (DEBUG) Log.v(TAG, "  Created new loader " + info);
            } else {
                if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
                info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
            } 
            if (info.mHaveData && mStarted) {
                // If the loader has already generated its data, report it now.
                info.callOnLoadFinished(info.mLoader, info.mData);
            } 
            return (Loader<D>)info.mLoader;
        }
    
    //其实这个创建loader的过程特别简单,我们主要看第三个参数,callback 这个参数
    //一想就明白,在前面3个demo里我们是直接在fragemet和activity里实现的callback
    //所以传进去的就是this,也就是说 回调就是在这个函数里 真正的和loader 发生了关联了
    private LoaderInfo createAndInstallLoader(int id, Bundle args,
                LoaderManager.LoaderCallbacks<Object> callback) {
            try {
                mCreatingLoader = true;
                LoaderInfo info = createLoader(id, args, callback);
                installLoader(info);
                return info;
            } finally {
                mCreatingLoader = false;
            }
        }
    

    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<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;
    
            /* 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<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);
        }
    
    //并且通过这个注册
     public void registerListener(int id, OnLoadCompleteListener<D> 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<Object> 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<Object> 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机制

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