介绍:
Android 3.0引入加载器,支持在Activity 以及Fragment中异步加载数据。
可用于每个Activity 以及Fragment
支持异步加载数据
监控其数据并在内容变化时传递新的结果
在某一个配置更改后重建加载器时,会自动重新链接上一个加载器的Cursor,因此,他们无需重新查询其数据。
使用:
1 在Activity中可以调用getSupportLoaderManager()方法返回 LoaderManager的对象。
mLoaderManager = getSupportLoaderManager();
这里返回的是V4包下面的LoaderManager对象。
2 启动加载器。
mLoaderManager.initLoader(LOADER_ID, bundle, new MainPageLoaderCallBack());
initLoader() 方法采用以下参数:
int id 用于标识加载器的唯一 ID。在此示例中,ID 为 1。
Bundle args 在构建时提供给加载器的可选参数。
LoaderManager.LoaderCallbacks 实现, LoaderManager 将调用此实现来报告加载器事件。
initLoader() 调用确保加载器已初始化且处于Activity状态。这可能会出现两种结果:
如果 ID 指定的加载器已存在,则将重复使用上次创建的加载器。
如果 ID 指定的加载器不存在,则 initLoader() 将触发 LoaderManager.LoaderCallbacks 方法 onCreateLoader()。
在此方法中,我们可以实现代码以实例化并返回新加载器。之后我们会有实例展示如何使用。
initLoader()方法会返回Loader对象。LoaderManager 将自动管理加载器的生命周期。
LoaderManager 将根据需要启动和停止加载,并维护加载器的状态及其相关内容。这意味着我们很少需要与Loader的这个对象交互。
3 LoaderManager 还有一个方法为restartLoader(),即为重启Loader。
当存在含有制定Id的加载器,但你又想放弃之前的旧数据,重新开始执行,就可以电泳restartLoader()方法,参数和initLoader()方法一样。
4 LoaderManager.LoaderCallbacks 的几个回调方法:
onCreateLoader():针对指定的 ID 进行实例化并返回新的 Loader
一般我们会在这个方法中创建具体的Loader实例,用于做具体的逻辑。在下面我写的小Demo中在该方法中,创建了AsyncTaskLoader实例,用于异步加载数据。
onLoadFinished(Loader loader, D data) :将在先前创建的加载器完成加载时调用
当完成加载后,会执行这个方法,我们可以通过其传递回来的参数做我们想做的事情。因为整个Loader框架利用泛型,我们在实例化LoaderCallbacks时,所指定的类型,就是onLoadFinished
第二个参数返回的类型。
onLoaderReset(): 将在先前创建的加载器重置且其数据因此不可用时调用。
这个没什么好说的,目前我还没有用到过。
下面我们来看一个简单的实例:(这里没有用Google给的实例,我自己写了一个简单的实例,我觉得这个例子更能体现其使用的场景。)
public class MainActivity extends AppCompatActivity {
private LoaderManager mLoaderManager;
private static final String TAG = "main";
private int LOADER_ID = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLoaderManager = getSupportLoaderManager();
if(mLoaderManager.getLoader(LOADER_ID) == null) {
mLoaderManager.initLoader(LOADER_ID, null, new MainPageLoaderCallBack(this)).forceLoad();
}else {
mLoaderManager.restartLoader(LOADER_ID, null, new MainPageLoaderCallBack(this)).forceLoad();
}
}
public static class MainPageLoaderCallBack implements LoaderManager.LoaderCallbacks<String>{
private Context context;
public MainPageLoaderCallBack(Context context) {
this.context = context;
}
@Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new MainPageLoader(context);
}
@Override
public void onLoadFinished(Loader<String> loader, String data) {
Log.d(TAG,"data : "+data);
}
@Override
public void onLoaderReset(Loader<String> loader) {
}
}
public static class MainPageLoader extends AsyncTaskLoader<String> {
public MainPageLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
super.onStartLoading();
}
@Override
protected void onStopLoading() {
super.onStopLoading();
}
@Override
public String loadInBackground() {
try{
Thread.sleep(5000);
}catch (Exception e){
}
return "load info";
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mLoaderManager != null) {
mLoaderManager.destroyLoader(LOADER_ID);
}
}
}
其实上面的这个Demo,很好理解了,我相信你耐着心看到这里,一定能理解。哈哈。(在Demo中用的是V4包下面的加载器)
利用AsyncTaskLoader可以执行耗时的加载操作,甚至可以用来联网获取数据。
下面说一下在实际应用中,遇到的问题。
首先在上面的这个Demo中,除了loadInBackground()方法在子线程中,其他的回调方法都在主线程中。
在实际应用中遇到了这样的情况,调用了initLoader()方法启动加载器后,loadInBackground()方法不执行,
看Google给的Demo没有看到这样的说明,后来查找API无意间看到forceLoad()方法,调用之后,真个问题就解决了。
在利用其他Loader则不需要调用这个方法。