android Loaders

Android 3.0引进loaders使得activityfragment中异步加载数据变得简单.

Loaders有这些特点:

1.他们对每一个activityfragment都有效

2.他们提供异步加载数据

3.他们监听他们的数据源并且当数据内容发生改变的时候传递新的结果

4.在一个配置改变时,他们自动的重新连接到最后loader的光标.因此,他们不需要去重新查询他们的数据.



Loader API Summary(LoaderAPI概要)

LoaderManager 

  一个和Activity或者Fragment想关联的抽象类,它管理一个或者更多的Loader实例.这有助于一个应用管理在结合activityfragment的时候管理长时间运行的操作;它最常见的使用是和一个CursorLoader,  但是应用能自由的写入他们自己的loaders为了加载其他类型的数据.


LoaderManager.LoaderCallbacks 

一个为了客户端和LoaderManager 交互的回调接口.例如,你可以使用onCreateLoader()回调方法去创建一个新的loader.


Loader 

一个执行异步加载数据的抽象类.是一个loader的基础类.典型的你可以使用 CursorLoader ,但是你也可以实现你自己的子类.loaders被激活他们应该监听他们的数据源并且当内容发生改变时传递新的result.


AsyncTaskLoader 

一个提供 AsyncTask  去执行操作的抽象loader.


CursorLoader 

一个 AsyncTaskLoader 的子类,这个类查询 ContentResolver  并且返回一个Cursor .这个类以一种标准的查询Cursor 方式实现Loader协议,基于 AsyncTaskLoader 去执行cursor查询在一个后台线程中,因此它不会阻塞应用的UI. 从一个 ContentProvider 中异步加载数据的方式的最好方法就是使用这个loader , 而不是通过fragment或者activityAPI去执行一个查询管理.


Using Loaders in an Application(Loaders在一个应用中的使用)

一个应用经常在这些地方使用到loaders:

1.一个activity或者fragment

2.一个LoaderManager 的实例

3.一个通过 ContentProvider 在后台加载数据的 CursorLoader .或者,你能实现你自己的 Loader 或者 AsyncTaskLoader 从一些源中去加载数据.

4.一个 LoaderManager.LoaderCallbacks 接口的实现.

5.一个数据源,例如一个 ContentProvider ,当使用一个 CursorLoader 时.


Starting a Loader(启动一个loader)

LoaderManager 管理在activity或者fragment内部一个或多个Loader  的实例.每一个activity或者fragment只有一个 LoaderManager . 你通常在activityonCreate()方法中初始化一个 Loader ,或者在fragment onActivityCreated() 方法中,你可以像如下这样做:

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

 initLoader()  方法接受以下参数:

1.一个标识这个loader的唯一的ID

2.可选的建议参数在构造loader时候

3.一个 LoaderManager.LoaderCallbacks 的实现, LoaderManager 调用从而去报告加载事件.

initLoader()  方法的调用确保一个loader被初始化和激活,它可能有两个结果:

1.如果loader指定id已经存在,那么最后一个创建的loader将会被重新使用

2.如果通过id指定的loader不存在, initLoader() 触发 LoaderManager.LoaderCallbacks  的 onCreateLoader() 方法.这里是你实现代码去实例化和返回一个loader的地方.更多的描述,请看 onCreateLoader 部分.

另外一种情况,给予的 LoaderManager.LoaderCallbacks 实现已经和loader关联,那么当loader状态改变的时候将会被调用.如果这时这个方法的调用者已经在其启动状态,并且被请求的loader已经存在,并且已经产生了他的数据,那么系统会在 initLoader() 期间马上调用 onLoadFinished() 方法,因此你一定要对这种情况的发生有所准备.更多的描述,请看  onLoadFinished  部分.

注意 initLoader() 方法返回一个已经创建 Loader ,但是你不需要捕获一个对它的引用. LoaderManager  自定管理loader的生命周期 LoaderManager 在必要的时候启动和停止加载,并且维持这个loader的状态和它所关联的内容.这意味着,你将很少马上就和loader进行交互.当特定事件发生时,你最常使用 LoaderManager.LoaderCallbacks 接口的方法去干涉加载线程. 更多信息,请看 Using the LoaderManager Callbacks. 


Restarting a Loader(重新启动一个loader)

当你使用 initLoader() 方法时,如上所述,如果有一个已经存在的使用指定idloader,它就会使用它.如果没有,则会创建它.但是有时你会想要放弃掉你旧的数据并且重新开始.

你使用 restartLoader() 方法去放弃就数据.例如,当用户的查询改变时,this 实现 SearchView.OnQueryTextListener  接口去重新加载.因为这个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 LoaderManager Callbacks(LoaderManager 回调方法的使用)

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

Loaders,特别是 CursorLoader ,当他们被停止的时候都想要保持(记住)他们的数据.loaders允许应用穿过activity或者fragment onStop() 和onStart()  方法去保持他们的数据,因此当用户返回到一个应用时,他们没必要去等待数据的重新加载.

在知道什么时候创建一个新的loader,或者函数应用什么时候停止使用一个loader的数据时,使用LoaderManager.LoaderCallbacks  接口的方法.

LoaderManager.LoaderCallbacks  接口有这些方法:

1.onCreateLoader()  : 实例化并且返回一个给定ID的新创建的Loader 

2.onLoadFinished()  : 当以前创建好的一个loader被重置的时候调用.


onCreateLoader

当你企图去使用一个loader(例如,通过 initLoader() 方法),这个方法会检查通过指定IDloader是否存在.如果这个loader不存在,它会触发LoaderManager.LoaderCallbacks 的 onCreateLoader() 方法.

这里就是你新创建loader的地方,典型的loader是一个 CursorLoader ,但是你也能自己实现一个Loader的子类.

在这个例子中,onCreateLoader() 方法创建一个 CursorLoader 对象.你一定要使用CursorLoader  的构造方法去构建它,CursorLoader 的构造需要完成到 ContentProvider 中查询操作的信息的设置.

例如:

 // 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提供保证在最后数据被释放之前调用这意味着你应该移除掉所有使用的旧数据(因为他们很快就会被释放),but should not do your own release of the data since its loader owns it and will take care of that. 

Loader一旦知道应用很长时间没有使用它的时候,它会释放这些数据.例如,如果这些数据是一个从 CursorLoader 得到的cursor,你不应该自己去调用 close() 方法.如果这个cursor用在了一个 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被重置时这个方法被调用,因此让它的数据不可用.这个回调让你查明这些数据什么时候即将被释放因此你可以移除掉它的引用.

例如:

// 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(实例)

作为一个例子,这里是一个fragment的完全实现,这个fragment显示一个ListView 数据时从联系人的 content provider 中得到.它使用一个 CursorLoader 去管理在提供者上的查询. (It uses a CursorLoader to manage the query on the provider.) 

要让一个应用去使用一个用户的联系人,Manifest文件一定要声明 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);
    }
}


文件连接:http://blog.csdn.net/murongshusheng/article/details/7702540



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值