Loader 小记

装载器从android3.0开始引进。它使得在activityfragment中异步加载数据变得简单。从谷歌文档中可以看到,它具有以下四个特性:

1. 他们对每个 activity 和 fragment 都有效。(因为 loader 对象需要 LoaderManager 来管理,而在 activity 和 fragment 中能获取到 LoaderManager 对象。其实 fragment 拿到的 LoaderManager 对象是 其所绑定的 activity 中的 LoaderManager 对象)。

2. 他们提供了 异步加载数据 的能力

3. 他们监视数据源,并在数据源改变时传递新的结果。

4. 在其所在的 activity 或者 fragment 由于设备配置改变而被重新启动后,它可以自动链接到之前使用的加载器,从而不需要重新查询结果。


LoaderManager 中的 initLoader() 方法用来初始化一个 loader。在这个方法中,首先根据传入的参数,判断这个 id 对应的loader是否已经存在并且有效,如果存在并有效,那么只是给已存在的loader对象换一个回调函数;否则创建一个新的loader对象,此时调用传入的回调函数中的 onCreateLoader 方法。获取到loader对象之后,判断当前的 activity 是否可见(started),可见就启动这个loader,让它开始加载数据(因为 LoaderManager 会在 activity 进行到 onStart 方法的时候,自动启动所有的loader开始加载数据)。所谓的“让它开始加载数据”,只不过是调用 loader 对象的 startLoading 方法而已。在这个方法中,设置了三个布尔量的值,然后调用了 onStartLoading() 方法来加载数据。在我们自定义 loader 的时候,继承的 AsyncTaskLoader 类中的 onStartLoading() 方法只有一个空方法体。所以此时我们一定要覆写 onStartLoading() 方法,并且在其中调用 forceLoad() 方法来强制加载数据。


loader 的回调函数中的 onLoaderReset() 方法让我难以理解,所以研究了一下。发现只有在 destroy 一个 loader 的时候才有可能调用 onLoaderReset 这个方法,下面是贴一段代码大家一看就明白了(代码摘自android源码 LoaderManager.java 中)。

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 (mActivity != null) {
                    lastBecause = mActivity.mFragments.mNoTransactionsBecause;
                    mActivity.mFragments.mNoTransactionsBecause = "onLoaderReset";
                }
                try {
                    mCallbacks.onLoaderReset(mLoader);
                } finally {
                    if (mActivity != null) {
                        mActivity.mFragments.mNoTransactionsBecause = lastBecause;
                    }
                }
            }
            mCallbacks = null;
            mData = null;
            mHaveData = false;
            if (mLoader != null) {
                if (mListenerRegistered) {
                    mListenerRegistered = false;
                    mLoader.unregisterListener(this);
                    mLoader.unregisterOnLoadCanceledListener(this);
                }
                mLoader.reset();
            }
            if (mPendingLoader != null) {
                mPendingLoader.destroy();
            }
        }
所以一般在 onLoaderReset 方法中释放该 loader 中的数据。从以上代码还可以看到,在这里还调用了 mLoader.reset 方法,这个方法也会引起一个方法 onReset() 调用(属于 loader 的方法)。这个我们在自定义 loader 时也用得到,同样处理释放相关的操作。


loader还有一个操作是 restart,这个就是“ 重新创建一个使用这个id的loader ”。  


关于自定义 Loader,大家可以参考下 Api Demos 中的 App --> Loader --> Custom 。

以下是我看例子总结的一些重点:

1. 自定义的数据集(在例子中就是 AppListAdapter ),要有一个 public 的方法来设置数据;

2. 自定义的 loader 要记得自己驱动 加载数据 和 释放数据的过程;

3. 自定义的 loader 要自己实现对数据源的监控和实时更新自己的数据(在例子中是通过定义 BroadCastReceiver 来实现的)。

4. 以内部类的形式来实现自定义 loader 的话,该内部类必须是 static 的,否则会抛出异常,使程序崩溃。

5. loader 的回调方法都是在 初始化该loader的方法所在的线程中 执行的,加载数据的过程是在其他线程。


AsyncTaskLoader 类中的 setUpdateThrottle 方法可以设置两次 load 之间的最小时间间隔。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值