本文出自:http://developer.android.com/guide/components/loaders.html#summary
Loaders
Android 3.0引入了Loader用于异步加载数据,Loaders使得在Activity和Fragment里异步加载数据变得更加容易。Loader有如下一些特性:
1.they are available to every activity and fragment.//activity和fragment里都能使用
2.they provide asynchronous loading of data.//提供数据的异步加载
3.they monitor the source of their data and deliver new results when the content changes.//自动监控源数据改变并通知数据、更行数据结果
4.They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data. //当配置改变时自动重连到最近使用的loader游标,这样不需要重复查询数据
Loader API Summary
在app里有多个相关与loader使用相关的类和接口,其摘要如下表:
Class/Interface |
Description |
An abstract class associated with an Activity or Fragment for managing one or more Loader instances. This helps an application manage longer-running operations in conjunction with theActivity or Fragment lifecycle; the most common use of this is with a CursorLoader, however applications are free to write their own loaders for loading other types of data. |
|
A callback interface for a client to interact with the LoaderManager. For example, you use the onCreateLoader() callback method to create a new loader. |
|
An abstract class that performs asynchronous loading of data. This is the base class for a loader. You would typically useCursorLoader, but you can implement your own subclass. While loaders are active they should monitor the source of their data and deliver new results when the contents change. |
|
Abstract loader that provides an AsyncTask to do the work. |
|
A subclass of AsyncTaskLoader that queries theContentResolver and returns a Cursor. This class implements the Loader protocol in a standard way for querying cursors, building on AsyncTaskLoader to perform the cursor query on a background thread so that it does not block the application's UI. Using this loader is the best way to asynchronously load data from aContentProvider, instead of performing a managed query through the fragment or activity's APIs. |
上面的类和接口是实现loader必须要的组件,但你不需要实现上面的所有类和接口。但为了能初始化一个Loader,你必须要持有一个LoaderManager的引用。你也必须提供Loader的实现类,例如CursorLoader。下面的部分将告诉你如何使用这些类和接口在你的app里实现loader。
Using Loaders in an application
该部分描述了如何在Android app里使用Loader。一个典型的使用loader的app包括:
1.一个activity或者Fragment
2.一个LoaderManager的实例
3.系统默认提供的Loader的实现类CursorLoader——通过ContentProvider进行数据加载。当然地,你也可以实现自己的loader或者AsyncTaskLoader来从其他的数据源加载数据
4.展示loader数据的方式,例如像SimpleCursorAdapter
5.数据源。例如当使用CursorLoader的数据源ContentProvider
Starting a Loader
LoaderManager管理一个activity或者Fragment里的一个或者多个Loader实例。每个Activity或者Fragment里只能有一个LoaderManager。
一般地,在一个activity的onCreate()方法里或者Fragment的onActivityCreated()方法里初始化一个Loader。如下所示:
// Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this);
initLoader方法接收如下几个参数:
1.Loader的唯一ID,上面的例子里ID是0
2.可选参数,当Loader构造时提供给loader用于loader的实例化(上面的例子里是null)
3.LoaderManager.LoaderCallbacks实现类。LoaderManager调用该回调类上报Loader事件。上面的例子里,该类本身实现了该接口,因此传递它自身的引用:this。
initLoader()的调用确保了loader被初始化和是active的,有如下两个结果
1.如果指定一个已经存在的Loader Id,将复用上次产生的Loader。
2.如果指定的Loader ID不存在,initloader()方法将触发LoaderManager.LoaderCallbacks的onCreateLoader()回调方法。在该方法里,你实现和返回新的Loader。关于这更多的讨论,请参见onCreateLoader部分。
不管上面两种情况中的哪种情况,LoaderManager.LoaderCallbacks的实现都和Loader相关,其在Loader状态改变时都将被调用。如果当loader已经是已开始状态,并且Loader已经存在,也产生了它的数据,那么系统立即的调用onLoadFinished()(在initLoader()期间),因此,你必须为这的发生做好准备。参见onLoaderFinished查看更多的回调方法讨论。
注意initLoader()方法会返回创建的Loader对象,但我们不需要持有该loader的引用。LoaderManager自动管理Loader的生命周期。LoaderManager在必要时开始和停止加载,维护loader的状态和与其相关的内容和数据。像这表明的,我们很少直接和loader打交道(though for an example of using loader methods to fine-tune a loader's behavior, see the LoaderThrottle sample),最常见的情况是当特定的事件发生时你使用LoaderManager.LoaderCallbacks回调干涉loader的加载过程。该主题的更多讨论,参见 Using the LoaderManager Callbacks.
Restarting a Loader
如上所示,当使用initLoader()的时候,如果指定的ID已经存在,这复用存在的Loader。如果没有,则产生一个新的Loader。有时,你可能想要丢弃旧的数据,然后再次加载新数据。
为了丢弃旧的数据,你能使用reStartLoader()。例如SearchView.OnQueryTextListener
的实现类当用户查询改变时重启Loader。为了使用经过修正的搜索过滤器进行一个新的查询,你需要重启Loader.
public boolean onQueryTextChanged(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; }
Using the LoaderManger Callbacks
LoaderManager.LoaderCallback是一个回调接口,用于客户端和LoaderManager进行交互。
Loaders,特别地例如CursorLoader,是被期望在已经停止后保留它们的数据。这使得App能在Activity或者Fragment的onStop()或者onStart()方法期间保持它们的数据。这样,当用户重新返回到application时,他们不必等数据重新加载。你能使用LoaderManager.LoaderCallback回调方法知道什么时候产生一个新的Loader,然后告诉application什么时候是停止使用Loader的数据的时机。
LoaderManager.LoaderCallback包括如下回掉方法:
1.onCreateLoader() — 产生对应ID的新的Loader,并返回该Loader
2.onLoadFinished() — 当先前已产生的Loader完成它的数据加载的时候调用
3.onLoaderReset() — 当先前已产生的Loader正被重置时调用,Loader重置后它的数据将变得无效。
下面将详细描述这些方法
onCreateLoader
当你企图访问Loader(例如,通过initLoader()),它会核查对应指定的ID的Loader是否存在,如果不存在,将触发LoaderManager.LoaderCallback的onCreateLoader方法,在这儿你可以产生一个新的Loader。例如CursorLoader,它是系统提供的一个实现了Loader的类,当然,你也可以实现自己的loader类。
例如,在onCreateLoader回调方法里你产生了一个CursorLoader,而产生该Loader需要调用它的构造方法,其构造方法需要如下一些参数,这些一系列参数用于执行对ContentProvider的查询:
1.uri — 检索内容的URI
2.projection — 返回列的列表,传递null,将返回所有列,但这样效率低。
3.selection — 返回行的过滤器,符合SQL WHERE 从句的格式(但不包括WHERE字段本身),传递null将返回对应uri的所有行(所有记录)。
4.selectionArgs — 在参数selection里可能包含通配符?,这些通配符将由来自于selectionArgs参数里的值取代。依序出现在selection里,将包装成字符串。
5.sortOrder — 怎么排序返回的结果行,符合SQL ORDER BY语句(但不包括ORDER BY关键字本身),传递null将采用默认的排序方式,将可能是无序的。
例如:
// If non-null, this is the current filter the user has provided. String mCurFilter; ... public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); }
onLoadFinished
该方法在先前已产生的Loader已完成加载时调用。该方法的调用要先于填充该loader的数据的释放。在这个点你需要移除所有旧数据的使用(因为数据将马上被释放)。但是你不应该对这些数据做你自己的释放操作,因为Loader拥有这些数据,应该有Loader关注和管理这些数据。
一旦Loader知道application将不在使用它时,Loader将释放这些数据。例如,如果这些数据是来自于CursorLoader的游标,你不应该调用它自身的close()方法,如果游标正在CursorAdapter里持有,你应该使用swapCursor()方法以便于旧的Cursor不被关闭。例如:
// This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; ... public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); }
onLoaderReset
该方法在先前产生的loader正被重置时调用,接着,数据将变得无效。这个回调告诉你数据即将被释放,因此你能移除对它的引用。
下面的实现类调用swapCursor()方法,传入的参数为null:
// This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; ... public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); }
Example
如下所示的例子,是一个利用Loader展示LIstVIiew数据的fragment的完整实现,该listview的展示数据来自于查询联系人content provider。使用CursorLoader管理和查询Provider。
对于一个访问用户联系人的应用,像下面所示的例子,其manifest文件里必须包括READ_CONATACTS权限。
public static class CursorLoaderListFragment extends ListFragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { // This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; // If non-null, this is the current filter the user has provided. String mCurFilter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Give some text to display if there is no data. In a real // application this would come from a resource. setEmptyText("No phone numbers"); // We have a menu item to show in action bar. setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, null, new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, new int[] { android.R.id.text1, android.R.id.text2 }, 0); setListAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // Place an action bar item for searching. MenuItem item = menu.add("Search"); item.setIcon(android.R.drawable.ic_menu_search); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); SearchView sv = new SearchView(getActivity()); sv.setOnQueryTextListener(this); item.setActionView(sv); } public boolean onQueryTextChange(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; } @Override public boolean onQueryTextSubmit(String query) { // Don't care about this. return true; } @Override public void onListItemClick(ListView l, View v, int position, long id) { // Insert desired behavior here. Log.i("FragmentComplexList", "Item clicked: " + id); } // These are the Contacts rows that we will retrieve. static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, }; public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); } public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); } public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); } }
More Examples
在ApiDemos里有几个不同例子,这些例子解释了如何使用loaders:
1.LoaderCursor — 上面所示片段的完全的版本
2.LoaderThrottle — An example of how to use throttling to reduce the number of queries a content provider does when its data changes
下载和安装SDK例子的更多信息,参见Getting the Samples
相关推荐
在Android开发中,Loader是一种强大的工具,用于在后台线程加载数据并自动处理数据变更,以便在用户界面上保持最新状态。"android loader异步装载数据"这一主题着重讲解了如何利用Loader机制来实现聊天软件的数据...
在Android系统中,Loader是一种重要的组件,主要用于异步加载数据并更新UI。在这个特定的上下文里,“Android LOADER”似乎是指与3DS模型(3D Studio Max)和MD2格式相关的加载技术。MD2(Quake II Model)是3D游戏...
在Android应用开发中,Loader是一种用于管理后台数据加载的组件,它可以帮助我们处理异步操作,使得数据在用户界面更新时更加流畅。RxJava则是一个非常流行的响应式编程库,可以方便地处理异步事件流。将RxJava ...
在Android开发中,Loader是一种强大的工具,用于在后台加载数据并保持与Activity或Fragment的生命周期同步。本测试Demo主要展示了如何使用Android系统提供的`CursorLoader`以及如何自定义`AppLoader`来实现数据加载...
Android Loader 是一个强大的工具,自Android 3.0(API级别11)开始引入,用于在Activity或Fragment中异步加载数据。Loader的设计目标是简化数据加载过程,使其能够跟踪数据源的变化,并在数据更新时自动传递新结果...
在Android开发中,Loader是一种强大的工具,用于在后台异步加载数据,并且与UI线程解耦,防止因长时间操作导致应用程序无响应(ANR)。Loader管理器在Activity和Fragment中帮助开发者处理数据加载,确保数据加载过程...
在Android开发中,Loader是一种强大的工具,用于在后台异步加载数据,并且能够处理数据源的变更,如当用户添加、删除或修改联系人时。Loader API被设计为与Activity和Fragment生命周期紧密结合,确保在正确的时间...
在Android开发中,Loader是一种强大的工具,用于在后台加载数据并自动管理数据的生命周期,尤其在数据变化时。Loader的设计目标是解决UI线程阻塞问题,提高应用程序的响应性和用户体验。下面我们将深入探讨Android ...
Android-Skin-Loader > 联系我 : fengjun.dev@gmail.com > > 个人博客 : http://allenfeng.com/ > > 一个通过动态加载本地皮肤包进行换肤的皮肤框架 更新日志 导入到Android Studio,使用gradle构建皮肤包(见7. ...
GalleryActivity读取本地相册及照片 能够按相册区分 并选取照片 1 读取本地照片 2 查看本地的相册,以及其中照片信息 3 选择一个相册,查看其中照片 4 选取照片进行操作或者上传 5查看自己选择的照片 ...
在Android开发中,Loader是一种强大的工具,用于在后台线程加载数据并通知UI进行更新,以避免阻塞主线程。Android 3.0引入了Loader API,为开发者提供了更高效、灵活的数据加载机制。本教程将详细介绍如何使用自定义...
androidx loader 资源包
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是两个关键的概念,它们用于高效地管理数据加载,尤其是在数据变化时的更新处理。Loader是Android框架提供的一种异步加载数据的机制,而LoaderManager则是用来管理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 '...
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 ...
Loader是Android框架中用于后台加载数据的组件,尤其适用于需要在UI线程之外执行复杂数据获取的情况。LoaderManager和Loader接口共同提供了加载、刷新和回收数据的能力。 1. LoaderManager:管理Loader的生命周期,...
当然也有很多的开源框架中也可以处理这些问题,但是我个人认为Android提供的Loader机制绝对是首选。 Loader的出现以一种更友好的方式改善了用户体验。主要优点概括: 1. 与Activity和Fragment完美融合; 2. 异步加载...