装载器从android3.0开始引进。它使得在activity或fragment中异步加载数据变得简单。装载器具有如下特性:
-
它们对每个Activity和Fragment都有效。
-
他们提供了异步加载数据的能力。
-
它们监视数据源的一将一动并在内容改变时传送新的结果。
-
当由于配置改变而被重新创建后,它们自动重连到上一个加载器的游标,所以不必重新查询数据。
装载器API概述
在使用装载器时,会涉及很多类和接口们,我们在下表中对它们总结一下:
Class/Interface | 说明 |
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来执行一个被管理的查询就不行了。 |
上面所列的类和接口们是你在你的应用中要实现装载器时的核心组件。你的每个装载器并不一定需要所有的组件,但是你总是需要引用LoaderManager来初始化一个装载器。后面的章节将向你展示如何使用这些类和接口们。
一个使用装载器的应用会典型的包含如下组件:
-
一个Activity或Fragment.
-
一个LoaderManager的实例.
-
一个加载被ContentProvider所支持的数据的CursorLoader.或者,你可以从Loader或AsyncTaskLoader实现你自己的装载器来从其它源加载数据.
-
一个LoaderManager.LoaderCallbacks的实现.这是你创建新的装载器以及管理你的已有装载器的引用的地方.
-
一个显示装载器的数据的途径,例如使用一个SimpleCursorAdapter.
-
一个数据源,比如当是用CursorLoader时,它将是一个ContentProvider.
启动一个装载器
LoaderManager管理一个Activiry或Fragment中的一个或多个装载器.但每个activity或fragment只拥有一个LoaderManager.
你通常要在activity的onCreate()方法中或fragment的onActivityCreated()方法中初始化一个装载器.你可以如下创建:
- // 准备装载器.可以重连一个已经存在的也可以启动一个新的.
- getLoaderManager().initLoader(0,null, this);
initLoader() 方法有以下参数:
-
一个唯一ID来标志装载器.在这个例子中,ID是0.
-
可选的参数,用于装载器初始化时(本例中是null).
-
一个LoaderManager.LoaderCallbacks的实现.被LoaderManager调用以报告装载器的事件,在这个例子中,类本实现了这个接口,所以传的是它自己:this.
initLoader()保证一个装载器被初始化并激活.它具有两种可能的结果:
-
如果ID所指的装载器已经存在,那么这个装载器将被重用.
-
如果装载器不存在,initLoader()就触发LoaderManager.LoaderCallbacks的方法onCreateLoader().这是你实例化并返回一个新装载器的地方.
在这两种情况中,传入的LoaderManager.LoaderCallbacks的实现都与装载器绑定在一起.并且会在装载器状态变化时被调用.如果在调用这个方法时,调用者正处于启动状态,并且所请求的装载器已存在并产生了数据,那么系统会马上调用onLoadFinished()(也就是说在initLoader()还在执行时).所以你必须为这种情况的发生做好准备.
注意initLoader()返回所创建的装载器,但是你不需保存一个对它的引用.LoaderManager自动管理装载器的生命.LoaderManager会在需要时开始和停止装载动作,并且维护装载器的状态和它所关联的内容.这意味着,你很少与装载器直接交互.你通常都是使用LoaderManager.LoaderCallbacks的方法们在某个事件发生时介入到数据加载的过程中.
重启装载器
当你使用initLoader()
时,如果指定ID的装载器已经存在,则它使用这个装载器.如果不存在呢,它将创建一个新的.但是有时你却是想丢弃旧的然后开始新的数据.
要想丢弃旧数据,你应使用restartLoader()
.例如,下面这个
SearchView.OnQueryTextListener
的实现在用户查询发生改变时重启了装载器,装载器于是需重启从而能使用新的搜索过虑来进行一次新的查询.
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><strong>[java]</strong> <a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7252037#" class="ViewSource" title="view plain">view plain</a><a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7252037#" class="CopyToClipboard" title="copy">copy</a></div></div><ol class="dp-j" start="1"><li class="alt"><span><span><span style=</span><span class="string">"font-family:KaiTi_GB2312;"</span><span>></span><span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> onQueryTextChanged(String newText) { </span></span></li><li><span> <span class="comment">// 当动作栏的搜索字串发生改时被调用.</span><span> </span></span></li><li class="alt"><span> <span class="comment">// 更新搜索过虑,然后重新启动装载利用这个新过虑进行新的查询.</span><span> </span></span></li><li><span> mCurFilter = !TextUtils.isEmpty(newText) ? newText : <span class="keyword">null</span><span>; </span></span></li><li class="alt"><span> getLoaderManager().restartLoader(<span class="number">0</span><span>, </span><span class="keyword">null</span><span>, </span><span class="keyword">this</span><span>); </span></span></li><li><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class="alt"><span>}</span> </span></li></ol></div><h2 style="color:rgb(0,0,136)"><a target=_blank name="t1"></a><span style="color:#3a3a3a;"><span style="font-family:KaiTi_GB2312;"><span lang="zh-CN">使用</span>LoaderManager的<span lang="zh-CN">回调</span></span></span></h2><p style="color:rgb(0,0,136); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">LoaderManager.LoaderCallbacks</span></span></a></code><span style="color:#333333;"><span lang="zh-CN">是一个回调接口,它使得客户端可以与</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">LoaderManager</span></span></a></code><span style="color:#333333;"><span lang="zh-CN">进行交互.</span></span></span></p><p style="color:rgb(0,0,136); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><span style="color:#333333;"><span lang="zh-CN">装载器,一般指的是</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/content/CursorLoader.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">CursorLoader</span></span></a></code><span style="color:#333333;"><span lang="zh-CN">,我们希望在它停止后依然保持数据.这使得应用可以在</span><span style="font-size:13px; font-size:9pt">activity</span></span><span style="color:#333333;"><span lang="zh-CN">或</span><span style="font-size:13px; font-size:9pt">fragment</span></span><span style="color:#333333;"><span lang="zh-CN">的 </span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/Activity.html#onStop%28%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">onStop()</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">和</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/Activity.html#onStart%28%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">onStart()</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">之间保持数据,所以当用户回到一个应用时,它们不需等待数据加载.你使用</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">LoaderManager.LoaderCallbacks</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;">的</span><span style="color:#333333;"><span lang="zh-CN">方法们,在需要时创建新的装载器,并且告诉应用什么时候要停止使用装载器的数据.</span></span></span></p><p style="color:rgb(0,0,136); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">LoaderManager.LoaderCallbacks</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">包含以下方法们:</span></span></span></p><ul style="color:rgb(0,0,136)"><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onCreateLoader%28int,%20android.os.Bundle%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">onCreateLoader()</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">跟据传入的</span><span style="font-size:13px; font-size:9pt">ID</span></span><span style="color:#333333;"><span lang="zh-CN">,初始化并返回一个新的装载器.</span></span></span></p></li><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoadFinished%28android.content.Loader%3CD%3E,%20D%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">onLoadFinished()</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">当一个装载器完成了它的装载过程后被调用.</span></span></span></p></li><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoaderReset%28android.content.Loader%3CD%3E%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">onLoaderReset()</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">当一个装载器被重置而什其数据无效时被调用.</span></span></span></p></li></ul><h4 class="cjk" style="color:rgb(0,0,136); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><a target=_blank name="t2"></a><span style="font-family:KaiTi_GB2312;"><a target=_blank name="onCreateLoader"></a><span style="color:#3a3a3a;">onCreateLoader</span></span></h4><p style="color:rgb(0,0,136); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><span style="color:#333333;"><span lang="zh-CN">当你试图去操作一个装载器时</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">(</span></span><span style="color:#333333;"><span lang="zh-CN">比如,通过</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.html#initLoader%28int,%20android.os.Bundle,%20android.app.LoaderManager.LoaderCallbacks%3CD%3E%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">initLoader()</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">)</span></span><span style="color:#333333;"><span lang="zh-CN">,会检查是否指定</span><span style="font-size:13px; font-size:9pt">ID</span></span><span style="color:#333333;"><span lang="zh-CN">的装载器已经存在.如果它不存在,将会触发</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">LoaderManager.LoaderCallbacks</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">的方法</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onCreateLoader%28int,%20android.os.Bundle%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">onCreateLoader()</span></span></a></code><span style="color:#333333;"><span lang="zh-CN">.这是你创建一个新装载器的地方.通常这个装载器是一个</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/content/CursorLoader.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">CursorLoader</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"></span></span><span style="color:#333333;"><span lang="zh-CN">,但是你也可以实现你自己的装载器.</span></span></span></p><p style="color:rgb(0,0,136); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"><span style="color:#333333;"><span lang="zh-CN">在下面的例子中,回调方法</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onCreateLoader%28int,%20android.os.Bundle%29"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">onCreateLoader()</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">创建一个</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/content/CursorLoader.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">CursorLoader</span></span></a></code><span style="color:#333333;"><span lang="zh-CN">.你必须使用构造方法来建立</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/content/CursorLoader.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">CursorLoader</span></span></a></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">,构造方法需要向</span></span><code class="western"><a target=_blank href="http://developer.android.com/reference/android/content/ContentProvider.html"><span style="color:#006699;"><span style="font-size:13px; font-size:9pt">ContentProvider</span></span></a></code><span style="color:#333333;"><span lang="zh-CN">执行一次查询的完整信息作为参数,它尤其需要:</span></span></span></p><ul style="color:rgb(0,0,136)"><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312"><span style="font-style:italic"><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"><span style="font-style:normal">uri</span></span></span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">要获取的内容的</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">URI</span></span><span style="color:#333333;"><span lang="zh-CN">.</span></span></span></p></li><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312"><span style="font-style:italic"><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"><span style="font-style:normal">projection</span></span></span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">要返回的列组成的列被.传入</span></span><code class="western"><span style="color:#007000;"><span style="font-size:13px; font-size:9pt">null</span></span></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">将会返回所有的列,但这是低效的.</span></span></span></p></li><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312"><a target=_blank name="__DdeLink__11630_1772819336"></a><span style="font-style:italic"><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"><span style="font-style:normal">selection</span></span></span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">一个过滤器,表明哪些行将被返回.格式化成类似</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">SQLWHERE </span></span><span style="color:#333333;"><span lang="zh-CN">语句的样子</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">(</span></span><span style="color:#333333;"><span lang="zh-CN">除了没有</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">WHERE)</span></span><span style="color:#333333;"><span lang="zh-CN">.传入</span></span><code class="western"><span style="color:#007000;"><span style="font-size:13px; font-size:9pt">null</span></span></code><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">将返回所有的行.</span></span></span></p></li><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312"><span style="font-style:italic"><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"><span style="font-style:normal">selectionArgs</span></span></span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">你可以在</span></span><span style="font-style:italic"><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"><span style="font-style:normal">selection</span></span></span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> </span></span><span style="color:#333333;"><span lang="zh-CN">中包含一些</span><span style="font-size:13px; font-size:9pt">'</span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">?'</span></span></span><span style="color:#333333;"><span lang="zh-CN">,它将被本参数的值替换掉.这些值出现的顺序与</span><span style="font-size:13px; font-size:9pt">'?'</span></span><span style="color:#333333;"><span lang="zh-CN">在</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">selection</span></span><span style="color:#333333;"><span lang="zh-CN">中出现的顺序一至.值将作为字符串.</span></span></span></p></li><li><p style="border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312"><span style="font-style:italic"><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"><span style="font-style:normal">sortOrder</span></span></span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt"> —</span></span><span style="color:#333333;"><span lang="zh-CN">如何为行们排序.格式化成类似于</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">SQLORDER BY </span></span><span style="color:#333333;"><span lang="zh-CN">语句的样字</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">(</span></span><span style="color:#333333;"><span lang="zh-CN">除了没有</span></span><span style="color:#333333;"><span style="font-size:13px; font-size:9pt">ORDERBY)</span></span><span style="color:#333333;"><span lang="zh-CN">.传入</span></span><code class="western"><span style="color:#007000;"><span style="font-size:13px; font-size:9pt">null</span></span></code><span style="color:#333333;"><span lang="zh-CN">将使用默认顺序,默认顺序可能是无顺序.</span></span></span></p></li></ul><p style="color:rgb(0,0,136); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm" lang="zh-CN"><span style="color:#333333;"><span style="font-family:KaiTi_GB2312;">例子:</span></span></p><pre name="code" class="cjk" style="margin-bottom:0.21cm; background-color:rgb(255,255,255); border-top-style:none; border-right-style:none; border-bottom-style:none; border-left-style:none; border-width:initial; border-color:initial; padding-top:0cm; padding-right:0cm; padding-bottom:0cm; padding-left:0cm"><span style="font-family:KaiTi_GB2312;"></span><div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><strong>[java]</strong> <a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7252037#" class="ViewSource" title="view plain">view plain</a><a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7252037#" class="CopyToClipboard" title="copy">copy</a></div></div><ol class="dp-j" start="1"><li class="alt"><span><span> </span><span class="comment">// If non-null, this is the current filter the user has provided.</span><span> </span></span></li><li><span>String mCurFilter; </span></li><li class="alt"><span>... </span></li><li><span><span class="keyword">public</span><span> Loader<Cursor> onCreateLoader(</span><span class="keyword">int</span><span> id, Bundle args) { </span></span></li><li class="alt"><span> <span class="comment">// 这里是在需要创建新装载器时被调用的.</span><span> </span></span></li><li><span> <span class="comment">// 我们只是简单的拥有一个装载器,所以我们不需要关心ID.</span><span> </span></span></li><li class="alt"><span> <span class="comment">// First, pick the base URI to use depending on whether we are</span><span> </span></span></li><li><span> <span class="comment">// currently filtering.</span><span> </span></span></li><li class="alt"><span> Uri baseUri; </span></li><li><span> <span class="keyword">if</span><span> (mCurFilter != </span><span class="keyword">null</span><span>) { </span></span></li><li class="alt"><span> baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, </span></li><li><span> Uri.encode(mCurFilter)); </span></li><li class="alt"><span> } <span class="keyword">else</span><span> { </span></span></li><li><span> baseUri = Contacts.CONTENT_URI; </span></li><li class="alt"><span> } </span></li><li><span> <span class="comment">// Now create and return a CursorLoader that will take care of</span><span> </span></span></li><li class="alt"><span> <span class="comment">// creating a Cursor for the data being displayed.</span><span> </span></span></li><li><span> String select = <span class="string">"(("</span><span> + Contacts.DISPLAY_NAME + </span><span class="string">" NOTNULL) AND ("</span><span> </span></span></li><li class="alt"><span> + Contacts.HAS_PHONE_NUMBER + <span class="string">"=1) AND ("</span><span> </span></span></li><li><span> + Contacts.DISPLAY_NAME + <span class="string">" != '' ))"</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">new</span><span> CursorLoader(getActivity(), baseUri, </span></span></li><li><span> CONTACTS_SUMMARY_PROJECTION, select, <span class="keyword">null</span><span>, </span></span></li><li class="alt"><span> Contacts.DISPLAY_NAME + <span class="string">" COLLATE LOCALIZED ASC"</span><span>); </span></span></li><li><span>} </span></li></ol></div><h2><span style="font-family:Times New Roman,serif;"><strong>onLoadFinished</strong></span></h2><p><span lang="zh-CN">这个方法是在前面已创建的装载器已经完成其加载过程后被调用.这个方法保证会在应用到装载器上的数据被释放之前被调用.在此方法中,你必须删除所有对旧数据的使用</span><span style="font-family:Times New Roman,serif;">(</span><span lang="zh-CN">因为它将很快会被删除</span><span style="font-family:Times New Roman,serif;">),</span><span lang="zh-CN">但是不要自己去释放它们,因为它们的装载器会做这些事情.</span></p><p><span lang="zh-CN">装载器一旦了解到应用不再使用数据时,将马上释放这些数据.例如,如果数据是一个从</span><span style="font-family:Times New Roman,serif;">CursorLoader</span><span lang="zh-CN">来的游标,你不应调用游标的</span><span style="font-family:Times New Roman,serif;">close()</span><span lang="zh-CN">.如果游标被放置在一个</span><span style="font-family:Times New Roman,serif;">CursorAdapter</span><span lang="zh-CN">中,你应使用</span><span style="font-family:Times New Roman,serif;">swapCursor()</span><span lang="zh-CN">方法,以使旧的游标不被关闭.例如:</span></p><div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><strong>[java]</strong> <a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7256605#" class="ViewSource" title="view plain">view plain</a><a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7256605#" class="CopyToClipboard" title="copy">copy</a></div></div><ol class="dp-j" start="1"><li class="alt"><span><span class="comment">//这个Adapter被用于显示列表的数据.</span><span> </span></span></li><li><span>SimpleCursorAdapter mAdapter; </span></li><li class="alt"><span>... </span></li><li><span> </span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onLoadFinished(Loader<Cursor> loader, Cursor data) { </span></span></li><li><span> <span class="comment">// Swap the new cursor in. (The framework will take care of closing the</span><span> </span></span></li><li class="alt"><span> <span class="comment">// old cursor once we return.)</span><span> </span></span></li><li><span> mAdapter.swapCursor(data); </span></li><li class="alt"><span>} </span></li></ol></div> <h2><a target=_blank name="t1"></a><span style="font-family:Times New Roman,serif;"><strong>onLoaderReset</strong></span> </h2><p lang="zh-CN">当一个已创建的装载器被重置从而使其数据无效时,此方法被调用.此回调使你能发现什么时候数据将被釋放于是你可以釋放对它的引用.</p><p><span lang="zh-CN">下面这个实现调用参数为</span><span style="font-family:Times New Roman,serif;">null</span><span lang="zh-CN">的</span><span style="font-family:Times New Roman,serif;">swapCursor()</span><span lang="zh-CN">:</span></p><div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><strong>[java]</strong> <a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7256605#" class="ViewSource" title="view plain">view plain</a><a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7256605#" class="CopyToClipboard" title="copy">copy</a></div></div><ol class="dp-j" start="1"><li class="alt"><span><span class="comment">// 这个Adapter被用于显示列表的数据.</span><span> </span></span></li><li><span>SimpleCursorAdapter mAdapter; </span></li><li class="alt"><span>... </span></li><li><span> </span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onLoaderReset(Loader<Cursor> loader) { </span></span></li><li><span> <span class="comment">//此处是用于上面的onLoadFinished()的游标将被关闭时执行, 我们需确保我们不再使用它.</span><span> </span></span></li><li class="alt"><span> mAdapter.swapCursor(<span class="keyword">null</span><span>); </span></span></li><li><span>} </span></li></ol></div> <h2><a target=_blank name="t2"></a><strong>例子</strong> </h2><p><span lang="zh-CN">作为一个例子,这里完整实现了一个</span><span style="font-family:Times New Roman,serif;">Fragment</span><span lang="zh-CN">显示一个包含从联系人</span><span style="font-family:Times New Roman,serif;">contentprovider</span><span lang="zh-CN">返回查询数据的</span><span style="font-family:Times New Roman,serif;">ListView</span><span lang="zh-CN">的内容的功能.它使用一个</span><span style="font-family:Times New Roman,serif;">CursorLoader</span><span lang="zh-CN">来管理对</span><span style="font-family:Times New Roman,serif;">provider</span><span lang="zh-CN">的查询.</span></p><p> <span lang="zh-CN">为了能从用户的联系人中取得数据,本例的</span><span style="font-family:Times New Roman,serif;">manifest</span><span lang="zh-CN">必须包含</span><span style="font-family:Times New Roman,serif;">READ_CONTACTS</span><span lang="zh-CN">权限.</span></p><p><span style="font-family:Times New Roman,serif;"></span></p><div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><strong>[java]</strong> <a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7256605#" class="ViewSource" title="view plain">view plain</a><a target=_blank href="http://blog.csdn.net/niu_gao/article/details/7256605#" class="CopyToClipboard" title="copy">copy</a></div></div><ol class="dp-j" start="1"><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">class</span><span> CursorLoaderListFragment </span><span class="keyword">extends</span><span> ListFragment </span></span></li><li><span> <span class="keyword">implements</span><span> OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 这是用于显示列表数据的Adapter</span><span> </span></span></li><li class="alt"><span> SimpleCursorAdapter mAdapter; </span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 如果非null,这是当前的搜索过虑器</span><span> </span></span></li><li><span> String mCurFilter; </span></li><li class="alt"><span> </span></li><li><span> <span class="annotation">@Override</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onActivityCreated(Bundle savedInstanceState) { </span></span></li><li class="alt"><span> <span class="keyword">super</span><span>.onActivityCreated(savedInstanceState); </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 如果列表中没有数据,就给控件一些文字去显示.在一个真正的应用</span><span> </span></span></li><li><span> <span class="comment">// 中这应用资源中取得.</span><span> </span></span></li><li class="alt"><span> setEmptyText(<span class="string">"No phone numbers"</span><span>); </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 我们在动作栏中有一个菜单项.</span><span> </span></span></li><li><span> setHasOptionsMenu(<span class="keyword">true</span><span>); </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 创建一个空的adapter,我们将用它显示加载后的数据</span><span> </span></span></li><li class="alt"><span> mAdapter = <span class="keyword">new</span><span> SimpleCursorAdapter(getActivity(), </span></span></li><li><span> android.R.layout.simple_list_item_2, <span class="keyword">null</span><span>, </span></span></li><li class="alt"><span> <span class="keyword">new</span><span> String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, </span></span></li><li><span> <span class="keyword">new</span><span> </span><span class="keyword">int</span><span>[] { android.R.id.text1, android.R.id.text2 }, </span><span class="number">0</span><span>); </span></span></li><li class="alt"><span> setListAdapter(mAdapter); </span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 准备loader.可能是重连到一个已存在的或开始一个新的</span><span> </span></span></li><li><span> getLoaderManager().initLoader(<span class="number">0</span><span>, </span><span class="keyword">null</span><span>, </span><span class="keyword">this</span><span>); </span></span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="annotation">@Override</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onCreateOptionsMenu(Menu menu, MenuInflater inflater) { </span></span></li><li><span> <span class="comment">// 放置一个动作栏项用于搜索.</span><span> </span></span></li><li class="alt"><span> MenuItem item = menu.add(<span class="string">"Search"</span><span>); </span></span></li><li><span> item.setIcon(android.R.drawable.ic_menu_search); </span></li><li class="alt"><span> item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); </span></li><li><span> SearchView sv = <span class="keyword">new</span><span> SearchView(getActivity()); </span></span></li><li class="alt"><span> sv.setOnQueryTextListener(<span class="keyword">this</span><span>); </span></span></li><li><span> item.setActionView(sv); </span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> onQueryTextChange(String newText) { </span></span></li><li><span> <span class="comment">// 在动作栏上的搜索字串改变时被调用.更新</span><span> </span></span></li><li class="alt"><span> <span class="comment">//搜索过滤器,并重启loader来执行一个新的查询</span><span> </span></span></li><li><span> mCurFilter = !TextUtils.isEmpty(newText) ? newText : <span class="keyword">null</span><span>; </span></span></li><li class="alt"><span> getLoaderManager().restartLoader(<span class="number">0</span><span>, </span><span class="keyword">null</span><span>, </span><span class="keyword">this</span><span>); </span></span></li><li><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="annotation">@Override</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> onQueryTextSubmit(String query) { </span></span></li><li><span> <span class="comment">// 我们不关心这个方法</span><span> </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li><span> } </span></li><li class="alt"><span> </span></li><li><span> <span class="annotation">@Override</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onListItemClick(ListView l, View v, </span><span class="keyword">int</span><span> position, </span><span class="keyword">long</span><span> id) { </span></span></li><li class="alt"><span> <span class="comment">// 写入你想写的代码</span><span> </span></span></li><li><span> Log.i(<span class="string">"FragmentComplexList"</span><span>, </span><span class="string">"Item clicked: "</span><span> + id); </span></span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 这是我们想获取的联系人中一行的数据.</span><span> </span></span></li><li><span> <span class="keyword">static</span><span> </span><span class="keyword">final</span><span> String[] CONTACTS_SUMMARY_PROJECTION = </span><span class="keyword">new</span><span> String[] { </span></span></li><li class="alt"><span> Contacts._ID, </span></li><li><span> Contacts.DISPLAY_NAME, </span></li><li class="alt"><span> Contacts.CONTACT_STATUS, </span></li><li><span> Contacts.CONTACT_PRESENCE, </span></li><li class="alt"><span> Contacts.PHOTO_ID, </span></li><li><span> Contacts.LOOKUP_KEY, </span></li><li class="alt"><span> }; </span></li><li><span> <span class="keyword">public</span><span> Loader<Cursor> onCreateLoader(</span><span class="keyword">int</span><span> id, Bundle args) { </span></span></li><li class="alt"><span> <span class="comment">// 当一个新的loader需被创建时调用.本例仅有一个Loader,</span><span> </span></span></li><li><span> <span class="comment">//所以我们不需关心ID.首先设置base URI,URI指向的是联系人</span><span> </span></span></li><li class="alt"><span> Uri baseUri; </span></li><li><span> <span class="keyword">if</span><span> (mCurFilter != </span><span class="keyword">null</span><span>) { </span></span></li><li class="alt"><span> baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, </span></li><li><span> Uri.encode(mCurFilter)); </span></li><li class="alt"><span> } <span class="keyword">else</span><span> { </span></span></li><li><span> baseUri = Contacts.CONTENT_URI; </span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 现在创建并返回一个CursorLoader,它将负责创建一个</span><span> </span></span></li><li><span> <span class="comment">// Cursor用于显示数据</span><span> </span></span></li><li class="alt"><span> String select = <span class="string">"(("</span><span> + Contacts.DISPLAY_NAME + </span><span class="string">" NOTNULL) AND ("</span><span> </span></span></li><li><span> + Contacts.HAS_PHONE_NUMBER + <span class="string">"=1) AND ("</span><span> </span></span></li><li class="alt"><span> + Contacts.DISPLAY_NAME + <span class="string">" != '' ))"</span><span>; </span></span></li><li><span> <span class="keyword">return</span><span> </span><span class="keyword">new</span><span> CursorLoader(getActivity(), baseUri, </span></span></li><li class="alt"><span> CONTACTS_SUMMARY_PROJECTION, select, <span class="keyword">null</span><span>, </span></span></li><li><span> Contacts.DISPLAY_NAME + <span class="string">" COLLATE LOCALIZED ASC"</span><span>); </span></span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onLoadFinished(Loader<Cursor> loader, Cursor data) { </span></span></li><li><span> <span class="comment">// 将新的cursor换进来.(框架将在我们返回时关心一下旧cursor的关闭)</span><span> </span></span></li><li class="alt"><span> mAdapter.swapCursor(data); </span></li><li><span> } </span></li><li class="alt"><span> </span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onLoaderReset(Loader<Cursor> loader) { </span></span></li><li class="alt"><span> <span class="comment">//在最后一个Cursor准备进入上面的onLoadFinished()之前.</span><span> </span></span></li><li><span> <span class="comment">// Cursor要被关闭了,我们需要确保不再使用它.</span><span> </span></span></li><li class="alt"><span> mAdapter.swapCursor(<span class="keyword">null</span><span>); </span></span></li><li><span> } </span></li><li class="alt"><span>} </span></li></ol></div> <span style="font-family:Times New Roman,serif;"> </span>