`

android Loader

 
阅读更多

转自: http://blog.csdn.net/nkmnkm/article/details/7256605     

装载器从android3.0开始引进。它使得在activityfragment中异步加载数据变得简单。装载器具有如下特性:

 

  • 它们对每个ActivityFragment都有效。

  • 他们提供了异步加载数据的能力。

  • 它们监视数据源的一将一动并在内容改变时传送新的结果。

  • 当由于配置改变而被重新创建后,它们自动重连到上一个加载器的游标,所以不必重新查询数据。

 

装载器API概述

 


在使用装载器时,会涉及很多类和接口们,我们在下表中对它们总结一下:

 

Class/Interface

说明

LoaderManager

一个抽像类,关联到一个ActivityFragment,管理一个或多个装载器的实例。这帮助一个应用管理那些与ActivityFragment的生命周期相关的长时间运行的的操作。最常见的方式是与一个CursorLoader一起使用,然而应用是可以随便写它们自己的装载器以加载其它类型的数据。

每个activityfragment只有一个LoaderManager。但是一个LoaderManager可以拥有多个装载器。

LoaderManager.LoaderCallbacks

一个用于客户端与LoaderManager交互的回调接口。例如,你使用回调方法onCreateLoader()来创建一个新的装载器。

Loader(装载器)

一个执行异步数据加载的抽象类。它是加载器的基类。你可以使用典型的CursorLoader,但是你也可以实现你自己的子类。一旦装载器被激活,它们将监视它们的数据源并且在数据改变时发送新的结果。

AsyncTaskLoader

提供一个AsyncTask来执行异步加载工作的抽象类。

CursorLoader

AsyncTaskLoader的子类,它查询ContentResolver然后返回一个Cursor。这个类为查询cursor以标准的方式实现了装载器的协议,它的游标查询是通过AsyncTaskLoader在后台线程中执行,从而不会阻塞界面。使用这个装载器是从一个ContentProvider异步加载数据的最好方式。相比之下,通过fragmentactivityAPI来执行一个被管理的查询就不行了。

 

 

上面所列的类和接口们是你在你的应用中要实现装载器时的核心组件。你的每个装载器并不一定需要所有的组件,但是你总是需要引用LoaderManager来初始化一个装载器。后面的章节将向你展示如何使用这些类和接口们。

 

一个使用装载器的应用会典型的包含如下组件:

  • 一个ActivityFragment

  • 一个LoaderManager的实例.

  • 一个加载被ContentProvider所支持的数据的CursorLoader.或者,你可以从LoaderAsyncTaskLoader实现你自己的装载器来从其它源加载数据.

  • 一个LoaderManager.LoaderCallbacks的实现.这是你创建新的装载器以及管理你的已有装载器的引用的地方.

  • 一个显示装载器的数据的途径,例如使用一个SimpleCursorAdapter

  • 一个数据源,比如当是用CursorLoader时,它将是一个ContentProvider

     

启动一个装载器

LoaderManager管理一个ActiviryFragment中的一个或多个装载器.但每个activityfragment只拥有一个LoaderManager

你通常要在activityonCreate()方法中或fragmentonActivityCreated()方法中初始化一个装载器.你可以如下创建:

 

[java] view plaincopy
 
  1. // 准备装载器.可以重连一个已经存在的也可以启动一个新的.  
  2. getLoaderManager().initLoader(0,nullthis);  

initLoader()方法有以下参数:

 

  • 一个唯一ID来标志装载器.在这个例子中,ID0

  • 可选的参数,用于装载器初始化时(本例中是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的实现在用户查询发生改变时重启了装载器,装载器于是需重启从而能使用新的搜索过虑来进行一次新的查询.

[java] view plaincopy
 
  1. <span style="font-family:KaiTi_GB2312;">public boolean onQueryTextChanged(String newText) {  
  2.     // 当动作栏的搜索字串发生改时被调用.  
  3.     // 更新搜索过虑,然后重新启动装载利用这个新过虑进行新的查询.  
  4.     mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;  
  5.     getLoaderManager().restartLoader(0nullthis);  
  6.     return true;  
  7. }</span>  

使用LoaderManager的回调

LoaderManager.LoaderCallbacks是一个回调接口,它使得客户端可以与LoaderManager进行交互.

装载器,一般指的是CursorLoader,我们希望在它停止后依然保持数据.这使得应用可以在activityfragment的 onStop() onStart() 之间保持数据,所以当用户回到一个应用时,它们不需等待数据加载.你使用LoaderManager.LoaderCallbacks 方法们,在需要时创建新的装载器,并且告诉应用什么时候要停止使用装载器的数据.

LoaderManager.LoaderCallbacks 包含以下方法们:

  • onCreateLoader() —跟据传入的ID,初始化并返回一个新的装载器.

  • onLoadFinished() —当一个装载器完成了它的装载过程后被调用.

  • onLoaderReset() —当一个装载器被重置而什其数据无效时被调用.

onCreateLoader

当你试图去操作一个装载器时(比如,通过initLoader()),会检查是否指定ID的装载器已经存在.如果它不存在,将会触发LoaderManager.LoaderCallbacks 的方法onCreateLoader().这是你创建一个新装载器的地方.通常这个装载器是一个CursorLoader,但是你也可以实现你自己的装载器.

在下面的例子中,回调方法onCreateLoader() 创建一个CursorLoader.你必须使用构造方法来建立CursorLoader ,构造方法需要向ContentProvider执行一次查询的完整信息作为参数,它尤其需要:

  • uri —要获取的内容的URI

  • projection —要返回的列组成的列被.传入null 将会返回所有的列,但这是低效的.

  • selection —一个过滤器,表明哪些行将被返回.格式化成类似SQLWHERE 语句的样子(除了没有WHERE).传入null 将返回所有的行.

  • selectionArgs —你可以在selection 中包含一些'?',它将被本参数的值替换掉.这些值出现的顺序与'?'selection中出现的顺序一至.值将作为字符串.

  • sortOrder —如何为行们排序.格式化成类似于SQLORDER BY 语句的样字(除了没有ORDERBY).传入null将使用默认顺序,默认顺序可能是无顺序.

例子:

[java] view plaincopy
 
  1.  // If non-null, this is the current filter the user has provided.  
  2. String mCurFilter;  
  3. ...  
  4. public Loader<Cursor> onCreateLoader(int id, Bundle args) {  
  5.     // 这里是在需要创建新装载器时被调用的.  
  6.     // 我们只是简单的拥有一个装载器,所以我们不需要关心ID.  
  7.     // First, pick the base URI to use depending on whether we are  
  8.     // currently filtering.  
  9.     Uri baseUri;  
  10.     if (mCurFilter != null) {  
  11.         baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,  
  12.                   Uri.encode(mCurFilter));  
  13.     } else {  
  14.         baseUri = Contacts.CONTENT_URI;  
  15.     }  
  16.     // Now create and return a CursorLoader that will take care of  
  17.     // creating a Cursor for the data being displayed.  
  18.     String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("  
  19.             + Contacts.HAS_PHONE_NUMBER + "=1) AND ("  
  20.             + Contacts.DISPLAY_NAME + " != '' ))";  
  21.     return new CursorLoader(getActivity(), baseUri,  
  22.             CONTACTS_SUMMARY_PROJECTION, select, null,  
  23.             Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");  
  24. }  

 

 

onLoadFinished

这个方法是在前面已创建的装载器已经完成其加载过程后被调用.这个方法保证会在应用到装载器上的数据被释放之前被调用.在此方法中,你必须删除所有对旧数据的使用(因为它将很快会被删除),但是不要自己去释放它们,因为它们的装载器会做这些事情.

装载器一旦了解到应用不再使用数据时,将马上释放这些数据.例如,如果数据是一个从CursorLoader来的游标,你不应调用游标的close().如果游标被放置在一个CursorAdapter中,你应使用swapCursor()方法,以使旧的游标不被关闭.例如:

 

[java] view plaincopy
 
  1. //这个Adapter被用于显示列表的数据.  
  2. SimpleCursorAdapter mAdapter;  
  3. ...  
  4.   
  5. public void onLoadFinished(Loader<Cursor> loader, Cursor data) {  
  6.     // Swap the new cursor in.  (The framework will take care of closing the  
  7.     // old cursor once we return.)  
  8.     mAdapter.swapCursor(data);  
  9. }  

 

onLoaderReset

当一个已创建的装载器被重置从而使其数据无效时,此方法被调用.此回调使你能发现什么时候数据将被釋放于是你可以釋放对它的引用.

下面这个实现调用参数为nullswapCursor()

 

[java] view plaincopy
 
  1. // 这个Adapter被用于显示列表的数据.  
  2. SimpleCursorAdapter mAdapter;  
  3. ...  
  4.   
  5. public void onLoaderReset(Loader<Cursor> loader) {  
  6.     //此处是用于上面的onLoadFinished()的游标将被关闭时执行, 我们需确保我们不再使用它.  
  7.     mAdapter.swapCursor(null);  
  8. }  

 

例子

作为一个例子,这里完整实现了一个Fragment显示一个包含从联系人contentprovider 返回查询数据的ListView的内容的功能.它使用一个CursorLoader来管理对provider的查询.


为了能从用户的联系人中取得数据,本例的manifest必须包含READ_CONTACTS权限.

 

[java] view plaincopy
 
  1. public static class CursorLoaderListFragment extends ListFragment  
  2.         implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {  
  3.   
  4.     // 这是用于显示列表数据的Adapter  
  5.     SimpleCursorAdapter mAdapter;  
  6.   
  7.     // 如果非null,这是当前的搜索过虑器  
  8.     String mCurFilter;  
  9.   
  10.     @Override public void onActivityCreated(Bundle savedInstanceState) {  
  11.         super.onActivityCreated(savedInstanceState);  
  12.   
  13.         // 如果列表中没有数据,就给控件一些文字去显示.在一个真正的应用  
  14.         // 中这应用资源中取得.  
  15.         setEmptyText("No phone numbers");  
  16.   
  17.         // 我们在动作栏中有一个菜单项.  
  18.         setHasOptionsMenu(true);  
  19.   
  20.         // 创建一个空的adapter,我们将用它显示加载后的数据  
  21.         mAdapter = new SimpleCursorAdapter(getActivity(),  
  22.                 android.R.layout.simple_list_item_2, null,  
  23.                 new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },  
  24.                 new int[] { android.R.id.text1, android.R.id.text2 }, 0);  
  25.         setListAdapter(mAdapter);  
  26.   
  27.         // 准备loader.可能是重连到一个已存在的或开始一个新的  
  28.         getLoaderManager().initLoader(0nullthis);  
  29.     }  
  30.   
  31.     @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {  
  32.         // 放置一个动作栏项用于搜索.  
  33.         MenuItem item = menu.add("Search");  
  34.         item.setIcon(android.R.drawable.ic_menu_search);  
  35.         item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);  
  36.         SearchView sv = new SearchView(getActivity());  
  37.         sv.setOnQueryTextListener(this);  
  38.         item.setActionView(sv);  
  39.     }  
  40.   
  41.     public boolean onQueryTextChange(String newText) {  
  42.         // 在动作栏上的搜索字串改变时被调用.更新  
  43.         //搜索过滤器,并重启loader来执行一个新的查询  
  44.         mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;  
  45.         getLoaderManager().restartLoader(0nullthis);  
  46.         return true;  
  47.     }  
  48.   
  49.     @Override public boolean onQueryTextSubmit(String query) {  
  50.         // 我们不关心这个方法  
  51.         return true;  
  52.     }  
  53.   
  54.     @Override public void onListItemClick(ListView l, View v, int position, long id) {  
  55.         // 写入你想写的代码  
  56.         Log.i("FragmentComplexList""Item clicked: " + id);  
  57.     }  
  58.   
  59.     // 这是我们想获取的联系人中一行的数据.  
  60.     static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {  
  61.         Contacts._ID,  
  62.         Contacts.DISPLAY_NAME,  
  63.         Contacts.CONTACT_STATUS,  
  64.         Contacts.CONTACT_PRESENCE,  
  65.         Contacts.PHOTO_ID,  
  66.         Contacts.LOOKUP_KEY,  
  67.     };  
  68.     public Loader<Cursor> onCreateLoader(int id, Bundle args) {  
  69.         // 当一个新的loader需被创建时调用.本例仅有一个Loader,  
  70.         //所以我们不需关心ID.首先设置base URI,URI指向的是联系人  
  71.         Uri baseUri;  
  72.         if (mCurFilter != null) {  
  73.             baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,  
  74.                     Uri.encode(mCurFilter));  
  75.         } else {  
  76.             baseUri = Contacts.CONTENT_URI;  
  77.         }  
  78.   
  79.         // 现在创建并返回一个CursorLoader,它将负责创建一个  
  80.         // Cursor用于显示数据  
  81.         String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("  
  82.                 + Contacts.HAS_PHONE_NUMBER + "=1) AND ("  
  83.                 + Contacts.DISPLAY_NAME + " != '' ))";  
  84.         return new CursorLoader(getActivity(), baseUri,  
  85.                 CONTACTS_SUMMARY_PROJECTION, select, null,  
  86.                 Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");  
  87.     }  
  88.   
  89.     public void onLoadFinished(Loader<Cursor> loader, Cursor data) {  
  90.         // 将新的cursor换进来.(框架将在我们返回时关心一下旧cursor的关闭)  
  91.         mAdapter.swapCursor(data);  
  92.     }  
  93.   
  94.     public void onLoaderReset(Loader<Cursor> loader) {  
  95.         //在最后一个Cursor准备进入上面的onLoadFinished()之前.  
  96.         // Cursor要被关闭了,我们需要确保不再使用它.  
  97.         mAdapter.swapCursor(null);  
  98.     }  
  99. }  
分享到:
评论

相关推荐

    android loader异步装载数据

    在Android开发中,Loader是一种强大的工具,用于在后台线程加载数据并自动处理数据变更,以便在用户界面上保持最新状态。"android loader异步装载数据"这一主题着重讲解了如何利用Loader机制来实现聊天软件的数据...

    Android lOADER

    在Android系统中,Loader是一种重要的组件,主要用于异步加载数据并更新UI。在这个特定的上下文里,“Android LOADER”似乎是指与3DS模型(3D Studio Max)和MD2格式相关的加载技术。MD2(Quake II Model)是3D游戏...

    Android-基于RxJavaObservable封装的一个AndroidLoader

    在Android应用开发中,Loader是一种用于管理后台数据加载的组件,它可以帮助我们处理异步操作,使得数据在用户界面更新时更加流畅。RxJava则是一个非常流行的响应式编程库,可以方便地处理异步事件流。将RxJava ...

    android loader 测试demo

    在Android开发中,Loader是一种强大的工具,用于在后台加载数据并保持与Activity或Fragment的生命周期同步。本测试Demo主要展示了如何使用Android系统提供的`CursorLoader`以及如何自定义`AppLoader`来实现数据加载...

    Android Loader详细介绍及实例代码

    Android Loader 是一个强大的工具,自Android 3.0(API级别11)开始引入,用于在Activity或Fragment中异步加载数据。Loader的设计目标是简化数据加载过程,使其能够跟踪数据源的变化,并在数据更新时自动传递新结果...

    Android Loader的使用以及手机通讯录的获取方法

    在Android开发中,Loader是一种强大的工具,用于在后台异步加载数据,并且与UI线程解耦,防止因长时间操作导致应用程序无响应(ANR)。Loader管理器在Activity和Fragment中帮助开发者处理数据加载,确保数据加载过程...

    Android 使用Loader 读取联系人

    在Android开发中,Loader是一种强大的工具,用于在后台异步加载数据,并且能够处理数据源的变更,如当用户添加、删除或修改联系人时。Loader API被设计为与Activity和Fragment生命周期紧密结合,确保在正确的时间...

    loader的使用

    在Android开发中,Loader是一种强大的工具,用于在后台加载数据并自动管理数据的生命周期,尤其在数据变化时。Loader的设计目标是解决UI线程阻塞问题,提高应用程序的响应性和用户体验。下面我们将深入探讨Android ...

    Android代码-Android-Skin-Loader

    Android-Skin-Loader &gt; 联系我 : fengjun.dev@gmail.com &gt; &gt; 个人博客 : http://allenfeng.com/ &gt; &gt; 一个通过动态加载本地皮肤包进行换肤的皮肤框架 更新日志 导入到Android Studio,使用gradle构建皮肤包(见7. ...

    android读取本地照片和相册

    GalleryActivity读取本地相册及照片 能够按相册区分 并选取照片 1 读取本地照片 2 查看本地的相册,以及其中照片信息 3 选择一个相册,查看其中照片 4 选取照片进行操作或者上传 5查看自己选择的照片 ...

    Android 异步加载显示 Loader 自定义Loader

    在Android开发中,Loader是一种强大的工具,用于在后台线程加载数据并通知UI进行更新,以避免阻塞主线程。Android 3.0引入了Loader API,为开发者提供了更高效、灵活的数据加载机制。本教程将详细介绍如何使用自定义...

    androidx-loader-1.0.0.aar

    androidx loader 资源包

    Android代码-SugarLoader

    A lightweight API to add syntax sugar to Android Loader API Why SugarLoader ? Google's Loader API is great, as it provides a robust way to load data into a fragment or an activity, with no risk to ...

    Android 中 Loader 及 LoaderManager 的使用

    在Android应用开发中,Loader和LoaderManager是两个关键的概念,它们用于高效地管理数据加载,尤其是在数据变化时的更新处理。Loader是Android框架提供的一种异步加载数据的机制,而LoaderManager则是用来管理Loader...

    Android代码-File-Loader

    Android library for downloading, saving/caching and retrieving any type of files ( image, video, pdf, apk etc ) easily. Download Gradle: repositories { mavenCentral() maven { url '...

    Asynchronous Android Programming

    Get accustomed to the use of the Android Loader construct to deliver up-to-date results In Detail Asynchronous programming has acquired immense importance in Android programming, especially when we ...

    android sqlite数据库升级及使用loader异步加载

    Loader是Android框架中用于后台加载数据的组件,尤其适用于需要在UI线程之外执行复杂数据获取的情况。LoaderManager和Loader接口共同提供了加载、刷新和回收数据的能力。 1. LoaderManager:管理Loader的生命周期,...

    android_loader_demo

    当然也有很多的开源框架中也可以处理这些问题,但是我个人认为Android提供的Loader机制绝对是首选。 Loader的出现以一种更友好的方式改善了用户体验。主要优点概括: 1. 与Activity和Fragment完美融合; 2. 异步加载...

Global site tag (gtag.js) - Google Analytics