Android API Guides---Loader

Loader
在Android 3.0的推出,装载机可以很容易在活动或片段异步加载数据。装载机具有以下特点:
他们提供给每一个活动和片段。
它们提供的数据的异步加载。
他们监控其数据的来源和交付时新成果内容的变化。
配置更改后重新被他们时自动重新连接到最后加载程序的光标。因此,它们并不需要重新查询他们的数据。
装载机API摘要
有多个类和接口可能涉及在应用中使用装载机。他们总结在此表中:
类/接口描述
LoaderManager的抽象类具有   Activity或Fragment相关联的,用于管理一个或多个装载机实例。这有助于应用程序与活动或片段生命周期管理相结合长期运行的操作;这是最常见的用途是用CursorLoader,但是应用程序可以自由地写自己的装载机装载其他类型的数据。
由于每个活动或片段只有一个LoaderManager。但一个LoaderManager可以有多个装载机。
LoaderManager.LoaderCallbacks为客户与LoaderManager交互的回调接口。例如,你可以使用onCreateLoader()回调方法来创建一个新的加载器。
装载机的抽象类进行数据的异步加载。这是一个装载机的基类。您通常会使用CursorLoader,但你可以实现自己的子类。虽然装载机是活动的,他们应该监控其数据的来源和当内容改变时提供新的成果。
AsyncTaskLoader摘要装载机,提供了一个的AsyncTask做的工作。
CursorLoader AsyncTaskLoader的子类,查询ContentResolver的,并返回一个指针。此类实现查询游标,建立在AsyncTaskLoader在后台线程执行光标查询,以便它不会阻止应用程序的用户界面以标准的方式加载协议。使用这种装载机是异步从ContentProvider的加载,而不是通过片段或活动的API,执行托管查询的数据,最好的办法。
在上表中的类和接口都将使用来实现在应用程序中加载的重要组成部分。您不需要所有的人都为你创建的每个装载机,但你总是以初始化加载器和一个Loader类的实现,如CursorLoader需要的LoaderManager的参考。以下部分显示您如何使用这些类和接口在应用程序中。
在应用中使用装载机
本节将介绍如何在Android应用程序中使用装载机。使用装载机典型的应用包括以下内容:
一个活动或片段。
所述Load​​erManager的一个实例。
一个CursorLoader加载由ContentProvider的支持数据。另外,您也可以实现自己的装载机或AsyncTaskLoader的子类来从其他来源加载数据。
对于LoaderManager.LoaderCallbacks的实现。这是创建新的装载机和管理现有装载机的引用。
显示loader的数据,如一个SimpleCursorAdapter的一种方法。
数据源,如ContentProvider的,使用时CursorLoader。
启动加载器
该LoaderManager管理一个活动或片段中的一个或多个装载机实例。由于每个活动或片段只有一个LoaderManager。
您通常初始化加载该活动的onCreate()方法中,或片段的onActivityCreated()方法中。你这样做,如下所示:
// Prepare the loader.  Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);

该initLoader()方法采用下列参数:
一个唯一的ID标识装载机。在这个例子中,编号为0。
可选参数供应给施工(空在这个例子中)加载程序。
一个LoaderManager.LoaderCallbacks实施,其中LoaderManager打电话报告装载机事件。在本实施例中,本地类实现LoaderManager.LoaderCallbacks接口,因此它传递到自身的引用,这一点。
该initLoader()调用确保加载器被初始化和积极的。它有两个可能的结果:
如果由ID指定的加载器已经存在,最后创建的加载器重复使用。
如果由ID指定的加载器不存在,initLoader()触发LoaderManager.LoaderCallbacks方法onCreateLoader()。这是你实现代码实例化和返回一个新的加载器。有关详细讨论,请参见onCreateLoader。
在这两种情况下,给定的LoaderManager.LoaderCallbacks执行与装载器相关联,并且将被称为装载状态改变时。如果在这个点叫来电者是它的启动状态,并且请求的装载机已经存在,并且已经产生了数据,然后系统调用onLoadFinished()立即(initLoader期间()),所以你必须为此做好准备发生。见onLoadFinished这个回调的更多讨论
请注意,initLoader()方法返回所创建的装载机,但你并不需要捕捉引用。该LoaderManager自动管理加载器的使用寿命。的LoaderManager开始并在必要时停止加载,并保持该加载程序和它的相关联的内容的状态。由于这意味着,你很少直接加载器交互(尽管使用加载器方法微调装载机的行为的一个例子,看到LoaderThrottle样品)。您最常使用LoaderManager.LoaderCallbacks方法在加载过程中发生特定事件时进行干预。有关此主题的更多讨论,请参阅使用LoaderManager回调。
重新启动装载机
当您使用initLoader(),如上图所示,它使用现有的装载机具有指定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,预计在停止后保留其数据。这允许应用程序保持在整个活动或片段的的onStop()和在onStart()方法的数据,这样,当用户返回到一个应用程序,它们不必等待数据重新载入。您可以使用LoaderManager.LoaderCallbacks方法时,知道什么时候创建一个新的Loader,并告诉应用程序时,是时候停止使用loader的数据。
LoaderManager.LoaderCallbacks包括以下方法:
onCreateLoader() - 实例化并返回一个新的Loader为给定的ID。
onLoadFinished() - 当调用先前创建的装载机已完成其负载。
onLoaderReset() - 当先前创建的加载器被重置,从而使其数据不可调用。
这些方法更详细地在下面的章节中描述。
onCreateLoader
当您尝试访问加载器(例如,通过initLoader()),它会检查由ID指定的装载器是否存在。如果不是这样,它触发LoaderManager.LoaderCallbacks方法onCreateLoader()。这是你创建一个新的加载器。通常,这将是一个CursorLoader,但你可以实现自己的装载机子类。
在这个例子中,onCreateLoader()回调方法创建一个CursorLoader。你必须建立使用它的构造方法,这需要执行查询到所需ContentProvider的全套信息CursorLoader。具体而言,它需要:
URI - 的URI内容检索。
投影 - 一个列表,其中列返回。传递null将返回所有列,这是低效的。
选择 - 过滤行宣布要返回的,格式化为一个SQL WHERE子句(不包括WHERE本身)。传递null将返回给定的URI的所有行。
selectionArgs两个 - 你可能包括S IN的选择,这将是从selectionArgs两个值来代替,因为它们出现在选择的顺序?该值将被绑定为字符串。
中将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
当一个以前创建的加载器已经完成它的负载调用此方法。这种方法保证了为这个装载机提供的最后一个数据发布之前被调用。此时,您应该删除所有使用旧数据(因为它会很快被释放),但由于其拥有装载机,并会采取照顾不应该做你自己的数据发布。
一旦它知道应用程序不再使用它的装载机将释放数据。例如,如果数据是光标从CursorLoader,你不应该调用close()就可以了你自己。如果光标被放置在一个CursorAdapter的,你应该使用swapCursor()方法,使旧光标没有关闭。例如:
/ 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);
}


作为一个例子,这里是全面落实,显示包含对联系人内容提供者的查询结果一个ListView的一个片段。它采用了CursorLoader来管理供应商查询。
对于一个应用程序访问用户的联系人,如本例所示,它的清单必须包括许可READ_CONTACTS。
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几个不同的样本,说明如何使用装载机:
LoaderCursor - 上面显示的代码片段的完整版本。
LoaderThrottle - 如何使用节流来降低内容提供者确实时其数据变化查询的数量的例子。

你可能感兴趣的:(android,api,sdk,阅读,Loaders)