从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应用程序后台加载数据的更多相关文章

  1. Android中ListView动态加载数据

    1. 引言: 为了提高ListView的效率和应用程序的性能,在Android应用程序中不应该一次性加载ListView所要显示的全部信息,而是采取分批加载策略,随着用户的滑动,动态的从后台加载所需的 ...

  2. java攻城狮之路(Android篇)--widget_webview_metadata_popupwindow_tabhost_分页加载数据_菜单

    一.widget:桌面小控件1 写一个类extends AppWidgetProvider 2 在清单文件件中注册: <receiver android:name=".ExampleA ...

  3. Android中ListView分页加载数据

    public class MainActivity extends Activity { private ListView listView=null; //listview的数据填充器 privat ...

  4. android 中使用缓存加载数据

    最近app快完工了,但是很多列表加载,新闻咨询等数据一直从网络请求,速度很慢,影响用户体验,所以寻思用缓存来加载一些更新要求不太高的数据 废话不多说,上代码 欢迎转载,但请保留文章原始出处:)  博客 ...

  5. Android 自定义ListView动态加载数据

    我们都知道网络取数据是耗时操作,如果我们一次性请求所有数据,假如数据量不多那还可以接受,但是如果数据量特别多,那么带来的后果就是用户的愤怒(用户是很没有耐心的),所以这时候我们就需要动态的加载数据,分 ...

  6. HighCharts 后台加载数据的时候去掉默认的 series

    var chart; var options = { chart: { renderTo: 'container', type:'line' }, title: { text: '历史趋势时序图', ...

  7. Android中ListView异步加载数据

    1.主Activity public class MainActivity extends Activity { private ListView listView; private ArrayLis ...

  8. MVC中使用Echart后台加载数据 实现饼图、折线图、全国地图数据,单击双击事件等

    @{ Layout = null; } @if (false) { <script src="~/Js/jquery-easyui-1.5/jquery.min.js"> ...

  9. 根据后台加载数据,添加loading动画

    <script> var current = 0; var hit = @hits; $(this).scroll(function(){ var viewHeight =$(this). ...

随机推荐

  1. pta寒假作业3

    题目三:捉老鼠啊,亏了还是赚了 实验代码 #include <stdio.h>     #include <stdlib.h> int main(void)    {      ...

  2. openstack项目【day24】:VLAN模式

    本节内容 一 二层基础知识 1.1 vlan介绍 1.1.1:vlan的含义 1.1.2:vlan的类型 1.1.3:vlan的不足 1.2 : 二层交换的基础知识 1.2.1:二层交换机最基本的功能 ...

  3. OpenStack VS Kubernetes,谁是你心中的王者?

      当下云计算的领域里热度最高的两个项目,无疑是OpenStack和Kubernetes.如果云计算是一个风起云涌的江湖,毫不夸张的说OpenStack和Kubernetes就是江湖里的泰山北斗.Op ...

  4. oldboy s21day07(深浅拷贝及文件操作)

    #!/usr/bin/env python# -*- coding:utf-8 -*- # 1.看代码写结果'''v1 = [1, 2, 3, 4, 5]v2 = [v1, v1, v1]v1.app ...

  5. jQuery AJAX 方法 success()后台传来的4种数据

    JAVA中的四种JSON解析方式详解 jQuery AJAX 方法 success()后台传来的4种数据 1.后台返回一个页面 js代码 /**(1)用$("#content-wrapper ...

  6. 锁定表头和固定列(Fixed table head and columns)

    源码: /// <summary> /// 锁定表头和列 /// <para> sorex.cnblogs.com </para> /// </summary ...

  7. Coursera, Big Data 2, Modeling and Management Systems (week 1/2/3)

    Introduction to data management 整个coures 2 是讲data management and storage 的,主要内容就是分布式文件系统,HDFS, Redis ...

  8. SQLserver 数据库高版本无法还原到低版本的数据解决方法

    sql server 数据库的版本只支持从上往下兼容.即高版本可以兼容低版本 .低版本不能兼容低版本.通常我们在开发时会用比较高的版本.但是部署到客户那边可能他们的数据库版本会比较低. 我们可以通过导 ...

  9. Django跨域请求

    一.jsonp方式 同源策略会阻止ajaxa请求,但不阻止src. jsonp方式其实是利用了<script>标签可以直接跨域的性质,在body中生成一个<script>标签, ...

  10. spring cloud 注册中心--eureka注册与发现

    本文详细介绍spring cloud微服务的默认注册中心--eureka注册与发现.开发环境需要Windows系统.jdk和intellij idea.与zookeeper注册中心相比,eureka不 ...