Android CursorLoader实例详解(附源码)

来源:互联网 发布:cf宏鼠标一键瞬狙数据 编辑:程序博客网 时间:2024/04/29 09:59

Android Loader的基本知识前面几篇博客已经涉及很多,接下来这篇博客将会结合一个实际Demo来描述Loader的使用,该Demo是Contacts 联系人,自定义ContentProvider的内容,提供Uri,在显示联系人列表出使用的是Cursor 的 contentResolver.query 方法,在搜索联系人部分用到了CursorLoader,下面结合这个Demo 来描述Loader的使用。

Demo 截图如下:



下面对该Demo的各个函数进行详解。搜索界面的代码是一个由Fragment组成的Activity,fragment 代码如下:

package com.uppowerstudio.chapter5.phonebook;import android.app.ListFragment;import android.app.LoaderManager;import android.content.CursorLoader;import android.content.Loader;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.text.TextUtils;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.widget.SearchView;import android.widget.SearchView.OnQueryTextListener;import android.widget.SimpleCursorAdapter;import com.uppowerstudio.chapter5.phonebook.database.Constants;public class CursorLoaderListFragment extends ListFragment implementsConstants, OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {SimpleCursorAdapter mAdapter;String mCurFilter;@Overridepublic void onActivityCreated(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onActivityCreated(savedInstanceState);//设置包含菜单项setHasOptionsMenu(true);mAdapter = new SimpleCursorAdapter(getActivity(), R.layout.list_row,null, new String[] { "contact_name", "phone_number" },new int[] { R.id.list_item_contact_name,R.id.list_item_contact_phone }, 0);setListAdapter(mAdapter);//初始化Loader ,Loader的ID 为0getLoaderManager().initLoader(0, null, this);  }@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {// TODO Auto-generated method stubsuper.onCreateOptionsMenu(menu, 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);}@Overridepublic boolean onQueryTextSubmit(String query) {// TODO Auto-generated method stubreturn true;}@Overridepublic boolean onQueryTextChange(String newText) {// TODO Auto-generated method stubmCurFilter = !TextUtils.isEmpty(newText) ? newText : null;getLoaderManager().restartLoader(0, null, this);return true;}@Overridepublic Loader<Cursor> onCreateLoader(int id, Bundle args) {// TODO Auto-generated method stubUri baseUri;if (mCurFilter != null) {baseUri = Uri.withAppendedPath(Constants.CONTENT_URI,Uri.encode(mCurFilter));} else {baseUri = Constants.CONTENT_URI;}return new CursorLoader(getActivity(), baseUri,null, null, null,COLUMN_ID);}@Overridepublic void onLoadFinished(Loader<Cursor> loader, Cursor data) {// TODO Auto-generated method stubmAdapter.swapCursor(data);}@Overridepublic void onLoaderReset(Loader<Cursor> loader) {// TODO Auto-generated method stubmAdapter.swapCursor(null);  }}


activity 代码比较简单,就不贴出来了

下面结合这个 Demo 对 CursorLoader进行详解。

initLoader() 函数

首先,我这里编写的查找联系人的布局是一个activity加fragment,在fragment的onActivityCreated()方法中,我们先初始化Loader,

getLoaderManager().initLoader(0, null, this); 
该函数中有3个参数,第一个是新建的Loader的ID,这里为0,第二个是Bunder类型的数据,这里设置为null,第三个是this,表示回调本身

onQueryTextChange() 函数


在这个Demo 中,我们添加了一个搜索栏用于搜索联系人,onQueryTextChange() 函数用于检测搜索框中的内容是否变化,一旦搜索栏中的内容发生变化,onQueryTextChange() 函数就会被调用。该函数的代码如下:
@Overridepublic boolean onQueryTextChange(String newText) {// TODO Auto-generated method stubmCurFilter = !TextUtils.isEmpty(newText) ? newText : null;getLoaderManager().restartLoader(0, null, this);return true;}

其中,mCurFilter是搜素栏过滤器,用于获取搜素栏的内容。当onQueryTextChange()被调用时,还调用了getLoaderManager().restartLoader(0, null, this);  函数,这个函数用于重新开启一个新的Loader,虽然说是restart,但是我们注意到这个函数有3个参数,第一个是 ID,即新的Loader 的 ID ,这里为 0 ,第二个参数是一个 Bundle 类型的数据,是一个可选参数,这里设置为null,没什么影响,第三个是 this ,表示回调它本身。

但是restartLoader()  这个函数并非将当前的 Loader 重启,如果之前restartLoader() 方法中的Loader的ID存在,即与之前调用initLoader()方法时的ID一致,则销毁这个Loader,并重新创建一个新的,ID相同的Loader,如果这个ID与之前调用initLoader()方法时的ID不一样,则重新创建一个id为这个ID的新Loader。但此时之前创建的Loader并不会被关闭,依旧可以被使用,至于创建的Loader什么时候被关闭呢?这个下面再解释。

onCreateLoader() 方法


该方法主要用于创建一个新的Loader,这里我们创建了一个CursorLoader用于异步查询联系人,避免ContentProvider应用Cursor查询时可能导致的UI阻塞。代码如下:

@Overridepublic Loader<Cursor> onCreateLoader(int id, Bundle args) {// TODO Auto-generated method stubUri baseUri;if (mCurFilter != null) {baseUri = Uri.withAppendedPath(Constants.CONTENT_URI,Uri.encode(mCurFilter));} else {baseUri = Constants.CONTENT_URI;}return new CursorLoader(getActivity(), baseUri,null, null, null,COLUMN_ID);}

onCreateLoader()方法有两个参数,第一个就是新创建的Loader的ID,第二个就是之前调用initLoader()restartLoader()方法时的第二个参数Bundle类型的数据。

在这里,我们使用之前在onQueryTextChange()函数中使用到的搜索过滤器mCurFilter, 该过滤器其实就是搜索栏的内容,在这里,我们将问题简单化,将搜索框的内容添加到搜索Uri的后面作为搜索联系人的ID,添加的方法为:
Uri.withAppendedPath(Constants.CONTENT_URI,Uri.encode(mCurFilter)) 
这句代码将搜索栏的内容转码为Uri并添加到CONTENT_URI 后面,其实也就是在CONTENT_URI  content://com.uppowerstudio.chapter5.phonebook.provider/phonebook  后面加上 ID,形成新的查询某个联系人的Uri
content://com.uppowerstudio.chapter5.phonebook.provider/phonebook/#   
其中 # 代表任意数字,这里为联系人的ID

onCreateLoader()函数最后返回新建了一个 CursorLoader ,其中getActivity()表示结果返回到这个fragment所绑定的那个activity,baseUri 即是我们要查询的Uri,这里是某个联系人的Uri,三个nul分别是projection,selection,selectionArgs,这里我们均设置为null,这几个参数的定义可以参考 ContentResolove.query() ,这里不再详细描述,最后一个是排序的方式,我们选择了ID,即显示查找到的联系人的时候按照查找出来的联系人的ID来排序。

onLoadFinished() 函数


在查询函数加在完毕之后,onLoaderFinish() 函数就会被调用,该函数的代码如下:

@Overridepublic void onLoadFinished(Loader<Cursor> loader, Cursor data) {// TODO Auto-generated method stubmAdapter.swapCursor(data);}

该方法中调用了设配器 mAdapter的swapCursor()方法,在加在数据完成后,将加载到的Cursor类型的数据data交换到mAdapter中并显示出来。该函数调用时,用户必须停止对 Cursor 中的数据的引用,因为这些数据即将被删除,但是用户不用也不要调用cursor的close()方法,以为在ContentProvider中用户需要调用cursor的close()方法,但是在CursorLoader中会自动关闭cursor,不用用户关闭。只要系统察觉到应用不再使用Cursor,系统就会自动关闭。

onLoaderReset()函数


该函数在推出搜索界面是被调用,用于将Loader的数据设置为不可用,如果之前新建了多个Loader,该函数就会被多次调用,每次调用都只会Reset 一个拥有独立ID的Loader。该函数的代码如下:
@Overridepublic void onLoaderReset(Loader<Cursor> loader) {// TODO Auto-generated method stubmAdapter.swapCursor(null);  }

在该函数中将null值交换到设配器中。

onQueryTextSubmit()函数


这个函数其实没什么用,在用户的搜索栏输入数据完毕之后,按下回车时,该函数就会被调用,表示提交数据。代码如下:
@Overridepublic boolean onQueryTextSubmit(String query) {// TODO Auto-generated method stubreturn true;}

至此,Loader 的讲解已经结束,完整客运行的Demo下载链接如下:

http://download.csdn.net/detail/llp1992/8106475


3 0