LoaderManager使用详解(二)---了解LoaderManager

了解LoaderManager

这篇文章将介绍LoaderManager类,这是该系列的第二篇文章。

一:Loaders之前世界

二:了解LoaderManager

三:实现Loaders

四:实例:AppListLoader

注意:

要了解这一LoaderManager这部分知识,要求对Loaders如何工作有基本了解。Loaders的实现将在下一篇文章中涵盖。现在你只需要将Loaders看成一个简单、字包含的对象。该对象特性包括:1.在一个单独线程载入数据;2.监测底层数据源,当探测到有改变时就更新或者重新查询。了解上面的Loader相关内容就足以了解本文内容了。下文所有的Loaders假设100%正确。

LoaderManager是什么?

  简单的理解是,LoaderManager用来负责管理与Activity或者Fragment联系起来的一个或多个Loaders对象。每个Activity或者Fragment都有唯一的一个LoaderManager实例,用来启动、停止、保持、重启、关闭它的Loaders。这些事件有时直接在客户端通过调用initLoader()/restartLoader()/destroyLoader()函数来实现。通常这些事件通过主要的Activity/Fragment声明周期事件来触发,而不是手动(当然也可以手动调用)。比如,当一个Activity关闭时(destroyed),改活动将指示它的LoaderManager来销毁并且关闭它的Loaders(当然也会销毁并关闭与这些Loaders关联的资源,比如Cursor)。

  LoaderManager并不知道数据如何装载以及何时需要装载。相反地,LoaderManager只需要控制它的Loaders们开始、停止、重置他们的Load行为,在配置变换(比如横竖屏切换)时保持loaders们的状态,并提供一个简单的接口来获取load结果到客户端中。从上面的行为可以看到,LoaderManager是一个比现在过时的startManagingCursor方法更加智能和通用的方法。在Activity的声明周期状态轮转中,比较两种管理数据的方法,可以发现LoaderManager方法有下面几个方面更胜一筹:

1. startManagingCursor管理Cursors,而LoaderManager管理Loader<D>对象。Loader<D>是一个模板类,D是一个包含了需要载入数据的类。也就是说,数据源并不必须是Cursor,它可以是List、JSONArray。。。任何类。LoaderManager与它包含的数据内容解耦了,所以更加灵活。

2. 调用startManagingCursor会导致Activity在已经加入管理的Cursor上调用requery()方法。在第一篇文章中提到过,在UI线程执行requery()方法代价非常高。相反的是,Loader<D>的子类会异步载入(译者注:另外再开一个线程,就叫异步了。)数据,所以使用LoaderManager永远不会产生阻塞UI线程的情况。

3. startManagingCursor在配置变化(例如横竖屏切换)时,并不会保持Cursor的状态。麻烦的是,每次Activity由于配置变化(比如,简单的横竖屏切换),都会导致Cursor下回并且被重新查询。LoaderManager就智能多了,当配置变化时,它会保持它里面的Loader们的状态,所以并不需要重新查询数据。

4. LoaderManager提供无缝的数据监测。任何时候,当Loader的数据源改变,LoaderManager将会从对应的Loader上面接收到一个新的同步载入数据,并将更新数据返回给客户端(注意:仅当Loader被正确实现,LoaderManager才会接收到这些数据变化通知。我们将会在该系列的第三篇文章讨论自定义Loaders的实现)。

如果你觉得上面很难,我也并不会强调她。上面的内容最重要的是LoaderManager让你的生活更容易。LoaderManager为你初始化、管理、销毁Loaders,减少了代码复杂度和与Activity或者Fragment生命周期相关的bug。更多地,与LoaderManager交互需要实现三个简单的回调方法,我们在下一节将讨论LoaderManager.LoaderCallbacks<D>。

实现LoaderManager.LoaderCallbacks<D>接口

LoaderManager.LoaderCallbacks<D>接口LoaderManager用来向客户返回数据的方式。每个Loader都有自己的回调对象供与LoaderManager进行交互。该回调对象在实现LoaderManager中地位很高,告诉LoaderManager如何实例化Loader(onCreateLoader),以及当载入行为结束或者重启(onLoadFinished或者onLoadReset)之后执行什么操作。大多数情况,你需要把该接口实现为组件的一部分,比如说让你的Activity或者Fragment实现LoadManager.LoaderCallbacks<D>接口。

public class SampleActivity extends Activity implements LoaderManager.LoaderCallbacks<D> {

  public Loader<D> onCreateLoader(int id, Bundle args) { ... }

  public void onLoadFinished(Loader<D> loader, D data) { ... }

  public void onLoaderReset(Loader<D> loader) { ... }

  /* ... */
}

一旦实现该接口,客户端将回调对象(本例中为“this”)作为LoaderManager的initLoader函数的第三个参数传输。

总的来说,实现回调接口非常直接明了。每个回调方法都有各自明确的与LoaderManager进行交互的目的:

1. onCreateLoader是一个工厂方法,用来返回一个新的Loader。LoaderManager将会在它第一次创建Loader的时候调用该方法。

2. onLoadFinished方法将在Loader创建完毕的时候自动调用。典型用法是,当载入数据完毕,客户端(译者注:调用它的Activity之类的)需要更新应用UI。客户端假设每次有新数据的时候,新数据都会返回到这个方法中。记住,检测数据源是Loader的工作,Loader也会执行实际的同步载入操作。一旦Loader载入数据完成,LoaderManager将会接受到这些载入数据,并且将将结果传给回调对象的onLoadFinished方法,这样客户端(比如Activity或者Fragment)就能使用该数据了。

3. 最后,当Loader们的数据被重置的时候将会调用onLoadReset。该方法让你可以从就的数据中移除不再有用的数据。

在下一节中,我们将讨论Android初学者们经常问到的问题:如何从过时的Managed Cursor转移到更强大的LoaderManager来?

从Managed Cursor转移到LoaderManager

下面的代码跟上一篇文章的代码实现的功能类似。当然,不同就是改成使用LoaderManager来实现。CursorLoader确保所有的查询都是异步执行,这确保了我们不会阻塞UI线程。更进一步,LoaderManager在Activity全生命周期管理CursorLoader,当配置转换时保持它的数据。处理每次新数据在回调接口的onLoadFinished方法中的载入。这样Activity可以很自由的使用查询结果。

public class SampleListActivity extends ListActivity implements
    LoaderManager.LoaderCallbacks<Cursor> {

  private static final String[] PROJECTION = new String[] { "_id", "text_column" };

  // The loader‘s unique id. Loader ids are specific to the Activity or
  // Fragment in which they reside.
  private static final int LOADER_ID = 1;

  // The callbacks through which we will interact with the LoaderManager.
  private LoaderManager.LoaderCallbacks<Cursor> mCallbacks;

  // The adapter that binds our data to the ListView
  private SimpleCursorAdapter mAdapter;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String[] dataColumns = { "text_column" };
    int[] viewIDs = { R.id.text_view };

    // Initialize the adapter. Note that we pass a ‘null‘ Cursor as the
    // third argument. We will pass the adapter a Cursor only when the
    // data has finished loading for the first time (i.e. when the
    // LoaderManager delivers the data to onLoadFinished). Also note
    // that we have passed the ‘0‘ flag as the last argument. This
    // prevents the adapter from registering a ContentObserver for the
    // Cursor (the CursorLoader will do this for us!).
    mAdapter = new SimpleCursorAdapter(this, R.layout.list_item,
        null, dataColumns, viewIDs, 0);

    // Associate the (now empty) adapter with the ListView.
    setListAdapter(mAdapter);

    // The Activity (which implements the LoaderCallbacks<Cursor>
    // interface) is the callbacks object through which we will interact
    // with the LoaderManager. The LoaderManager uses this object to
    // instantiate the Loader and to notify the client when data is made
    // available/unavailable.
    mCallbacks = this;

    // Initialize the Loader with id ‘1‘ and callbacks ‘mCallbacks‘.
    // If the loader doesn‘t already exist, one is created. Otherwise,
    // the already created Loader is reused. In either case, the
    // LoaderManager will manage the Loader across the Activity/Fragment
    // lifecycle, will receive any new loads once they have completed,
    // and will report this new data back to the ‘mCallbacks‘ object.
    LoaderManager lm = getLoaderManager();
    lm.initLoader(LOADER_ID, null, mCallbacks);
  }

  @Override
  public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // Create a new CursorLoader with the following query parameters.
    return new CursorLoader(SampleListActivity.this, CONTENT_URI,
        PROJECTION, null, null, null);
  }

  @Override
  public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    // A switch-case is useful when dealing with multiple Loaders/IDs
    switch (loader.getId()) {
      case LOADER_ID:
        // The asynchronous load is complete and the data
        // is now available for use. Only now can we associate
        // the queried Cursor with the SimpleCursorAdapter.
        mAdapter.swapCursor(cursor);
        break;
    }
    // The listview now displays the queried data.
  }

  @Override
  public void onLoaderReset(Loader<Cursor> loader) {
    // For whatever reason, the Loader‘s data is now unavailable.
    // Remove any references to the old data by replacing it with
    // a null Cursor.
    mAdapter.swapCursor(null);
  }
}

总结

正如其名LoaderManager,它负责在Activity或者Fragment的生命周期内管理Loader们。LoaderManager很简单,并且它的实现代码量通常很少。比较难的部分是实现Loaders,这个主题将在下一篇文章中讨论:实现Loaders(三)(超链接)

时间: 2024-10-17 11:44:10

LoaderManager使用详解(二)---了解LoaderManager的相关文章

LoaderManager使用详解(一)---没有Loader之前的世界

来源: http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html 感谢作者Alex Lockwood的努力,让我们看到如此精彩的文章. 第一部分 没有Loader之前的世界 这一部分将对Loaders和LoaderManager做一个简短的介绍.第一节将在Android3.0之前如何载入数据,指出其缺陷.第二节讲述每个类的目的,以及它们异步载入数据的能力. 这篇文章是有关Loade

UINavigationController详解二(转)页面切换和SegmentedController

原文出自:http://blog.csdn.net/totogo2010/article/details/7682433,非常感谢. 1.RootView 跳到SecondView 首先我们需要新一个View.新建SecondView,按住Command键然后按N,弹出新建页面,我们新建SecondView 2.为Button 添加点击事件,实现跳转 在RootViewController.xib中和RootViewController.h文件建立连接 在RootViewController.m

Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

[Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.Android 布局学习之——LinearLayout的layout_weight属性   4.Android 布局学习之——LinearLayout属性baselineAligned的作用及baseline    Layout Parameters(布局参数): 在XML文件中,我们经常看到类似与lay

CSS3中的弹性流体盒模型技术详解(二)

在上一篇文章<CSS3中的弹性流体盒模型技术详解(一)>里,我给大家列出了,从css1到css3各版本中盒子模型的基本元素.本篇我会把余下的属性进行详细讲解. box-pack 作用:用来规定子元素在盒子内的水平空间分配方式 box-pack 语法:box-pack: start | end | center | justify; start 对于正常方向的框,首个子元素的左边缘吸附在盒子的左边框显示 对于相反方向的框,最后子元素的右边缘吸附在盒子的右边框显示 end 对于正常方向的框,最后子

php学习之道:WSDL详解(二)

3.定义服务使用的逻辑消息 当服务的操作被调用时,服务被定义为消息交换.在wsdl文档中,这些消息被定义message元素.这些消息由称之为part元素的部分组成. 一个服务的操作,通过指定逻辑消息的方式来定义.当操作被调用时,逻辑消息被交换.(也就是说,逻辑消息代表了服务的操作)这些逻辑消息,将在网络上传输的数据定义为xml文档.他包含了所有的参数,这些参数是方法调用的一部分.(也就是说,逻辑消息里的参数,是操作对应方法的参数集合) 消息和参数列表:每一个被服务暴露的操作能且仅能有一个输入消息

LinearLayout详解二:从其父类View说起

这个View类说来就话长了,但我们又不得不说,要说呢,就得说的彻底,要让大家看得一清二楚,明明白白.所以我们就从源代码角度来看一个view是如何被加载的吧. 如果大家不知道怎么下载android的源代码,或者说懒得去下载(因为源代码确实比较大,大概有10G)的话,教大家几个取巧的办法: 1.直接在google中输入"android view.java"即可.这种方法成功率非常高,一般android的比较重要的类都能搜到. 2.给大家提供一个人家用于放源码的的git:[email pro

jquery validate 详解二

原文:http://blog.sina.com.cn/s/blog_608475eb0100h3h2.html 这里只是第二篇,前面的内容请参阅上一篇 五.常用方法及注意问题 1.用其他方式替代默认的SUBMIT 1 $().ready(function() { 2 $("#signupForm").validate({ 3 submitHandler:function(form){ 4 alert("submitted"); 5 form.submit(); 6

cocos2dx 启动过程详解二:内存管理和回调

在上一篇的第二部分中,我们有一句代码待解释的: // Draw the Scene void CCDirector::drawScene(void) { -- //tick before glClear: issue #533 if (! m_bPaused) //暂停 { m_pScheduler->update(m_fDeltaTime);   //待会会解释这里的内容 } -- } 这里是一个update函数,经常会写像this->schedule(schedule_selector(X

PopUpWindow使用详解(二)——进阶及答疑

相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow的基本使用,但还有几个相关函数还没有讲述,我们这篇将着重看看这几个函数的用法并结合源码来讲讲具体原因,最后是有关PopupWindow在使用时的疑问,给大家讲解一下. 一.常用函数讲解 这段将会给大家讲下下面几个函数的意义及用法,使用上篇那个带背景的例子为基础. [java] view plain copy pu

HTTPS详解二:SSL / TLS 工作原理和详细握手过程

HTTPS 详解一:附带最精美详尽的 HTTPS 原理图 HTTPS详解二:SSL / TLS 工作原理和详细握手过程 在上篇文章HTTPS详解一中,我已经为大家介绍了 HTTPS 的详细原理和通信流程,但总感觉少了点什么,应该是少了对安全层的针对性介绍,那么这篇文章就算是对HTTPS 详解一的补充吧.还记得这张图吧. HTTPS 和 HTTP的区别 显然,HTTPS 相比 HTTP最大的不同就是多了一层 SSL (Secure Sockets Layer 安全套接层)或 TLS (Transp