zoukankan      html  css  js  c++  java
  • Android应用程序后台加载数据

    从ContentProvider查询你需要显示的数据是比较耗时的。如果你在Activity中直接执行查询的操作,那么有可能导致Activity出现ANR的错误。即使没有发生ANR,用户也容易感知到一个令人烦恼的UI卡顿。为了避免那些问题,你应该在另外一个线程中执行查询的操作,等待查询操作完成,然后再显示查询结果。

    通过CursorLoader对象,你可以用一种简单的方式实现异步查询,查询结束时它会和Activity进行重新连接。 CursorLoader不仅仅能够实现在后台查询数据,还能够在查询数据发生变化时自动执行重新查询的操作。

    主题一:使用CursorLoader执行查询任务

    CursorLoader通过ContentProvider在后台执行一个异步的查询操作,并且返回数据给调用它的Activity或者FragmentActivity。这使得Activity或者FragmentActivity能够在查询任务正在执行的同时继续与用户进行其他的交互操作。

    如何定义使用CursorLoader的Activity?

    为了在Activity或者FragmentActivity中使用CursorLoader,它们需要实现LoaderCallbacks<Cursor>接口。CursorLoader会调用LoaderCallbacks<Cursor>定义的这些回调方法与Activity进行交互。

    public class PhotoThumbnailFragment extends FragmentActivity implements
            LoaderManager.LoaderCallbacks<Cursor> {
    ...
    }

    如何初始化查询?

    为了初始化查询,需要调用LoaderManager.initLoader()。这个方法可以初始化LoaderManager的后台查询框架。你可以在用户输入查询条件之后触发初始化的操作,如果你不需要用户输入数据作为查询条件,你可以在onCreate()或者onCreateView()里面触发这个方法。

        // Identifies a particular Loader being used in this component
        private static final int URL_LOADER = 0;
        ...
        /* When the system is ready for the Fragment to appear, this displays
         * the Fragment's View
         */
        public View onCreateView(
                LayoutInflater inflater,
                ViewGroup viewGroup,
                Bundle bundle) {
            ...
            /*
             * Initializes the CursorLoader. The URL_LOADER value is eventually passed
             * to onCreateLoader().
             */
            getLoaderManager().initLoader(URL_LOADER, null, this);
            ...
        }

    需要注意的是:getLoaderManager()仅存在于Fragment类中;如果想要在FragmentActivity中获取到LoaderManager实例,可以调用getSupportLoaderManager()。

    如何启动查询任务?

    一旦后台任务被初始化好,它会执行你实现的回调方法onCreateLoader()。为了启动查询任务,会在这个方法里面返回CursorLoader。你可以初始化一个空的CursorLoader然后使用它的方法来定义你的查询条件,或者你可以在初始化CursorLoader对象的时候就同时定义好查询条件。

    /*
    * Callback that's invoked when the system has initialized the Loader and
    * is ready to start the query. This usually happens when initLoader() is
    * called. The loaderID argument contains the ID value passed to the
    * initLoader() call.
    */
    @Override
    public Loader<Cursor> onCreateLoader(int loaderID, Bundle bundle)
    {
        /*
         * Takes action based on the ID of the Loader that's being created
         */
        switch (loaderID) {
            case URL_LOADER:
                // Returns a new CursorLoader
                return new CursorLoader(
                            getActivity(),   // Parent activity context
                            mDataUrl,        // Table to query
                            mProjection,     // Projection to return
                            null,            // No selection clause
                            null,            // No selection arguments
                            null             // Default sort order
            );
            default:
                // An invalid id was passed in
                return null;
        }
    }

    一旦后台查询任务获取到了这个Loader对象,就开始在后台执行查询的任务。当查询完成之后,会执行onLoadFinished()这个回调函数。

    主题二:处理查询的结果

    在 onCreateLoader()的回调里面使用CursorLoader执行加载数据的操作。Loader查询完后会调用Activity或者FragmentActivity的LoaderCallbacks.onLoadFinished()将结果回调回来。这个回调方法的参数之一是Cursor,它包含了查询的数据。你可以使用Cursor对象来更新需要显示的数据或者进行下一步的处理。

    除了onCreateLoader()与onLoadFinished(),你也需要实现onLoaderReset()。这个方法在CursorLoader检测到Cursor上的数据发生变化的时候会被触发。当数据发生变化时,系统也会触发重新查询的操作。

    如何处理查询的结果?

    为了显示CursorLoader返回的Cursor数据,需要使用实现AdapterView的视图组件,,并为这个组件绑定一个实现了CursorAdapter的Adapter。系统会自动把Cursor中的数据显示到View上。

    你可以在显示数据之前建立View与Adapter的关联。然后在onLoadFinished()的时候把Cursor与Adapter进行绑定。一旦你把Cursor与Adapter进行绑定之后,系统会自动更新View。当Cursor上的内容发生改变的时候,也会触发这些操作。

    public String[] mFromColumns = {
        DataProviderContract.IMAGE_PICTURENAME_COLUMN
    };
    public int[] mToFields = {
        R.id.PictureName
    };
    // Gets a handle to a List View
    ListView mListView = (ListView) findViewById(R.id.dataList);
    /*
     * Defines a SimpleCursorAdapter for the ListView
     *
     */
    SimpleCursorAdapter mAdapter =
        new SimpleCursorAdapter(
                this,                // Current context
                R.layout.list_item,  // Layout for a single row
                null,                // No Cursor yet
                mFromColumns,        // Cursor columns to use
                mToFields,           // Layout fields to use
                0                    // No flags
        );
    // Sets the adapter for the view
    mListView.setAdapter(mAdapter);
    ...
    /*
     * Defines the callback that CursorLoader calls
     * when it's finished its query
     */
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        ...
        /*
         * Moves the query results into the adapter, causing the
         * ListView fronting this adapter to re-display
         */
        mAdapter.changeCursor(cursor);
    }

    如何处理废旧的Cursor引用?

    当Cursor失效的时候,CursorLoader会被重置。这通常发生在Cursor相关的数据改变的时候。在重新执行查询操作之前,系统会执行你的onLoaderReset()回调方法。在这个回调方法中,你应该删除当前Cursor上的所有数据,避免发生内存泄露。一旦onLoaderReset()执行结束,CursorLoader就会重新执行查询操作。

    /*
     * Invoked when the CursorLoader is being reset. For example, this is
     * called if the data in the provider changes and the Cursor becomes stale.
     */
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        
        /*
         * Clears out the adapter's reference to the Cursor.
         * This prevents memory leaks.
         */
        mAdapter.changeCursor(null);
    }
  • 相关阅读:
    谈谈node(1)
    怎么调用html5的摄像头,录音,视频?
    es6-块级作用域let 和 var的区别
    输入手机号自动分隔
    How do I know which version of Javascript I'm using?
    PHP的类中的常量,静态变量的问题。
    【转】马拉松式学习与技术人员的成长性
    JavaScript Prototype in Plain Language
    Promise编程规范
    XMLHttpRequest对象解读
  • 原文地址:https://www.cnblogs.com/CVstyle/p/6391855.html
Copyright © 2011-2022 走看看