Loaders

来源:互联网 发布:steam免费mac游戏推荐 编辑:程序博客网 时间:2024/05/16 04:36

 

介绍在android3.0,Loaders 使异步导入数据在一个activity或fragment使用简单。Loaders特点:

1.      他们可以使用到每个activity和fragment。

2.      他们可以提供异步导入数据。

3.      他们监控他们的数据源并投递新的结果当内容改变时。

4.      他们自动重连接最后Loader的游标当被重新创建在一个配置修改,因此,他们不需要重新查询他们的数据。

 

LoaderAPI总结

这个多个类和接口被调用在使用loader在应用中。他们总结了这些在表中:

Class/Interface

Description

LoaderManager

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 the Activity orFragment 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. 

There is only one
 LoaderManager per activity or fragment. But aLoaderManager can have multiple loaders.

LoaderManager.LoaderCallbacks

A callback interface for a client to interact with the LoaderManager. For example, you use the onCreateLoader() callback method to create a new loader.

Loader

An abstract class that performs asynchronous loading of data. This is the base class for a loader. You would typically use CursorLoader, 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.

AsyncTaskLoader

Abstract loader that provides an AsyncTask to do the work.

CursorLoader

A subclass of AsyncTaskLoader that queries the ContentResolver 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 a ContentProvider, instead of performing a managed query through the fragment or activity's APIs.

 

这些类和接口子上面表中基本的组件你使用实现一个加载器在你的应用中。你不需要所有的加载器你创建,但是你将总是需要一个引用对LoaderManager为了初始化一个加载器并且实现一个加载器类比如CursorLoader。这个会在接下来将展示你怎么使用类和接口在应用中。

 

使用加载器在应用中

1.      一个activity或者Fragment.

2.      一个LoaderManager实例

3.      一个CursorLoader来加载数据用ContentProvider.也许你可以实现你自己的类Loader或者AsyncTaskLoader来加载数据从一些另外的资源里。

4.      一个实现LoaderManaer.LoaderCallbacks。这个是你创建一个新的加载器并且管理你的应用已经存在的加载器。

5.      一个方式展示加载的数据像一个SimpleCursorAdapter。

6.      一个数据源,比如ContentProvider,当使用CursorLoader。

 

启动一个

 

LoaderManager管理一个或多个Loader实例在一个Activity或Fragment。这个只有一个LoaderManager在每个activity或fragment里。

 

你代表初始化一个Loader在一个Activity的onCreate()方法里或者在fragment的onActivityCreated()方法。你可以接下来做:

// Prepare the loader.  Eitherre-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0,null,this);

这个initLoader方法做接下来的参数:

1.      唯一的ID定义这个loader。在例子这个id为0。

2.      可选择参数支持加载在构造函数中。

3.      一个LoaderManager.LoaderCallbacks实现,哪个LoaderManager调用报告加载器事件。在例子中,本地类实现LoaderManager.LoaderCallbacks接口,所以这个通过一个本身的引用。

这个initLoader()调用确定这个加载器初始化并激活。他有两个结果:

1.      假如加载器指定被一个已经存在的id,最后创建的会恢复。

2.      假如指定被一个不存在的id,initLoader()触发LoaderManager.LoaderCallbacks方法onCreateLoader()。在这个你实现的代码中示例并返回一个新的加载器。更多的讨论在onCreateLoader部分。

 

在无论发生什么情况,这个LoaderManager.LoaderCallbacks实现了相关联的加载器,并且将被调用当加载器状态改变时。假如在某个时间调用当调用者在启动状态,并且这个请求加载已经存在并且产生数据,当系统调用onLoaderFinished马上,所以你必须马上准备为这个发生。看onLoaderFinished为更多的讨论在返回。

 

注意initLoader()方法返回这个加载器被创建,但是你不需要捕获一个对它的引用。LoaderManager自动管理生命周期。这个LoaderManager开始并停止加载当需要的时候,并且保留加载器的状态并联系内容。这就意味着,你很少直接的和加载器交互(虽然对一个例子很少使用加载器方法在fine-tune加载的行为,看LoaderThrottle例子)。你必须使用LoaderManager.LoaderCallbacks方法干涉加载进程当指定事件发生。更多的讨论主题,看Using the LoaderManager Callbacks.

 

重新启动加载程序

当你使用initLoader(),像上面展示的,它使用一个已经存在的loader当一个指定的Id。假如不存在,它会创建一个。但是一些你想丢弃的老的数据和重新开始。

 

去掉去你老数据,你使用restartLoader()。比如,SearchView.OnQueryTextListener重器加载器当你使用查询改变时。这个加载器需要重新启动时他可以使用修改过的过滤器。

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;}

使用LoaderManager回调

LoaderManager.LoaderCallbacks是一个回调接口让一个客户端和LoaderManager交互。

加载器,在指定CursorLoader,预计保留数据在停止后数据。这个允许应用保持数据在通过activity或fragment的onStop和onStart方法里,所以当用户返回一个应用,他们不会等数据重新加载。你使用LoaderManager.LoaderCallbacks方法当你知道当你出创建一个新的加载器,并且告诉应用当它停止使用。

 

LoaderManager.LoaderCallbacks包括这些方法:

1.      onCreateLoade():实例化并且返回一个新的加载器id。

2.      onLoadFinished():调用当创建的加载器结束加载前。

3.      onLoaderReset():调用当创建的加载器被重置,因此使数据都失效。

 

这些方法描述更多在下面部分。

onCreateLoader

当你想访问一个加载器(比如,通过initLoader()),这个可以检查是否加载器指定ID已经存在。假如不存在,他就会触发LoaderManager.LoaderCallbacks方法onCreateLoader()。这个你可以创建一个新的加载器。典型的比如CursorLoader,但是你实现的你自己的加载器子类。

         举个例子,在onCreateLoader()回调方法创建一个CursorLoader。你必须建立CursorLoader使用构造方法,这个要求完全设置信息执行一个查询。特别的,他需要:

// 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

这个方法被调用在创建的加载器结束你后,这个方法是有担保优先被调用为了释放那些被加载器加载的数据。这时你应该移除所有旧的数据,但是你不应该使用你释放的数据从它加载他并且需要关注这些。

这个加载器将释放数据一旦知道应用不在使用它。比如,假如数据是一个游标从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

这个方法被调用当一个先前创建的加载器被重置,因此是数据不可用。这个回调让你寻找当数据打算被释放所以你可以移除他的引用。

这里实现调用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);}

例子:

一个例子,这里有实现所有一个Fragment展示一个ListView包含查询结果用内容提供器。他使用一个CursorLoader管理查询在提供者。为一个应用访问用户联系人在例子中展示,在它的清单中需要包含READ_CONTENT权限。

 

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);    }}

更多的例子:

这里不同的简单在apiDemos列举了怎样使用加载器:

1.      LoaderCursor-一个版本是上面的片段。

2.      LoaderThrottle-一个例子怎么样使用限流来减少查询内容提供者的数量当数据改变时。