Android 3.0 - 究竟使用 LoaderManager 实例有什么好处? [英] Android 3.0 - what are the advantages of using LoaderManager instances exactly?

查看:19
本文介绍了Android 3.0 - 究竟使用 LoaderManager 实例有什么好处?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 3.0 中,我们得到了花哨的 LoaderManager,它使用 AsyncTaskLoaderCursorLoader 和其他自定义 Loader 处理数据加载 实例.但是通读这些文档时我无法理解:这些比使用旧的 AsyncTask 进行数据加载有什么好处?

With 3.0 we got the fancy LoaderManager, which handles data loading using the AsyncTaskLoader, the CursorLoader, and other custom Loader instances. But reading through the docs for these I just couldn't get the point: how are these better than just using the good old AsyncTask for data loading?

推荐答案

嗯,它们实施起来要简单得多,并且负责生命周期管理的所有事情,因此更不容易出错.

Well they are a lot simpler to implement, and take care of everything about lifecycle management so are much less error prone.

只需查看示例代码,即可显示游标查询的结果,让用户通过操作栏中的查询输入字段交互式过滤结果集:

Just look at the sample code, for showing the result of a cursor query which lets the user interactively filter the result set through a query input field in the action bar:

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

使用 AsyncTask 自己正确地实现这个完整的例子将涉及更多的代码......即使如此,你是否会实现一些完整且运行良好的东西?例如,您的实现是否会在活动配置更改时保留已加载的 Cursor,以便在创建新实例时不需要重新查询?LoaderManager/Loader 将自动为您执行此操作,并根据活动生命周期负责正确创建和关闭 Cursor.

Correctly implementing this full example yourself with AsyncTask is going to involve a lot more code... and even then, are you going to implement something as complete and well working? For example, will your implementation retain the loaded Cursor across activity configuration changes so it doesn't need to be re-queried when the new instances is created? LoaderManager/Loader will do that automatically for you, as well as taking care of correctly creating and closing the Cursor based on the activity lifecycle.

另请注意,使用此代码不需要您考虑确保在主 UI 线程之外执行长时间运行的工作.LoaderManager 和 CursorLoader 为您处理所有这些,确保您在与游标交互时永远不会阻塞主线程.要正确执行此操作,您实际上需要在某个点同时激活两个 Cursor 对象,以便您可以在加载下一个要显示的 Cursor 时继续使用当前 Cursor 显示交互式 UI.LoaderManager 为您完成所有这些工作.

Also notice that using this code doesn't require that you think at all about making sure long running work is performed off the main UI thread. LoaderManager and CursorLoader take care of all of that for you, ensuring you will never block the main thread while interacting with the cursor. To do this correctly you actually need to have two Cursor objects active at the same time at points, so you can continue to display an interactive UI with your current Cursor while the next one to show is being loaded. LoaderManager does all of that for you.

这只是一个简单得多的 API -- 无需了解 AsyncTask 并考虑需要在后台运行什么,无需考虑 Activity 生命周期或如何在 Activity 中使用旧的托管光标"API(无论如何,它的效果不如 LoaderManager).

This is just a much simpler API -- no need to know about AsyncTask and think about what needs to run in the background, no need to think about activity lifecycle or how to use the old "managed cursor" APIs in Activity (which didn't work as well as LoaderManager anyway).

(顺便说一句,不要忘记新的支持"静态库,它可以让您在低至 1.6 的旧版 Android 上使用完整的 LoaderManager API!)

(Btw don't forget the new "support" static library that let you use the full LoaderManager API on older versions of Android down to 1.6!)

这篇关于Android 3.0 - 究竟使用 LoaderManager 实例有什么好处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆