Loader在android3.0以后出现,它可以使Activity和Fragment异步加载数据变得简单
当成批显示数据时,为了使用户的体验更好,需要进行异步装载,也就是说,让未显示数据的ListView等UI组件或控件先显示,避免出现白屏的尴尬现象,同时在后台下载数据,等下载完成后再更新ListView组件。这样尽管用户不会立刻看到数据,但是也不至于网络速度缓慢或服务器响应不及时而造成假死现象。
Loader的特性:
- 它对每个Activity和Fragment都有效
- 它提供了异步加载数据的能力
- 它拥有一个数据改变通知机制,当数据源做出改变时会及时通知。也就是可以监听数据源,一旦数据源发生变化,Loader会感知这些变化
- 当Cursor发生变化时,会自动加载数据,因此不需要再重新进行数据查询
API概述
- LoaderManager
一个抽像类,关联到一个Activity或Fragment,管理一个或多个装载器的实例。这帮助一个应用管理那些与Activity或Fragment的生命周期相关的长时间运行的的操作。最常见的方式是与一个CursorLoader一起使用,然而应用是可以随便写它们自己的装载器以加载其它类型的数据。
每个activity或fragment只有一个LoaderManager。但是一个LoaderManager可以拥有多个装载器。 - LoaderManager.LoaderCallbacks
一个用于客户端与LoaderManager交互的回调接口。例如,你使用回调方法onCreateLoader()来创建一个新的装载器。 - Loader(装载器)
一个执行异步数据加载的抽象类。它是加载器的基类。你可以使用典型的CursorLoader,但是你也可以实现你自己的子类。一旦装载器被激活,它们将监视它们的数据源并且在数据改变时发送新的结果。 - AsyncTaskLoader
提供一个AsyncTask来执行异步加载工作的抽象类。 - CursorLoader
AsyncTaskLoader的子类,它查询ContentResolver然后返回一个Cursor。这个类为查询cursor以标准的方式实现了装载器的协议,它的游标查询是通过AsyncTaskLoader在后台线程中执行,从而不会阻塞界面。使用这个装载器是从一个ContentProvider异步加载数据的最好方式。相比之下,通过fragment或activity的API来执行一个被管理的查询就不行
使用Loader的步骤
- 在Activity或者Fragment中,实现LoaderCallBack<Cursor>接口,并且声明加载数据结果的返回类型,重写父类的三个方法
Loader<Cursor> onCreateLoader(int id, Bundle args) //创建新的Loader,加载新的数据
void onLoadFinished(Loader<Cursor> loader, Cursor data) //加载数据完成后执行
void onLoaderReset(Loader<Cursor> loader) //在Loader加载数据之前,重置之前的数据 - 在Activity或者Fragment的初始化阶段的生命周期方法中 初始化启动Loader
/**
* id Loader的编号
* args Loader加载数据的条件
* callback Loader接口回调的方法
*/
getLoaderManager().initLoader(id, args, callback); - 在LoaderCallBacks的创建新的Loader的方法中(onCreateLoader) 实例化CursorLoader对象
CursorLoader loader = new CursorLoader(context, uri, projection, selection, selectionArgs, sortOrder)
//CursorLoader 内部使用了CotentResolver 加载ContentProvider暴露出来的数据,通过URI内置CotentObserver,监听数据源的变化 - 在LoaderCallBacks的加载数据完成的方法中(onLoadefinished) 将加载完成的数据显示在ListView中
adapter.changeCursor(arg1); - 在LoaderCallBacks的重置方法中(onLoaderReset), 清除之前的旧数据
adapter.changeCursor(null);
自定义Loader
- 定义一个类, 继承AsyncTaskLoader<D> ,声明返回结果的类型
- 重写方法 onStartLoading() , 执行方法: forceLoader()强制执行后台的方法, 加载数据
- 重写父类的方法 loadInBackground() , 在此方法中执行获取数据的操作, 并将结果返回
- 构造方法
实例(自定义Loader加载短信内容)
-
MainActivity.java
public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {
private ListView lv;
private SearchView sv;
private SimpleCursorAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);lv = (ListView) findViewById(R.id.lv); sv = (SearchView) findViewById(R.id.sv); adapter = new SimpleCursorAdapter(this, R.layout.item_lv, null, new String[]{"address","body"}, new int[]{R.id.address,R.id.body}, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); lv.setAdapter(adapter); getLoaderManager().initLoader(1, null, this); sv.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // TODO Auto-generated method stub return false; } @Override public boolean onQueryTextChange(String newText) { // TODO Auto-generated method stub Bundle bundle = new Bundle(); bundle.putString("key", newText); getLoaderManager().restartLoader(1, bundle, MainActivity.this); return false; } }); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { // TODO Auto-generated method stub MyLoader loader = new MyLoader(this,args); return loader; } @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) { // TODO Auto-generated method stub adapter.changeCursor(arg1); } @Override public void onLoaderReset(Loader<Cursor> arg0) { // TODO Auto-generated method stub adapter.changeCursor(null); } }
-
MyLoader
public class MyLoader extends AsyncTaskLoader<Cursor> {private Bundle bundle; private Uri uri = Uri.parse("content://sms"); private String []colums = {"_id","address","body"}; public MyLoader(Context context,Bundle bundle) { super(context); // TODO Auto-generated constructor stub this.bundle = bundle; } @Override protected void onStartLoading() { // TODO Auto-generated method stub super.onStartLoading(); forceLoad(); } @Override public Cursor loadInBackground() { // TODO Auto-generated method stub String selection = null; String[] selectionArgs = null; if (bundle!=null) { selection = "body like ? "; selectionArgs = new String[]{"%"+bundle.getString("key")+"%"}; } Cursor cursor = getContext().getContentResolver().query(uri, colums, selection, selectionArgs, null); return cursor; } }