澳门新莆京手机网站-新蒲京娱乐场 > 书籍 > Android 深刻精通Loader机制 让APP轻装参与比赛

Android 深刻精通Loader机制 让APP轻装参与比赛

1 背景

在Android中任何耗费时间的操作都无法放在UI主线程中,所以耗费时间的操作都亟需运用异步实现。同样的,在ContentProvider中也也许存在耗费时间操作,那时候也该应用异步操作,而3.0后头最推荐的异步操作就是Loader。它能够低价我们在Activity和Fragment中异步加载数据,并非用线程或AsyncTask,他的帮助和益处如下:

  • 提供异步加载数据机制;
  • 对数据源变化实行监听,实时更新数据;
  • 在Activity配置发生变化(如横竖屏切换)时决不再行加载数据;
  • 适用于任何Activity和Fragment;

PS:由于在大家前些天的多少个类型中都大气的接受了Loader来管理数量加载(何况由于马虎跳过多少个坑,举个例子Loader ID重复引致数据逻辑相当、多线程中restartLoader招致Loader抛出特别(最后有限支撑都在UI线程中推行就可以)等),所以接下去大家进行下使用及源码浅析。

PPPS:前方高能,小说巨长,请做好心绪筹算(您能够选拔经过左上角目录点击索引到感兴趣的章节直接查看,可能,只怕,恐怕直接高能往下看)。

二 Loader实现

在Android中央银行使Loaders机制,必要多少个类和接口的相称,以下是它们大意的涉嫌图,之后的剧情会对那多少个类或接口进行详细批注:

2-2-4 Loader使用实例实战

上边这些实例是叁个Fragment,模拟的是用ListView显示通讯录的实时相称查询结果,使用CursorLoader管理通信录Provider查询。如下源码,比较轻松,注释也很丰裕了,所以只是多解释:

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

    // This is the Adapter being used to display the list's data.
    SimpleCursorAdapter mAdapter;

    // If non-null, this is the current filter the user has provided.
    String mCurFilter;

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

        // Give some text to display if there is no data. In a real
        // application this would come from a resource.
        setEmptyText("No phone numbers");

        // We have a menu item to show in action bar.
        setHasOptionsMenu(true);

        // Create an empty adapter we will use to display the loaded data.
        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);

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

    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Place an action bar item for searching.
        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) {
        // 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;
    }

    @Override public boolean onQueryTextSubmit(String query) {
        // Don't care about this.
        return true;
    }

    @Override public void onListItemClick(ListView l, View v, int position, long id) {
        // Insert desired behavior here.
        Log.i("FragmentComplexList", "Item clicked: " + id);
    }

    // These are the Contacts rows that we will retrieve.
    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) {
        // 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");
    }

    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);
    }

    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);
    }
}

到此整个Loader根基使用就介绍完了,关于Loader的高档次和品级功能,比方自定义Loader等剧情这里先不贴代码表达,因为在此边一下子讲罢都会感到蒙圈,而且接受难度也正如大,所以大家在上面那么些根底铺垫之后乘热先来源码浅析,有了源码浅析把持住全局布局后再去用Loader的高级用法就可以以为百步穿杨多数。

2.2 CursorLoader
CursorLoader是AsyncTaskLoader的子类,内部装有ForceLoadContentObserver变量,观看者来落到实处对数据源的数据更新,施行加载数据操作,最要紧的本来是离不开查询操作,内部首要代码:

  • 第二个参数id:一个Acticity中能够加载多少个Loader,所以要给种种Loader制定四个唯生机勃勃的标志符id。第二个参数可以置空。
  • 其八个参数callback:回调。

2-1 Loader API概述表达

正如是我们付出中常用的片段Loader相关接口:

Class/Interface Description
LoaderManager 一个与Activity、Fragment关联的抽象类,用于管理一个或多个Loader实例。每个Activity或Fragment只能有一个LoaderManager,而一个LoaderManager可以有多个Loader。
LoaderManager.LoaderCallbacks 用于和LoaderManager交互的回调接口。譬如,可以使用onCreateLoader()创建一个新的Loader。
AsyncTaskLoader 抽象的Loader,提供一个AsyncTask继承实现。
CursorLoader AsyncTaskLoader的子类,用于向ContentResover请求返回一个Cursor。该类以标准游标查询实现了Loader协议,使用后台线程进行查询,使用这个Loader是从ContentProvider加载异步数据最好的方式。

4 拓展
1》 用来机关刷新ContentPorvider

手续(4卡塔尔:加多单元测量检验类。大家在单元测量检验里向SQLite中增添一些笔录。

4-2 不接纳ContentPorvider且自定义Loader的情景下活动刷新

咱俩脚下的连串其实都施用了ContentPorvider完毕,所以正是地方讲的那多少个景况。但是你一定会问,假使大家使用的数额不用于选用间分享,使用ContentProvider那得多麻烦啊?笔者先报告你,是很坚苦,可是Android提供的CursorLoader的API必需采用ContentProvider工夫完成多少加载和活动刷新。

此刻你钦点会说,这还说个屁!哎,别急,你看看下边这段代码是或不是会具备感触呢,如下:

public NoProviderLoader extends AsyncTaskLoader {
    ......
    ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
    ......
    @Override
    public Cursor loadInBackground() {
        SQLiteDatabase database = sqLiteOpenHelper.getReadableDatabase();
        Cursor cursor = database.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
        if (cursor != null) {
            //最重要的两行代码!!!!!!
            cursor.registerContentObserver(mObserver);//给Cursor设置观察者
            cursor.setNotificationUri(getContext().getContentResolver(), otificationUri);//给Cursor设置要观察的URI
        }

        return cursor;
    }
    ......
}

哎?是或不是地方代码很想获得,异步操作的办法中绝非使用ContentProvider,而是径直读取了数据库。握草!那不就是大家刚刚想要的供给么,它从未利用ContentProvider提供Cursor数据,同一时候落到实处了数额变动自动更新效用。

回顾解释下方面代码的法则吧,大家自定义的NoProviderLoader中定义的ForceLoadContentObserver是Loader的贰当中间类,上边源码解析已经表明过了,当数码变动时会调拨运输该类的onChange(卡塔尔国方法,实质是调拨运输了Loader的forceLoad(卡塔尔(قطر‎方法,所以能够自动刷新,非常少解释了。

这么些历程具体的实现步骤如下:

全副工程文件的目录结构如下:

2-2-3-3 onLoaderReset说明

当实例化好的Loader被重启时该办法被回调,这里会让Loader的数目置于无效状态。那个回调方法其实正是为了告知大家什么时候数据要被假释掉,所以我们应当在此个时候移除对它的援用。如下移除实例:

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

CursorLoader

具体步骤如下:

3-2 LoadManager及其达成类LoadManagerImpl的拆解深入分析

地点解析Activity及Fragment中获得LoaderManager实例时已经理解,大家拿到的LoaderManager实例其实正是LoaderManagerImpl对象,而LoaderManagerImpl又是LoaderManager类的子类,所以接下去大家来深入分析那五个父亲和儿子类。

先看下抽象父类LoaderManager,如下:

public abstract class LoaderManager {
    //LoaderManager的回调接口定义
    public interface LoaderCallbacks<D> {
        public Loader<D> onCreateLoader(int id, Bundle args);
        public void onLoadFinished(Loader<D> loader, D data);
        public void onLoaderReset(Loader<D> loader);
    }
    //下面这些方法没必要再细说了,上面介绍过的
    public abstract <D> Loader<D> initLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks<D> callback);

    public abstract <D> Loader<D> restartLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks<D> callback);
    //会触发回调的onLoaderReset方法
    public abstract void destroyLoader(int id);

    public abstract <D> Loader<D> getLoader(int id);

    public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);

    public static void enableDebugLogging(boolean enabled) {
        LoaderManagerImpl.DEBUG = enabled;
    }
}

能够瞥见LoaderManager抽象类只是概念了有的标准接口而已,那么随着大家看下抽象类LoaderManager的落实类LoaderManagerImpl,如下:

class LoaderManagerImpl extends LoaderManager {
    static final String TAG = "LoaderManager";
    static boolean DEBUG = false;

    //保存当前存活的Loader
    final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);
    //保存已经运行完的Loader
    final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);

    final String mWho;

    Activity mActivity;
    boolean mStarted;
    boolean mRetaining;
    boolean mRetainingStarted;
    //是否正在创建Loader,多线程中同时调运创建会导致异常
    boolean mCreatingLoader;
    //Loader的封装类
    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
            Loader.OnLoadCanceledListener<Object> {
        final int mId;
        final Bundle mArgs;
        LoaderManager.LoaderCallbacks<Object> mCallbacks;
        Loader<Object> mLoader;
        boolean mHaveData;
        boolean mDeliveredData;
        Object mData;
        boolean mStarted;
        //mRetaining标记Activity配置变化时保持当前Loader,不用销毁;和上面分析Activity的LoaderManager的retainNonConfigurationInstances方法关联!!!!!!
        boolean mRetaining;
        boolean mRetainingStarted;
        boolean mReportNextStart;
        boolean mDestroyed;
        boolean mListenerRegistered;

        LoaderInfo mPendingLoader;
        //LoaderInfo构造方法
        public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
            mId = id;
            mArgs = args;
            mCallbacks = callbacks;
        }
        //启动一个Loader
        void start() {
            //配置改变恢复则不用启动,用原来的
            if (mRetaining && mRetainingStarted) {
                mStarted = true;
                return;
            }
            //如果已经启动,则不用再restart了
            if (mStarted) {
                return;
            }

            mStarted = true;

            //如果当前封装中mLoader为空并且通过构造方法的mCallbacks不为空则回调onCreateLoader方法创建Loader
            if (mLoader == null && mCallbacks != null) {
               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
            }
            if (mLoader != null) {
                if (mLoader.getClass().isMemberClass()
                        && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
                        //如果当前创建的Loader对象是一个非静态内部类则抛异常!!!!!!
                    throw new IllegalArgumentException(
                            "Object returned from onCreateLoader must not be a non-static inner member class: "
                            + mLoader);
                }
                if (!mListenerRegistered) {
                    //注册Loader的监听方法
                    mLoader.registerListener(mId, this);
                    mLoader.registerOnLoadCanceledListener(this);
                    mListenerRegistered = true;
                }
                //调运Loader的startLoading方法
                mLoader.startLoading();
            }
        }
        //Activity的配置改变时进行标志位的设置,以便可以保存,配合上面Activity的分析!!!!!!
        void retain() {
            mRetaining = true;
            ......
        }
        //Activity配置变化后重启后如果有数据则通知回调方法,配合上面Activity的分析!!!!!!
        void finishRetain() {
            ......
            if (mStarted && mHaveData && !mReportNextStart) {
                callOnLoadFinished(mLoader, mData);
            }
        }
        //配合上面Activity的分析!!!!!!
        void reportStart() {
            ......
        }
        //停止Loader
        void stop() {
            mStarted = false;
            if (!mRetaining) {
                //如果不是Activity配置变化,即不用保存则注销掉这些回调
                if (mLoader != null && mListenerRegistered) {
                    ......
                }
            }
        }
        //取消掉Loader
        void cancel() {
            ......
        }
        //销毁掉Loader
        void destroy() {
            ......
            if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
                ......
                try {
                    //在destroy时如果有数据存在则调用callback的onLoaderReset方法!!!!!!
                    mCallbacks.onLoaderReset(mLoader);
                } finally {
                    ......
                }
            }
            ......
            if (mLoader != null) {
                //注销监听方法
                if (mListenerRegistered) {
                    ......
                }
                //close Cursor等重置操作
                mLoader.reset();
            }
            if (mPendingLoader != null) {
                mPendingLoader.destroy();
            }
        }
    //Loader被取消时回调该方法
        @Override
        public void onLoadCanceled(Loader<Object> loader) {
            ......
            LoaderInfo pending = mPendingLoader;
            //执行最新的Loader
            if (pending != null) {
                mPendingLoader = null;
                mLoaders.put(mId, null);
                destroy();
                installLoader(pending);
            }
        }
        //加载完成时回调
        @Override
        public void onLoadComplete(Loader<Object> loader, Object data) {
            ......
            //执行最新的Loader
            if (pending != null) {
                mPendingLoader = null;
                mLoaders.put(mId, null);
                destroy();
                installLoader(pending);
                return;
            }

            if (mData != data || !mHaveData) {
                mData = data;
                mHaveData = true;
                if (mStarted) {
                    callOnLoadFinished(loader, data);
                }
            }
            ......
        }
        //调用onLoadFinished
        void callOnLoadFinished(Loader<Object> loader, Object data) {
            if (mCallbacks != null) {
                ......
                try {
                    //回调onLoadFinished方法
                    mCallbacks.onLoadFinished(loader, data);
                } finally {
                    ......
                }
                mDeliveredData = true;
            }
        }
    }

    //!!!!!!真正LoaderManagerImpl的构造方法
    LoaderManagerImpl(String who, Activity activity, boolean started) {
        mWho = who;
        mActivity = activity;
        mStarted = started;
    }

    //更新当前Activity引用
    void updateActivity(Activity activity) {
        mActivity = activity;
    }

    //私有的创建Loader方法
    private LoaderInfo createLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks<Object> callback) {
        LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
        //回调callback的onCreateLoader方法得到Loader对象
        Loader<Object> loader = callback.onCreateLoader(id, args);
        //把得到的Loader对象包装成LoaderInfo对象
        info.mLoader = (Loader<Object>)loader;
        return info;
    }

    //包装了创建Loader与install方法,并将mCreatingLoader标记置位
    private LoaderInfo createAndInstallLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks<Object> callback) {
        try {
            mCreatingLoader = true;
            //调运上面的私有创建方法创建LoaderInfo对象
            LoaderInfo info = createLoader(id, args, callback);
            //把创建的LoaderInfo对象传入installLoader方法
            installLoader(info);
            return info;
        } finally {
            mCreatingLoader = false;
        }
    }

    void installLoader(LoaderInfo info) {
        //将创建的LoaderInfo对象存入mLoaders的Map中
        mLoaders.put(info.mId, info);
        if (mStarted) {
            //如果Activity已经started,则启动LoaderInfo的start方法
            info.start();
        }
    }

    //public的方法,创建一个Loader,前面介绍过的
    @SuppressWarnings("unchecked")
    public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
        //如果多线程中正在有创建的则抛出异常(写代码要注意这种情况,尤其是跑Monkey容易抛出,解决办法就是保证都在统一线程中执行!!!!!!)
        if (mCreatingLoader) {
            throw new IllegalStateException("Called while creating a loader");
        }
        //从现有的Map中尝试获取指定ID的LoaderInfo对象
        LoaderInfo info = mLoaders.get(id);
        if (info == null) {
            //发现不存在就调运上面的createAndInstallLoader创建一个
            info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
        } else {
            //否则还用当前的Loader,只是重新赋值了callBack而已
            info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
        }

        if (info.mHaveData && mStarted) {
            //已经有数据,直接调运LoaderInfo的callOnLoadFinished
            info.callOnLoadFinished(info.mLoader, info.mData);
        }
        //返回Loader对象
        return (Loader<D>)info.mLoader;
    }

    //重新创造Loader,前面介绍过的
    @SuppressWarnings("unchecked")
    public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
        if (mCreatingLoader) {
            //如果多线程中正在有创建的则抛出异常(写代码要注意这种情况,尤其是跑Monkey容易抛出,解决办法就是保证都在统一线程中执行!!!!!!)
            throw new IllegalStateException("Called while creating a loader");
        }

        LoaderInfo info = mLoaders.get(id);
        if (info != null) {
            LoaderInfo inactive = mInactiveLoaders.get(id);
            if (inactive != null) {
                if (info.mHaveData) {
                    //发现是已经运行完的Loader且已经存在的Loader有数据则destroy掉运行完的Loader
                    inactive.mDeliveredData = false;
                    inactive.destroy();
                    info.mLoader.abandon();
                    mInactiveLoaders.put(id, info);
                } else {
                    if (!info.mStarted) {
                        //有相同id的Loader还没start则destory掉
                        mLoaders.put(id, null);
                        info.destroy();
                    } else {
                        //有一个相同id的Loader正在加载数据,但是还没加载完,调用它的cancel()方法通知取消加载
                        info.cancel();
                        if (info.mPendingLoader != null) {
                            info.mPendingLoader.destroy();
                            info.mPendingLoader = null;
                        }
                        //创建一个指定id的Loader同时赋给mPendingLoader,因为这个时候已经有一个Loader正在加载数据,而且我们已经调用了其cancel()方法来通知取消加载
                        info.mPendingLoader = createLoader(id, args, 
                                (LoaderManager.LoaderCallbacks<Object>)callback);
                        //返回创建的Loader
                        return (Loader<D>)info.mPendingLoader.mLoader;
                    }
                }
            } else {
                //终止已存在的Loader
                info.mLoader.abandon();
                mInactiveLoaders.put(id, info);
            }
        }
        //重新创建Loader返回
        info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
        return (Loader<D>)info.mLoader;
    }

    //销毁指定id的Loader
    public void destroyLoader(int id) {
        if (mCreatingLoader) {
            throw new IllegalStateException("Called while creating a loader");
        }
        //不解释,单纯的destory
        int idx = mLoaders.indexOfKey(id);
        if (idx >= 0) {
            LoaderInfo info = mLoaders.valueAt(idx);
            mLoaders.removeAt(idx);
            info.destroy();
        }
        idx = mInactiveLoaders.indexOfKey(id);
        if (idx >= 0) {
            LoaderInfo info = mInactiveLoaders.valueAt(idx);
            mInactiveLoaders.removeAt(idx);
            info.destroy();
        }
        ......
    }

    //获取指定id的Loader对象
    @SuppressWarnings("unchecked")
    public <D> Loader<D> getLoader(int id) {
        if (mCreatingLoader) {
            throw new IllegalStateException("Called while creating a loader");
        }
        //优先获取LoaderInfo中的mPendingLoader
        LoaderInfo loaderInfo = mLoaders.get(id);
        if (loaderInfo != null) {
            if (loaderInfo.mPendingLoader != null) {
                return (Loader<D>)loaderInfo.mPendingLoader.mLoader;
            }
            return (Loader<D>)loaderInfo.mLoader;
        }
        return null;
    }
    ......
}

自己勒个去!好长,好累!通过地点粗略的分析你会意识和大家地点根基实例介绍LoaderManager的方式时描述的同样,种种方法都有和谐的特征,发挥着各自的遵循,LoaderManager的庐山真面目目是将Loader对象转变为LoaderInfo来举行拘押,也正是管理了有着的Loader对象。

开垦者技能前沿

留意为ListView绑定适配器的代码:listview.setAdapter(mAdapter卡塔尔(قطر‎是在Loader的回调接口中(132行)进行的,也正是在这里间更新UI,那样就可以看到落到实处机关刷新UI。

3-3 Loader及实际现类的深入分析

下边深入分析了Activity及Fragment管理了LoaderManager的连带措施,LoaderManager处理了Loader的连带措施,那么接下去大家就来探视那一个被拘留的终极指标Loader是咋回事,还只怕有他的子类咋回事。

先来看看笔者画的一张关系图,如下:

图片 1

本身去,那图将来看大概某些骇然,大家依然先来慢慢剖判一下再说吧。

通过上边大家的源码深入分析和剖析前这副图能够总计如下结论:

运作程序,动态演示效果如下:

2-2-3 使用LoaderManager Callbacks

LoaderManager.LoaderCallbacks是LoaderManager的回调交互作用接口。LoaderManager.LoaderCallbacks蕴涵如下五个措施:

  • onCreateLoader()
    实例化并重返一个新成立给定ID的Loader对象;
  • onLoadFinished()
    当创设好的Loader实现了数额的load之后回调此措施;
  • onLoaderReset()
    当创制好的Loader被reset时调用此办法,那样保证它的数码无效;

Android开采者都经历过应用软件 UI开拓不当 会造成overDraw,招致APPUI渲染过慢,可是洋比利时人却没听过overLoad,overLoad平时是由于开采者在主线程操作耗费时间操作,诱致程序变慢 以至现身的anr的场景,那么android早就为这种光景提供周全的实施方案,正是前不久给咱们说的Loader机制。

2、LoaderManager

2-2-2 重启一个Loader(restartLoader)

因而地点initLoader(卡塔尔国方法介绍大家可以领略initLoader调拨运输后只怕获得三个ID已存在的Loader,要么创制二个新的Loader;然则一时我们想屏弃旧数据然后再度开端成立一个新Loader,那可如何做呢?别担心,要放弃旧数据调用restartLoader(卡塔尔国就可以。举个例子,SearchView.OnQueryTextListener的兑现重启了Loader,当客商查询爆发变化时Loader须求重启,如下:

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;
}

地点方法的参数啥的和再上边的init方法雷同,就不再罗嗦了。

Loader

咱俩在步骤(4State of Qatar的单元测量检验里向数据库中加多一些数据之后,能够初阶接下去最要害的步子了:

4-3 Loader自定义之AsyncTaskLoader衍生

想非看不可到此间您越发会触类旁通的论争一句了,下边搞了半天都以和数据库Cursor相关的东东,难道Loader就无法异步处理别的数据构造么?答案是能,因为你也许早就注意到了Loader和AsyncTaskLoader都以泛型类;既然那样,那我们找猫画虎意气风发把呗,仿照CursorLoader自定义二个温馨的异步加载试试,具体落到实处如下(哈哈,想了又想,这里还是一贯付出官方的自定义AsyncTaskLoader好点,毕竟权威些,详细点小编翻看官方自定义实现Demo):

合法对此查询已安装App列表的Loader达成,帮忙新App安装后活动刷新的功能,完结如下:

/** * This class holds the per-item data in our Loader. */
public static class AppEntry {
    public AppEntry(AppListLoader loader, ApplicationInfo info) {
        mLoader = loader;
        mInfo = info;
        mApkFile = new File(info.sourceDir);
    }

    public ApplicationInfo getApplicationInfo() {
        return mInfo;
    }

    public String getLabel() {
        return mLabel;
    }

    public Drawable getIcon() {
        if (mIcon == null) {
            if (mApkFile.exists()) {
                mIcon = mInfo.loadIcon(mLoader.mPm);
                return mIcon;
            } else {
                mMounted = false;
            }
        } else if (!mMounted) {
            // If the app wasn't mounted but is now mounted, reload
            // its icon.
            if (mApkFile.exists()) {
                mMounted = true;
                mIcon = mInfo.loadIcon(mLoader.mPm);
                return mIcon;
            }
        } else {
            return mIcon;
        }

        return mLoader.getContext().getResources().getDrawable(
                android.R.drawable.sym_def_app_icon);
    }

    @Override public String toString() {
        return mLabel;
    }

    void loadLabel(Context context) {
        if (mLabel == null || !mMounted) {
            if (!mApkFile.exists()) {
                mMounted = false;
                mLabel = mInfo.packageName;
            } else {
                mMounted = true;
                CharSequence label = mInfo.loadLabel(context.getPackageManager());
                mLabel = label != null ? label.toString() : mInfo.packageName;
            }
        }
    }

    private final AppListLoader mLoader;
    private final ApplicationInfo mInfo;
    private final File mApkFile;
    private String mLabel;
    private Drawable mIcon;
    private boolean mMounted;
}

/** * Perform alphabetical comparison of application entry objects. */
public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
    private final Collator sCollator = Collator.getInstance();
    @Override
    public int compare(AppEntry object1, AppEntry object2) {
        return sCollator.compare(object1.getLabel(), object2.getLabel());
    }
};

/** * Helper for determining if the configuration has changed in an interesting * way so we need to rebuild the app list. */
public static class InterestingConfigChanges {
    final Configuration mLastConfiguration = new Configuration();
    int mLastDensity;

    boolean applyNewConfig(Resources res) {
        int configChanges = mLastConfiguration.updateFrom(res.getConfiguration());
        boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
        if (densityChanged || (configChanges&(ActivityInfo.CONFIG_LOCALE
                |ActivityInfo.CONFIG_UI_MODE|ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0) {
            mLastDensity = res.getDisplayMetrics().densityDpi;
            return true;
        }
        return false;
    }
}

/** * Helper class to look for interesting changes to the installed apps * so that the loader can be updated. */
public static class PackageIntentReceiver extends BroadcastReceiver {
    final AppListLoader mLoader;

    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);
        mLoader.getContext().registerReceiver(this, sdFilter);
    }

    @Override public void onReceive(Context context, Intent intent) {
        // Tell the loader about the change.
        mLoader.onContentChanged();
    }
}

/** * A custom Loader that loads all of the installed applications. */
public static class AppListLoader extends AsyncTaskLoader<List<AppEntry>> {
    final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
    final PackageManager mPm;

    List<AppEntry> mApps;
    PackageIntentReceiver mPackageObserver;

    public AppListLoader(Context context) {
        super(context);

        // Retrieve the package manager for later use; note we don't
        // use 'context' directly but instead the save global application
        // context returned by getContext().
        mPm = getContext().getPackageManager();
    }

    /** * This is where the bulk of our work is done. This function is * called in a background thread and should generate a new set of * data to be published by the loader. */
    @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为谷歌(Google卡塔尔出品,强盛的不胜,大家全然能够仿写这么些事例完毕和睦的乞请。

正如为官方对该自定义Loader调拨运输的德姆o代码:

public static class AppListAdapter extends ArrayAdapter<AppEntry> {
    private final LayoutInflater mInflater;

    public AppListAdapter(Context context) {
        super(context, android.R.layout.simple_list_item_2);
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public void setData(List<AppEntry> data) {
        clear();
        if (data != null) {
            addAll(data);
        }
    }

    /** * Populate new items in the list. */
    @Override public View getView(int position, View convertView, ViewGroup parent) {
        View view;

        if (convertView == null) {
            view = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
        } else {
            view = convertView;
        }

        AppEntry item = getItem(position);
        ((ImageView)view.findViewById(R.id.icon)).setImageDrawable(item.getIcon());
        ((TextView)view.findViewById(R.id.text)).setText(item.getLabel());

        return view;
    }
}

public static class AppListFragment extends ListFragment implements OnQueryTextListener, OnCloseListener, LoaderManager.LoaderCallbacks<List<AppEntry>> {

    // This is the Adapter being used to display the list's data.
    AppListAdapter mAdapter;

    // The SearchView for doing filtering.
    SearchView mSearchView;

    // If non-null, this is the current filter the user has provided.
    String mCurFilter;

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

        // Give some text to display if there is no data. In a real
        // application this would come from a resource.
        setEmptyText("No applications");

        // We have a menu item to show in action bar.
        setHasOptionsMenu(true);

        // Create an empty adapter we will use to display the loaded data.
        mAdapter = new AppListAdapter(getActivity());
        setListAdapter(mAdapter);

        // Start out with a progress indicator.
        setListShown(false);

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

    public static class MySearchView extends SearchView {
        public MySearchView(Context context) {
            super(context);
        }

        // The normal SearchView doesn't clear its search text when
        // collapsed, so we will do this for it.
        @Override
        public void onActionViewCollapsed() {
            setQuery("", false);
            super.onActionViewCollapsed();
        }
    }

    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Place an action bar item for searching.
        MenuItem item = menu.add("Search");
        item.setIcon(android.R.drawable.ic_menu_search);
        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
                | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
        mSearchView = new MySearchView(getActivity());
        mSearchView.setOnQueryTextListener(this);
        mSearchView.setOnCloseListener(this);
        mSearchView.setIconifiedByDefault(true);
        item.setActionView(mSearchView);
    }

    @Override public boolean onQueryTextChange(String newText) {
        // Called when the action bar search text has changed. Since this
        // is a simple array adapter, we can just have it do the filtering.
        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
        mAdapter.getFilter().filter(mCurFilter);
        return true;
    }

    @Override public boolean onQueryTextSubmit(String query) {
        // Don't care about this.
        return true;
    }

    @Override
    public boolean onClose() {
        if (!TextUtils.isEmpty(mSearchView.getQuery())) {
            mSearchView.setQuery(null, true);
        }
        return true;
    }

    @Override public void onListItemClick(ListView l, View v, int position, long id) {
        // Insert desired behavior here.
        Log.i("LoaderCustom", "Item clicked: " + id);
    }

    @Override public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) {
        // This is called when a new Loader needs to be created. This
        // sample only has one Loader with no arguments, so it is simple.
        return new AppListLoader(getActivity());
    }

    @Override public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
        // Set the new data in the adapter.
        mAdapter.setData(data);

        // The list should now be shown.
        if (isResumed()) {
            setListShown(true);
        } else {
            setListShownNoAnimation(true);
        }
    }

    @Override public void onLoaderReset(Loader<List<AppEntry>> loader) {
        // Clear the data in the adapter.
        mAdapter.setData(null);
    }
}

强有力的意气风发逼!那下满技艺,不解释,本身看。

PS:顺便说下AsyncTaskLoader与AsyncTask的界别,看完源码我们再回过头来计算性的说说她们相互分别,如下:

4、CursorLoader

3-3-3 CursorLoader子类源码浅析

有了上边继续自Loader的抽象AsyncTaskLoader,接下去大家就来看看SDK为大家提供的抽象AsyncTaskLoader达成类CursorLoader,大家先来轻易看看该类的情势图,如下:

图片 2

切切实实代码分析如下:

//继承自AsyncTaskLoader,数据类型为Cursor的Loader异步加载实现类
public class CursorLoader extends AsyncTaskLoader<Cursor> {
    //Cursor的子类ForceLoadContentObserver
    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();
        }
    }

    public CursorLoader(Context context) {
        super(context);
        mObserver = new ForceLoadContentObserver();
    }

    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;
    }

    @Override
    protected void onStartLoading() {
        if (mCursor != null) {
            deliverResult(mCursor);
        }
        if (takeContentChanged() || mCursor == null) {
            forceLoad();
        }
    }

    @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;
    }
}

能够开掘,CursorLoader的卷入大大简化了选用开采者代码的复杂度;它完全正是叁个异步的数据库查询瑞士联邦军刀,未有何非常须要深入分析的地点,所以不再过多表明。

当然了,intiLoader(卡塔尔国会回来三个创办的Loader,然则你不用获取它的引用,因为LoadeManager会自动处理该Loader的生命周期,你只用在它回调提供的生命周期方法中做和煦多少逻辑的拍卖就能够。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="240dp"
 4     android:layout_height="wrap_content"
 5     android:orientation="vertical" >
 6 
 7     <TextView
 8         android:id="@+id/textView1"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:text="姓名:" />
12 
13     <EditText
14         android:id="@+id/username"
15         android:layout_width="match_parent"
16         android:layout_height="wrap_content"
17         android:layout_marginBottom="4dp"
18         android:layout_marginLeft="4dp"
19         android:layout_marginRight="4dp"
20         android:layout_marginTop="16dp"
21         android:hint="username"
22         android:inputType="textEmailAddress" />
23 
24     <Button
25         android:id="@+id/btnAdd"
26         android:layout_width="match_parent"
27         android:layout_height="wrap_content" android:text="确定">
28     </Button>
29 
30 </LinearLayout>

2-2 在使用中使用Loader

在我们开荒的七个App里,使用Loader时常规的步骤包涵如下一些操作需要:

  • 一个Activity或Fragment;
  • 一个LoaderManager实例;
  • 叁个CursorLoader,从ContentProvider加载数据;
  • 四个LoaderManager.LoaderCallbacks完结,创立新Loader及管理已存在Loader;
  • 叁个团体Loader数据的Adapter,如SimpleCursorAdapter;

上边大家看下具体流程。

2 Loader
Loader是切实可行来操作职责的类,担任去调用分裂路子的数目接口,比方数据库,contentProvider, 文件等。

图片 3

4 应用层开辟之Loader晋级实战

上边对于Loader的底蕴运用及源码框架都开展了简短深入分析,有了上边的反衬大家再回过头来看看我们开辟中的一些尖端技能,通过这个高档技巧不仅仅是对近年来源码剖判的实例证实,也是对友好文化的积累。

最重若是加载数据,使用loader大家不用关切数据曾几何时转移了,也无需关怀activity的生命周期,做到数量不被重新多次加载情况,activty销毁数据自动释放的职能,做到二遍加载数次使用的功用,我们得以依赖须求,拿着loader变活灵通,这里的满腹经纶还索要您本人心得。
案例:https://github.com/NeglectedByBoss/Loader
更加多小说请猛戳

public abstract <D> Loader<D> initLoader(int id,Bundle args, LoaderManager.LoaderCallbacks<D> callback)

2-2-1 运营三个Loader(initLoader)

多个Activity或Fragment中LoaderManager管理叁个或八个Loader实例,种种Activity或Fragment独有二个LoaderManager,大家得以在Activity的onCreate(卡塔尔国或Fragment的onActivityCreated(卡塔尔国里开始化多个Loader。比如:

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

能够望见上面包车型客车initLoader(卡塔尔方法有四个参数:

  • 先是个参数代表当前Loader的ID;
  • 第2个参数代表提要求Loader布局函数的参数,可选;
  • 其四个参数代表LoaderManager.LoaderCallbacks的回调完毕;

地点initLoader(卡塔尔国方法的调用确认保障了三个Loader被领头化和激活的情况,该情势的调拨运输有如下二种结果:

  • 若是代表该Loader的ID已经存在,则前面成立的Loader将直接复用已经存在的;
  • 假使代表该Loader的ID子虚乌有,initLoader(卡塔尔(قطر‎会触发LoaderManager.LoaderCallbacks回调的onCreateLoader(State of Qatar方法创造叁个Loader;

能够瞥见通过initLoader(State of Qatar方法能够将LoaderManager.LoaderCallbacks实例与Loader举办关联,且当Loader的情况变化时就被回调。所以说,纵然调用者正处在其开首情况并且被呼吁的Loader已经存在,且已发生了多少,那么系统会立刻调用onLoadFinished(卡塔尔(在initLoader(卡塔尔国调用时期),所以您一定要酌量到这种气象的产生。

当然了,intiLoader(卡塔尔(قطر‎会回来一个创立的Loader,可是你绝不获取它的援引,因为LoadeManager会自动管理该Loader的生命周期,你只用在它回调提供的生命周期方法中做要好些个少逻辑的拍卖就可以。

要是代表该Loader的ID已经存在,则前边创设的Loader将一贯复用已经存在的;

假如我们接收上海体育场面菜单中的“增加”,会弹出一个对话框:

3-3-1 Loader基类源码浅析

咱俩先来看看那些Loader基类吧,该类主题措施及中间类组织图如下:

图片 4

代码解析如下:

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;
    //数据源变化监听器(观察者模式),实现了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();
        }
    }

    //Loader加载完成接口,当加载完成时Loader通知loaderManager,loaderManager再回调我们initLoader方法的callback
    public interface OnLoadCompleteListener<D> {
        public void onLoadComplete(Loader<D> loader, D data);
    }
    //LoaderManager中监听cancel,同上类似
    public interface OnLoadCanceledListener<D> {
        public void onLoadCanceled(Loader<D> loader);
    }

    //构造方法
    public Loader(Context context) {
        //mContext持有Application的Context,防止泄露内存等
        mContext = context.getApplicationContext();
    }

    //加载完成时回调传递加载数据结果,实质是对OnLoadCompleteListener接口方法的封装
    public void deliverResult(D data) {
        if (mListener != null) {
            mListener.onLoadComplete(this, data);
        }
    }
    //类似同上,对OnLoadCanceledListener的方法的封装
    public void deliverCancellation() {
        if (mOnLoadCanceledListener != null) {
            mOnLoadCanceledListener.onLoadCanceled(this);
        }
    }

    public Context getContext() {
        return mContext;
    }
    public int getId() {
        return mId;
    }
    public void registerListener(int id, OnLoadCompleteListener<D> listener) {
        mListener = listener;
        mId = id;
    }
    public void unregisterListener(OnLoadCompleteListener<D> listener) {
        mListener = null;
    }
    public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
        mOnLoadCanceledListener = listener;
    }
    public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
        mOnLoadCanceledListener = null;
    }
    public boolean isStarted() {
        return mStarted;
    }
    public boolean isAbandoned() {
        return mAbandoned;
    }
    public boolean isReset() {
        return mReset;
    }

    //开始加载数据时LoaderManager会调用该方法
    public final void startLoading() {
        //设置标记
        mStarted = true;
        mReset = false;
        mAbandoned = false;
        onStartLoading();
    }

    //真正开始加载数据的地方******空方法,子类实现!!!!!!
    protected void onStartLoading() {
    }

    //取消Loader的方法
    public boolean cancelLoad() {
        return onCancelLoad();
    }

    //真正取消的地方******,子类实现!!!!!!return false表示取消失败(因为已完成或未开始)
    protected boolean onCancelLoad() {
        return false;
    }

    //强制重新Loader,放弃旧数据
    public void forceLoad() {
        onForceLoad();
    }

    //真正重新Loader的地方******空方法,子类实现!!!!!!
    protected void onForceLoad() {
    }

    //同上
    public void stopLoading() {
        mStarted = false;
        onStopLoading();
    }
    protected void onStopLoading() {
    }

    //同上
    public void abandon() {
        mAbandoned = true;
        onAbandon();
    }
    protected void onAbandon() {
    }

    //同上
    public void reset() {
        onReset();
        mReset = true;
        mStarted = false;
        mAbandoned = false;
        mContentChanged = false;
        mProcessingChange = false;
    }
    protected void onReset() {
    }

    //Loader数据变化的一些标记处理
    public boolean takeContentChanged() {
        boolean res = mContentChanged;
        mContentChanged = false;
        mProcessingChange |= res;
        return res;
    }
    public void commitContentChanged() {
        mProcessingChange = false;
    }
    public void rollbackContentChanged() {
        if (mProcessingChange) {
            mContentChanged = true;
        }
    }

    //上面ForceLoadContentObserver内部类的onChange方法调运
    public void onContentChanged() {
        if (mStarted) {
            forceLoad();
        } else {
            mContentChanged = true;
        }
    }

    //一些方便调试的方法
    public String dataToString(D data)
    public String toString()
    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)
}

因而地点粗略的拆解剖析能够发掘,Loader基类无非也便是一个艺术接口的定义类,社团预先流出了有个别方式供LoaderManager去调拨运输管理,同期需要子类实现其提供的有的onXXX方法,以便LoaderManager调拨运输Loader的措施时得以触发Loader子类的达成逻辑。

小编看了源码,AsyncTaskLoader具备AsyncTask,在自家实例化后拉开三个线程,自笔者举办executePendingTask(卡塔尔国,此形式里实际就在试行asyncTask的mTask.executeOnExecutor(mExecutor,(Void[]卡塔尔(قطر‎null卡塔尔;�来完结AsyncTaskLoader的自身监听机制,当然笔者轮询和通讯是离不开Handler的 因为整个android的广播发表正是发愤忘食在Handler(底层binder)幼功上,这里不再剖判。

伊始分界面为:

2-2-3-1 onCreateLoader说明

当您尝试运用四个Loader(举例通过initLoader(State of Qatar方法),它会检查给定Loader的ID是还是不是留存,假若官样文章就触发LoaderManager.LoaderCallbacks里的onCreateLoader(卡塔尔(قطر‎方法创立贰个新Loader。创立新Loader实例标准的做法就是通过CursorLoader类创立,可是你也得以自定义二个一而再再而三自Loader的子类来贯彻团结的Loader。

上边包车型大巴例子中大家因而onCreateLoader(State of Qatar回调成立四个CursorLoader实例,使用CursorLoader的布局方法创设实例时索要有个别参数去询问三个ContentProvider。具体参数如下:

  • uri
    预备获取内容的U奔驰M级I。
  • projection
    要赶回的列key list,null表示回去全部列,但是回到全体列比很多时候会减低品质;
  • selection
    要赶回的行过滤,也正是SQL中的WHERE语句,null代表回到uri钦命的装有行;
  • selectionArgs
    用来替换上面selection中带有的“?”;
  • sortOrder
    结果的行排序,也正是SQL中的O奥迪Q5DE奇骏 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");
}

一遍完整的数量加载流程为Activity调用LoaderManager的doStart(State of Qatar方法,LoaderManager调用Loader的startLoading(卡塔尔(قطر‎方法,然后Loader调拨运输AsyncTaskLoader的doingBackground(卡塔尔国方法进行耗费时间数据加载,紧接着AsyncTaskLoader回调LoaderManager的complete数据加载成功措施,接着又LoaderManager回调我们在Activity中贯彻的callback中的onLoadFinish(卡塔尔方法。

步骤(5):

3-4 Loaders相关源码浅析总计

经过上边大家的源码分析和解析前那副图能够总括如下结论:

  • 三回完整的多少加载流程为Activity调用LoaderManager的doStart(State of Qatar方法,然后LoaderManager调用Loader的startLoading(卡塔尔国方法,然后Loader调拨运输AsyncTaskLoader的doingBackground(卡塔尔国方法进行耗费时间数据加载,然后AsyncTaskLoader回调LoaderManager的complete数据加载成功措施,接着LoaderManager回调大家在Activity中落到实处的callback中的onLoadFinish(State of Qatar方法。
  • Acivity和Fragment的生命周期主动管理了LoaderManager,每一种Activity用一个ArrayMap的mAllLoaderManager来保存当前Activity及其附属Frament的唯大器晚成LoaderManager;在Activity配置产生变化时,Activity在destory前会保存mAllLoaderManager,当Activity再重复成立时,会在Activity的onAttcach(卡塔尔、onCreate(卡塔尔国、performStart(卡塔尔方法中复苏mAllLoaderManager。
  • LoaderManager给Activity提供了拘禁本人的局地措施;同期主动管理了相应的Loader,它把每二个Loader封装为LoadInfo对象,同不时间它担负主动调运输管理理Loader的startLoading(State of Qatar、stopLoading(卡塔尔(قطر‎、,forceLoad(卡塔尔国等方法。
  • 由于一切Activity和Fragment主动管理了Loader,所以有关Loader的放走(比方CursorLoader的Cursor关闭等)无需大家人为管理,Loader框架会帮我们很好的处理的;同一时间特别注意,对于CursorLoader,当大家数据源爆发变化时Loader框架会经过ContentObserver调用onContentChanged的forceLoad方法重复央求数据实行回调刷新。

好了,至此你会发觉Loader真的很牛叉,No!应该是Google的程序员真的很牛叉,构造真的超级赞,值得推荐。

Acivity和Fragment的生命周期主动管理了LoaderManager,每种Activity用叁个ArrayMap的mAllLoaderManager来保存当前Activity及其附属Frament的唯生龙活虎LoaderManager;在Activity配置产生变化时,Activity在destory前会保存mAllLoaderManager,当Activity再另行创立时,会在Activity的onAttcach(State of Qatar、onCreate(卡塔尔(قطر‎、performStart(卡塔尔方法中苏醒mAllLoaderManager。

手续(3State of Qatar:新建类PersonContentProvider,继承ContetProvider,记得阐明权限。

3 源码浅析

和方面包车型地铁中央使用介绍近似,关于Loader的源码浅析进程会波及到Activity、Fragment、LoaderManager、Loader、AsyncLoader、CursorLoader等类。所以大家解析的进度仍然和原先相通,依赖使用各种进行深入分析。

咱俩在分条析理在此之前先来看一个Loader框架概要图,如下:

图片 5

透过地点图和前边的根底实例你会发觉Loader的框架和生龙活虎风流浪漫类的天职都很分明。Activity和Fragment管理LoaderManager,LoaderManager处理Loader,Loader获得数码后触发在LoaderManager中完毕的Loader的callback接口,LoaderManager在选用到Loader的callback回传调拨运输时接触大家Activity或Fragment中落到实处的LoaderManager回调callback接口,就好像此就兑现了Loader的有着机能,而小编辈平素写代码日常只用关爱LoaderManager的callback实现就可以;对于自定义Loader可能还亟需关爱AsyncTaskLoader子类的落实。

callback

若果单击菜单中的“删除”,会一直删除。

4-1 ContentPorvider意况下的CurSorLoader自动刷新

在我们利用CurSorLoader时我们都会盘算生龙活虎种景况的管理—–当数据库发生变化时怎么自动刷新当前UI。呵呵,大家先来讲说那几个原理,数据库在多少变动时通过ContentPorvider和ContentResolver发出布告,接着ContentProvider公告Cursor的观看者数据产生了变通,然后Cursor通告CursorLoader的观望者数据发生了更改,接着CursorLoader通过ContentProvider加载新数据,完事调用CursorAdapter的changeCursor(卡塔尔国用新数据替换旧数据显示。

本条进程具体的落实步骤如下:

  1. 对获取的Cursor数据设置要求监听的U福睿斯I(即,在ContentProvider的query(卡塔尔方法依旧Loader的loadingBackground(卡塔尔方法中调用Cursor的setNotificationUri(卡塔尔(قطر‎方法);
  2. 在ContentProvider的insert(卡塔尔、update(卡塔尔国、delete(卡塔尔等格局中调用ContentResolver的notifyChange(State of Qatar方法;

透过地点两步我们就会享用CurSorLoader的机关数据刷新成效了;能够开掘,所谓的CurSorLoader自动刷新无非正是观望者方式的框架而已,所以不再过多表达。

特别注意:

些微人觉着为了便利恐怕会将上边第一步对于Cursor设置监听间接写在了ContentProvider的query(卡塔尔方法中,如下:

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] 
selectionArgs,String sortOrder) {
    SQLiteDatabase database = sqLiteOpenHelper.getReadableDatabase();
    Cursor cursor = database.query(EmailContent.CONTACT_TABLE, projection,
    selection,selectionArgs, null, null, sortOrder);
    //设置NotificationUri监听
    cursor.setNotificationUri(contentResolver, EmailContent.MESSAGE);
    return cursor;
}

此处要晋升的是,这种写法在有个别场馆下是不值得推荐介绍的(譬喻大范围上千次并发平凡的调拨运输query操作场所),因为功效很低,他会频仍的通过Binder进行通讯,导致system_server不停的调拨运输GC操作,以致于会使系统卡顿。

PS:因为本身原先跳过叁次那一个坑,平时接受应用没啥难题,不过当进行压力测验时却开采LogCat平昔在不停的打字与印刷GC,同有时候导致当前系统卡顿,杀掉应用后系统就不卡了,所以基本猜疑难点就出在了选取中,于是通过广大办法去寻觅(譬喻dempsys content去查看个数),最后开掘始作俑者是以此监听频仍调运招致的,随将其挪到loadingBackground中不再卡顿。

先是个参数代表当前Loader的ID ,用来不一致哪些loader;

  • CursorLoader(Context context)
  • CursorLoader(Context context,Uri uri,String[] projection,String selection ,String[] selectionArgs,String sortOrder)
2-2-3-2 onLoadFinished说明

当创制好的Loader完结数据加载时回调此办法,大家要确保该措施在Loader释放现成维持的数码以前被调用。在那边大家应当移除全部对旧数据的使用(因为旧数据不久就能够被假释),可是绝不释放旧数据,因为Loader会帮大家做到旧数据的自由。

Loader大器晚成旦知道App不再动用旧数据就能够放出掉。举例,借使数据出自CursorLoader里的二个Cursor,大家不该团结在代码中调用close(卡塔尔(قطر‎方法;假如多个Cursor正在被停放到二个CursorAdapter时大家应当接收swapCursor(卡塔尔国举行新数据沟通,那样正在被放置的旧的Cursor就不会被关掉,也就不会引致艾达pter的加载非常。

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

对获得的Cursor数据设置需求监听的U奇骏I(即,在ContentProvider的query(卡塔尔国方法可能Loader的loadingBackground(State of Qatar方法中调用Cursor的setNotificationUri(State of Qatar方法);

Android中还提供了三个CursorLoader类,它是AsyncTaskLoader的子类,一个异步的加载数据的类,经过ContentResolver的正式查询并再次来到四个Cursor。这几个类达成了Loader的商量,未来生可畏种标准的秘诀查询Cursor。

4-4 进阶总计

由早先边功底实例、源码解析、进级演示你会意识Loader的确实相当好用,超帅呆了,屌爆了的我不想再解释什么了,自身心得呢。

PS:以前见到博客园上有人研讨AsyncTaskLoader与AsyncTask的界别,那下通透到底明朗了,看完源码大家再回过头来总括性的说说她们相互分别,如下:

class 优势 劣势
AsyncTaskLoader 会自动刷新数据变化;会自动处理Activiy配置变化造成的影响;适合处理纯数据加载; 不能实时通知UI刷新;不能在onLoadFinished时主动切换生命周期(譬如replace Fragment);
AsyncTask 可以与UI实时交互及replace操作; 不会自动处理Activiy配置变化造成的影响;

好了,该撕逼的也撕了,该说大话的也装了,该分析的也解析了,该学习的也学到了,接下去正是看本身什么带着Loader去叱诧风波了。

onLoadFinished()
load达成之后回调此方式;每便都调用

 

2 根基运用实例

该底蕴实例解说完全出自于官方文书档案,详细能够点击自身翻理念语原著。

既然接下去计划要说说她的施用苍劲的地方了,那不要紧大家先来一张图直观的感性认知下不用Loader(左)与用Loader(右)对大家开垦者及代码复杂度和框架的熏陶呢,如下:

图片 6

Loader源码在android.content上面,可以见到它的分占的额数有多种,loader机制包涵LoaderManager,Loader,LoaderCallbacks三片段,
LoaderManager 来管理大家的laoder实例,获取,开首化,重启叁个loader,
Loader 来实施大家的异步操作,有始发,达成,后台加载中等接口完成
LoaderCallbacks 来实践我们的loader回调,首倘诺绑定分发Loader,完毕加载,重新设置数据等。
流程如下图:

适用于Android3.0以至越来越高的版本,它提供了意气风发套在UI的主线程中异步加载数据的框架。使用Loaders能够特别简单的在Activity也许Fragment中异步加载数据,平常适用于大批量的数据查询,或然须要平时修正并登时呈现的多少展现到UI上,那样能够制止查询数据的时候,形成UI主线程的卡顿。

3-3-2 AsyncTaskLoader虚无子类源码浅析

上边既然说了Loader类的效能至关心珍视即使鲜明接口,同临时候供LoaderManager管理,那LoaderManager管理的Loader自然须要做一些职业,也正是说大家须求三番五次Loader完成部分逻辑操作。可是还好系统API已经帮大家贯彻了有些大概的包裹实现,大家那边就先来看下Loader的直接子类AsyncTaskLoader吧,先来看下该抽象子类的章程及其间类粗略图,如下:

图片 7

代码剖析如下:

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 {
        ......
        @Override
        protected D doInBackground(Void... params) {
            try {
                //AsyncTask的子线程中执行AsyncTaskLoader的onLoadInBackground方法!!!!重点
                D data = AsyncTaskLoader.this.onLoadInBackground();
                //把执行结果数据D返回到UI线程
                return data;
            } catch (OperationCanceledException ex) {
                if (!isCancelled()) {
                    throw ex;
                }
                return null;
            }
        }

        /* Runs on the UI thread */
        @Override
        protected void onPostExecute(D data) {
            //AsyncTask子线程执行完毕后回调AsyncTaskLoader的dispatchOnLoadComplete方法
            AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
        }

        /* Runs on the UI thread */
        @Override
        protected void onCancelled(D data) {
            //取消AsyncTask时调运
            AsyncTaskLoader.this.dispatchOnCancelled(this, data);
        }

        //Runnable的实现方法
        @Override
        public void run() {
            waiting = false;
            AsyncTaskLoader.this.executePendingTask();
        }
    ......
    }

    private final Executor mExecutor;

    volatile LoadTask mTask;
    volatile LoadTask mCancellingTask;

    long mUpdateThrottle;
    long mLastLoadCompleteTime = -10000;
    Handler mHandler;
    //public构造方法
    public AsyncTaskLoader(Context context) {
        this(context, AsyncTask.THREAD_POOL_EXECUTOR);
    }

    /** {@hide} 无法被外部调运的构造方法 */
    public AsyncTaskLoader(Context context, Executor executor) {
        super(context);
        mExecutor = executor;
    }

    public void setUpdateThrottle(long delayMS) {
        mUpdateThrottle = delayMS;
        if (delayMS != 0) {
            mHandler = new Handler();
        }
    }

    @Override
    protected void onForceLoad() {
        super.onForceLoad();
        //取消当前的Loader
        cancelLoad();
        //新建task并执行
        mTask = new LoadTask();
        executePendingTask();
    }

    @Override
    protected boolean onCancelLoad() {
        ......
    }

    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.
                    mTask.waiting = true;
                    mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
                    return;
                }
            }
            //真正的触发执行AsyncTask方法
            mTask.executeOnExecutor(mExecutor, (Void[]) null);
        }
    }

    void dispatchOnCancelled(LoadTask task, D data) {
        onCanceled(data);
        if (mCancellingTask == task) {
            rollbackContentChanged();
            mLastLoadCompleteTime = SystemClock.uptimeMillis();
            mCancellingTask = null;
            //触发Loader的接口方法onLoadCanceled,在LoaderManager中实现
            deliverCancellation();
            executePendingTask();
        }
    }

    void dispatchOnLoadComplete(LoadTask task, D data) {
        if (mTask != task) {
            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;
                //触发Loader的接口方法onLoadComplete,在LoaderManager中实现
                deliverResult(data);
            }
        }
    }
    //需要子类实现!!!!!在子线程中执行
    public abstract D loadInBackground();

    //LoadTask(AsyncTask的子线程中回调)中调运
    protected D onLoadInBackground() {
        return loadInBackground();
    }

    //LoadTask(AsyncTask的onCancelLoad中回调)调运
    public void cancelLoadInBackground() {
    }

    public boolean isLoadInBackgroundCanceled() {
        return mCancellingTask != null;
    }
    //锁标记处理
    public void waitForLoader() {
        LoadTask task = mTask;
        if (task != null) {
            task.waitForLoader();
        }
    }
}

能够望见上面继续Loader的AsyncTaskLoader其实质是提供了多少个依据AsyncTask工作体制的Loader(子类LoadTask世袭AsyncTask<Void, Void, D>,况兼达成了Runable接口,作用特别精锐。),不过不得直接用,因为其为abstract抽象类,所以大家需求继续实现它手艺够运用,不过辛亏系统API已经帮大家提供了她现有的子类CursorLoader,但CursorLoader同不常候也限定了Loader的泛型数据为Cursor类型。当然了,大家倘诺想要Loader自身的连串数据那也很简短—世袭完结AsyncTaskLoader就可以,前面会付出例子的。

地方initLoader(卡塔尔方法的调用二个Loader被起头化和激活的动静,该方法的调拨运输犹如下二种结果:

从LoaderCallbacks的宣示的多少个艺术中得以看见,它是八个泛型的接口,须求钦赐Loader数据的等级次序。假诺是数据源是从五个ContentProvider中收获的,平日直接行使它的子类CursorLoader,上边介绍CursorLoader。

3-1 Activity及Fragment中LoadManager的管住浅析

第黄金时代我们都知晓,在选取Loader的率先步就是在Activity可能Fragment中获得LoaderManager实例,所以我们先来看下Activity和Fragment是何等管理这个LoaderManager的。

先来探问Fragment中的LoaderManager,如下:

final class FragmentState implements Parcelable {
    ......
    LoaderManagerImpl mLoaderManager;
    boolean mLoadersStarted;
    boolean mCheckedForLoaderManager;
    ......
    //fragment中获取LoaderManager办法
    public LoaderManager getLoaderManager() {
        //可以看见,一个Fragment只有一个LoaderManager
        if (mLoaderManager != null) {
            return mLoaderManager;
        }
        if (mActivity == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mCheckedForLoaderManager = true;
        //从Activity中获取LoaderManager,传入的mWho为当前Fragment的识别key,然后create传入true表示创建!!!!!!
        mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);
        return mLoaderManager;
    }

    public void onStart() {
        mCalled = true;

        if (!mLoadersStarted) {
            mLoadersStarted = true;
            if (!mCheckedForLoaderManager) {
                mCheckedForLoaderManager = true;
                //如果还没调运过getLoaderManager,那就尝试获取LoaderManager,传入的create为false!!!!!
                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
            }
            //生命周期依附上LoaderManager
            if (mLoaderManager != null) {
                mLoaderManager.doStart();
            }
        }
    }

    public void onDestroy() {
        mCalled = true;
        if (!mCheckedForLoaderManager) {
            mCheckedForLoaderManager = true;
            //如果还没调运过getLoaderManager,那就尝试获取LoaderManager,传入的create为false!!!!!
            mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
        }
        //生命周期依附上LoaderManager
        if (mLoaderManager != null) {
            mLoaderManager.doDestroy();
        }
    }

    void performStart() {
        ......
        mCalled = false;
        onStart();
        ......
        //生命周期依附上LoaderManager
        if (mLoaderManager != null) {
            mLoaderManager.doReportStart();
        }
    }

    void performStop() {
        ......
        mCalled = false;
        onStop();
        ......
        if (mLoadersStarted) {
            mLoadersStarted = false;
            if (!mCheckedForLoaderManager) {
                mCheckedForLoaderManager = true;
                //如果还没调运过getLoaderManager,那就尝试获取LoaderManager,传入的create为false!!!!!
                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
            }
            if (mLoaderManager != null) {
                //生命周期依附上LoaderManager
                if (mActivity == null || !mActivity.mChangingConfigurations) {
                    mLoaderManager.doStop();
                } else {
                    mLoaderManager.doRetain();
                }
            }
        }
    }

    void performDestroyView() {
        ......
        mCalled = false;
        onDestroyView();
        ......
        //生命周期依附上LoaderManager
        if (mLoaderManager != null) {
            mLoaderManager.doReportNextStart();
        }
    }
}

从上边能够看看,Fragment在其生命周期内会调节LoaderManager(LoaderManager其实调控了Loader)的doStart、doDestroy等措施,也正是说我们在Fragment中只管经过getLoaderManager方法来拿到LoaderManager实例,然后利用就能够,别的Fragment都会帮大家管理OK的。

接下去看看Activity中的LoaderManager,如下:

public class Activity extends ContextThemeWrapper implements ... {
        //mAllLoaderManagers保存了Activity与Fragment的所有LoaderManager
    ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;
    LoaderManagerImpl mLoaderManager;
    ......
    //Activity中获取LoaderManager实例的方法
    public LoaderManager getLoaderManager() {
        //可以看见,一个Activity只有一个LoaderManager
        if (mLoaderManager != null) {
            return mLoaderManager;
        }
        mCheckedForLoaderManager = true;
        //咦?这不就是上面Fragment的getLoaderManager中调运的那个activity中的getLoaderManager吗,只是和这里的参数不一样而已
        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
        return mLoaderManager;
    }
    //Activity与Fragment获取LoaderManager实例的真正方法!!
    LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
        //可见一个Activity维护一个mAllLoaderManagers的MAP
        if (mAllLoaderManagers == null) {
            mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();
        }
        //尝试从缓存mAllLoaderManagers的MAP中获取已经实例化的LoaderManager实例
        LoaderManagerImpl lm = mAllLoaderManagers.get(who);
        if (lm == null) {
            if (create) {
                //如果没有找到并且需要实例化create(切记这个create参数是很重要的),就调运LoaderManagerImpl构造方法实例化一个LoaderManager对象,然后存入缓存mAllLoaderManagers的MAP中
                lm = new LoaderManagerImpl(who, this, started);
                mAllLoaderManagers.put(who, lm);
            }
        } else {
            lm.updateActivity(this);
        }
        return lm;
    }

    void invalidateFragment(String who) {
        if (mAllLoaderManagers != null) {
            LoaderManagerImpl lm = mAllLoaderManagers.get(who);
            if (lm != null && !lm.mRetaining) {
                //生命周期依附上LoaderManager
                lm.doDestroy();
                mAllLoaderManagers.remove(who);
            }
        }
    }

    final void performStop() {
        if (mLoadersStarted) {
            mLoadersStarted = false;
            //生命周期依附上LoaderManager
            if (mLoaderManager != null) {
                //mChangingConfigurations表示如果当前发生了配置变化则为true,否则为false!!!!!!!重点,Loader特性之一
                if (!mChangingConfigurations) {
                    //当前Activity的stop不是由配置变化引起则直接调用LoaderManager的doStop()方法!!!!!!
                    mLoaderManager.doStop();
                } else {
                    //当前Activity配置变化,所以需要保存当前的loaderManager,在Activity恢复时恢复这个LoaderManager!!!!!!
                    mLoaderManager.doRetain();
                }
            }
        }
    ......
    }

    final void performDestroy() {
        ......
        onDestroy();
        //生命周期依附上LoaderManager
        if (mLoaderManager != null) {
            mLoaderManager.doDestroy();
        }
        ......
    }

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (mLastNonConfigurationInstances != null) {
            //从mLastNonConfigurationInstances中恢复mAllLoaderManagers(mLastNonConfigurationInstances是从onAttach中恢复的),Activity配置变化时会走这里!!!!
            mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
        }
        ......
        mCalled = true;
    }

    final void performStart() {
    ......
        if (mAllLoaderManagers != null) {
            final int N = mAllLoaderManagers.size();
            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
            for (int i=N-1; i>=0; i--) {
                loaders[i] = mAllLoaderManagers.valueAt(i);
            }
            //生命周期依附上LoaderManager
            for (int i=0; i<N; i++) {
                LoaderManagerImpl lm = loaders[i];
                //调用LoaderManager.finishRetain()以及doReportStart()方法来恢复LoaderManager的状态!!!!!
                lm.finishRetain();
                lm.doReportStart();
            }
        }
        mActivityTransitionState.enterReady(this);
    }
    //该方法会被ActivityThread类调用,且调运时机早于performDestroy()方法!!!!!!
    NonConfigurationInstances retainNonConfigurationInstances() {
        ......
        NonConfigurationInstances nci = new NonConfigurationInstances();
        ......
        //配置变化时保存mAllLoaderManagers!!!!!!
        nci.loaders = mAllLoaderManagers;
        return nci;
    }
}

通过上边的解析能够窥见,Activity其实真正的军事拘系了Activity及Fragment的LoaderManager(Fragment也会管理有个别和谐LoaderManager的周期),而LoaderManager又治本了Loader,能够窥见他们分别的关押范围都以不行的清晰明了的。

LoaderManager.LoaderCallbacks是LoaderManager的回调交互作用接口。LoaderManager.LoaderCallbacks包罗以下两个方法:

1、Loaders:

Copyright © 2015-2019 http://www.carrefourstation.com. 澳门新莆京手机网站-新蒲京娱乐场有限公司 版权所有