Android应用程序后台加载数据
从ContentProvider查询你需要显示的数据是比较耗时的。如果你在Activity中直接执行查询的操作,那么有可能导致Activity出现ANR的错误。即使没有发生ANR,用户也容易感知到一个令人烦恼的UI卡顿。为了避免那些问题,你应该在另外一个线程中执行查询的操作,等待查询操作完成,然后再显示查询结果。
通过CursorLoader对象,你可以用一种简单的方式实现异步查询,查询结束时它会和Activity进行重新连接。 CursorLoader不仅仅能够实现在后台查询数据,还能够在查询数据发生变化时自动执行重新查询的操作。

主题一:使用CursorLoader执行查询任务
CursorLoader通过ContentProvider在后台执行一个异步的查询操作,并且返回数据给调用它的Activity或者FragmentActivity。这使得Activity或者FragmentActivity能够在查询任务正在执行的同时继续与用户进行其他的交互操作。
如何定义使用CursorLoader的Activity?
为了在Activity或者FragmentActivity中使用CursorLoader,它们需要实现LoaderCallbacks<Cursor>接口。CursorLoader会调用LoaderCallbacks<Cursor>定义的这些回调方法与Activity进行交互。
public class PhotoThumbnailFragment extends FragmentActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
...
}
如何初始化查询?
为了初始化查询,需要调用LoaderManager.initLoader()。这个方法可以初始化LoaderManager的后台查询框架。你可以在用户输入查询条件之后触发初始化的操作,如果你不需要用户输入数据作为查询条件,你可以在onCreate()或者onCreateView()里面触发这个方法。
// Identifies a particular Loader being used in this component
private static final int URL_LOADER = 0;
...
/* When the system is ready for the Fragment to appear, this displays
* the Fragment's View
*/
public View onCreateView(
LayoutInflater inflater,
ViewGroup viewGroup,
Bundle bundle) {
...
/*
* Initializes the CursorLoader. The URL_LOADER value is eventually passed
* to onCreateLoader().
*/
getLoaderManager().initLoader(URL_LOADER, null, this);
...
}
需要注意的是:getLoaderManager()仅存在于Fragment类中;如果想要在FragmentActivity中获取到LoaderManager实例,可以调用getSupportLoaderManager()。
如何启动查询任务?
一旦后台任务被初始化好,它会执行你实现的回调方法onCreateLoader()。为了启动查询任务,会在这个方法里面返回CursorLoader。你可以初始化一个空的CursorLoader然后使用它的方法来定义你的查询条件,或者你可以在初始化CursorLoader对象的时候就同时定义好查询条件。
/*
* Callback that's invoked when the system has initialized the Loader and
* is ready to start the query. This usually happens when initLoader() is
* called. The loaderID argument contains the ID value passed to the
* initLoader() call.
*/
@Override
public Loader<Cursor> onCreateLoader(int loaderID, Bundle bundle)
{
/*
* Takes action based on the ID of the Loader that's being created
*/
switch (loaderID) {
case URL_LOADER:
// Returns a new CursorLoader
return new CursorLoader(
getActivity(), // Parent activity context
mDataUrl, // Table to query
mProjection, // Projection to return
null, // No selection clause
null, // No selection arguments
null // Default sort order
);
default:
// An invalid id was passed in
return null;
}
}
一旦后台查询任务获取到了这个Loader对象,就开始在后台执行查询的任务。当查询完成之后,会执行onLoadFinished()这个回调函数。
主题二:处理查询的结果
在 onCreateLoader()的回调里面使用CursorLoader执行加载数据的操作。Loader查询完后会调用Activity或者FragmentActivity的LoaderCallbacks.onLoadFinished()将结果回调回来。这个回调方法的参数之一是Cursor,它包含了查询的数据。你可以使用Cursor对象来更新需要显示的数据或者进行下一步的处理。
除了onCreateLoader()与onLoadFinished(),你也需要实现onLoaderReset()。这个方法在CursorLoader检测到Cursor上的数据发生变化的时候会被触发。当数据发生变化时,系统也会触发重新查询的操作。
如何处理查询的结果?
为了显示CursorLoader返回的Cursor数据,需要使用实现AdapterView的视图组件,,并为这个组件绑定一个实现了CursorAdapter的Adapter。系统会自动把Cursor中的数据显示到View上。
你可以在显示数据之前建立View与Adapter的关联。然后在onLoadFinished()的时候把Cursor与Adapter进行绑定。一旦你把Cursor与Adapter进行绑定之后,系统会自动更新View。当Cursor上的内容发生改变的时候,也会触发这些操作。
public String[] mFromColumns = {
DataProviderContract.IMAGE_PICTURENAME_COLUMN
};
public int[] mToFields = {
R.id.PictureName
};
// Gets a handle to a List View
ListView mListView = (ListView) findViewById(R.id.dataList);
/*
* Defines a SimpleCursorAdapter for the ListView
*
*/
SimpleCursorAdapter mAdapter =
new SimpleCursorAdapter(
this, // Current context
R.layout.list_item, // Layout for a single row
null, // No Cursor yet
mFromColumns, // Cursor columns to use
mToFields, // Layout fields to use
0 // No flags
);
// Sets the adapter for the view
mListView.setAdapter(mAdapter);
...
/*
* Defines the callback that CursorLoader calls
* when it's finished its query
*/
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
...
/*
* Moves the query results into the adapter, causing the
* ListView fronting this adapter to re-display
*/
mAdapter.changeCursor(cursor);
}
如何处理废旧的Cursor引用?
当Cursor失效的时候,CursorLoader会被重置。这通常发生在Cursor相关的数据改变的时候。在重新执行查询操作之前,系统会执行你的onLoaderReset()回调方法。在这个回调方法中,你应该删除当前Cursor上的所有数据,避免发生内存泄露。一旦onLoaderReset()执行结束,CursorLoader就会重新执行查询操作。
/*
* Invoked when the CursorLoader is being reset. For example, this is
* called if the data in the provider changes and the Cursor becomes stale.
*/
@Override
public void onLoaderReset(Loader<Cursor> loader) { /*
* Clears out the adapter's reference to the Cursor.
* This prevents memory leaks.
*/
mAdapter.changeCursor(null);
}
Android应用程序后台加载数据的更多相关文章
- Android中ListView动态加载数据
1. 引言: 为了提高ListView的效率和应用程序的性能,在Android应用程序中不应该一次性加载ListView所要显示的全部信息,而是采取分批加载策略,随着用户的滑动,动态的从后台加载所需的 ...
- java攻城狮之路(Android篇)--widget_webview_metadata_popupwindow_tabhost_分页加载数据_菜单
一.widget:桌面小控件1 写一个类extends AppWidgetProvider 2 在清单文件件中注册: <receiver android:name=".ExampleA ...
- Android中ListView分页加载数据
public class MainActivity extends Activity { private ListView listView=null; //listview的数据填充器 privat ...
- android 中使用缓存加载数据
最近app快完工了,但是很多列表加载,新闻咨询等数据一直从网络请求,速度很慢,影响用户体验,所以寻思用缓存来加载一些更新要求不太高的数据 废话不多说,上代码 欢迎转载,但请保留文章原始出处:) 博客 ...
- Android 自定义ListView动态加载数据
我们都知道网络取数据是耗时操作,如果我们一次性请求所有数据,假如数据量不多那还可以接受,但是如果数据量特别多,那么带来的后果就是用户的愤怒(用户是很没有耐心的),所以这时候我们就需要动态的加载数据,分 ...
- HighCharts 后台加载数据的时候去掉默认的 series
var chart; var options = { chart: { renderTo: 'container', type:'line' }, title: { text: '历史趋势时序图', ...
- Android中ListView异步加载数据
1.主Activity public class MainActivity extends Activity { private ListView listView; private ArrayLis ...
- MVC中使用Echart后台加载数据 实现饼图、折线图、全国地图数据,单击双击事件等
@{ Layout = null; } @if (false) { <script src="~/Js/jquery-easyui-1.5/jquery.min.js"> ...
- 根据后台加载数据,添加loading动画
<script> var current = 0; var hit = @hits; $(this).scroll(function(){ var viewHeight =$(this). ...
随机推荐
- CF24D Broken robot
题目链接 题意 有一个\(n \times m\)的矩阵.机器人从点\((x,y)\)开始等概率的往下,往右,往左走或者不动.如果再第一列,那么不会往左走,再第m列不会往右走.也就是说机器人不会走出这 ...
- Memcached操作
标准协议和字段 Memcached的标准协议字段包含以下部分: 键,key,任意字符,最大250字节,不能有空格和换行 标志位,32比特,不能为0 超时时间,单位是秒,0代表永不超时,最长30天,30 ...
- 用servlet校验密码2
首先,mysql真的让我有点扎心,虽然安装了但是之前没用过 第一个 初始密码给我设了fj4X1=).......一长串字符,怎么记得住嘛,再说,我记那玩意儿干啥呀 所以 果断决定改个不费脑子的密码 但 ...
- 剑指Offer_编程题_22
题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序 ...
- 金融量化分析【day113】:布林带策略
一.布林带策略简介 1.简介 2.计算公式 3.图形 二.布林带策略代码 import jqdata def initialize(context): set_benchmark('0000 ...
- updateXML 注入 python 脚本
用SLQMAP来跑updateXML注入发现拦截关键字,然后内联注入能绕,最后修改halfversionedmorekeywords.py脚本,结果SQLMAP还是跑不出来.>_< hal ...
- Educational Codeforces Round 55 (Rated for Div. 2)
D. Maximum Diameter Graph 题意 给出每个点的最大度,构造直径尽可能长的树 思路 让度数大于$1$的点构成链,考虑是否能在链的两端加度为$1$的点 代码 #include &l ...
- excel合并
import org.apache.commons.lang.StringUtils; import org.apache.poi.hssf.usermodel.HSSFWorkbook; impor ...
- Django REST Framework API Guide 08
1.Filtering 2.Pagination FIltering GenericAPIView的子类筛选queryset的简单方法是重写.get_quueryset()方法. 1.根据当前用户进行 ...
- # 20175333曹雅坤《Java程序设计》第1周学习总结
教材学习内容总结 1.学习第一章PPT,安装JRE,JDK并配置path环境参数 2.在windows上使用dos命令运行教材第一章代码Hello.java和People.java 3.下载使用git ...