Android CursorLoader实例详解(附源码)

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 implements
		Constants, OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {

	SimpleCursorAdapter mAdapter;
	String mCurFilter;

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.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 为0
		getLoaderManager().initLoader(0, null, this);  
	}

	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		// TODO Auto-generated method stub
		super.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);
	}

	@Override
	public boolean onQueryTextSubmit(String query) {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean onQueryTextChange(String newText) {
		// TODO Auto-generated method stub
		mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
		getLoaderManager().restartLoader(0, null, this);
		return true;
	}

	@Override
	public Loader<Cursor> onCreateLoader(int id, Bundle args) {
		// TODO Auto-generated method stub
		Uri 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);
	}

	@Override
	public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
		// TODO Auto-generated method stub
		mAdapter.swapCursor(data);
	}

	@Override
	public void onLoaderReset(Loader<Cursor> loader) {
		// TODO Auto-generated method stub
		mAdapter.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() 函数就会被调用。该函数的代码如下:
	@Override
	public boolean onQueryTextChange(String newText) {
		// TODO Auto-generated method stub
		mCurFilter = !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阻塞。代码如下:

	@Override
	public Loader<Cursor> onCreateLoader(int id, Bundle args) {
		// TODO Auto-generated method stub
		Uri 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() 函数就会被调用,该函数的代码如下:

	@Override
	public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
		// TODO Auto-generated method stub
		mAdapter.swapCursor(data);
	}

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

onLoaderReset()函数


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

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

onQueryTextSubmit()函数


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

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

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


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值