Android Loader机制,实现异步加载数据

Loader


从Android3.0开始,Android SDK提供了Loader技术,使用Loader技术可以很容易进行数据的异步加载。

Loader 的主要API

LoaderManager:可以通过Activity或者的Fragment的getLoaderManager()方法得到LoaderManager,用来对Loader进行管理,
一个Activity或者Fragment只能有一个LoaderManager。

LoaderManager.LoaderCallbacks:用于同LoaderManager进行交互,可以在其中创建Loader对象。

AsyncTaskLoader:抽象类,可以进行异步加载数据的Loader,貌似内部也是通过AsynTask实现的
,可以通过继承它构建自己的Loader,也可以使用现有的子类,例如异步查询数据库可以使用CursorLoader。

使用Loader一般步骤:

  1. 初始化Loader,可以使用initLoader(intid, Bundle args, LoaderManager.LoaderCallbacks callback);方法进行初始化。
    id:标识Loader的ID,一个Activity或者Fragment只能有一个LoaderManager,但可以有多个Loader,通过ID区 分。在新建Loader时,如果发现已经有相同ID的Loader就会复用该Loader,而不会重新创建。
    args:传给新建Loader的参数。
    Callback:回调接口。

  2. 实现LoaderManager.LoaderCallbacks中的方法,LoaderManager.LoaderCallbacks中需要实现的方法有:
    public Loader onCreateLoader(int id, Bundle args):创建新的Loader,id为LoaderID,如果已经有相同ID的Loader就会复用该Loader,而不会重新创建。 args为初始化时传递的参数。该方法开始异步查询,并返回一个泛型类,如果是查询数据库可以返回一个CursorLoader,可以返回自定义的Loader。public voidonLoadFinished(Loader loader, D data):异步查询结束的会调用这个方法,并返回查询结果 data。public void onLoaderReset(Loader loader): 当调用Loader.reset()将Loader数据清空时,但在系统销毁Loader时会自动调用Loader.reset()方法,我们一般不需要手动调用,只需要在onLoaderReset方法中,将使用Loader的移除。

  3. 使用 restartLoader(intid, Bundle args, LoaderManager.LoaderCallbacks callback)方法进行数据更新,和初始化一个,如果有相同id的Loader存在,会复用Loader,并清空原有Loader中的数据,如果没有就新建一个。这个方法一般使用在需要更新数据时,例如下面例子中,在搜索关键改变时,需要调用这个方法,从新异步查询数据。


使用Loader实现加载联系人

这里写图片描述

所需权限(读取联系人)
<uses-permission android:name="android.permission.READ_CONTACTS"/>  
基本布局,使用ListView 即可
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.loader.MainActivity" >

    <TextView
        android:id="@android:id/empty"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>

</LinearLayout>
在菜单栏添加搜索框,用于测试Loader的异步加载
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity" >
     <!-- 显示搜索框 -->
    <item
        android:id="@+id/menu_search"
        android:actionViewClass="android.widget.SearchView"
        android:showAsAction="ifRoom|collapseActionView"
        android:title="搜索"
        tools:ignore="AppCompatResource">
    </item>
</menu>
MainActivity实现LoaderCallback 回调接口,实现OnQueryTextListener监听搜索框的变化

public class MainActivity extends ListActivity implements
        LoaderManager.LoaderCallbacks<Cursor>, SearchView.OnQueryTextListener {

    private SimpleCursorAdapter cursorAdapter;
    private String filterName = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(android.R.id.empty);
        tv.setText("请稍后");

        cursorAdapter = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_2, null,
                new String[] { ContactsContract.Contacts.DISPLAY_NAME },
                new int[] { android.R.id.text1 }, 0);
        setListAdapter(cursorAdapter);
        // 初始化Loader
        getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        Uri uri;
        // _ID字段必须存在
        String[] pro = new String[] { ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.Contacts._ID };
        if (TextUtils.isEmpty(filterName)) {
            uri = ContactsContract.Contacts.CONTENT_URI;
        } else {
            uri = Uri.withAppendedPath(
                    ContactsContract.Contacts.CONTENT_FILTER_URI,
                    Uri.encode(filterName));
        }
        // 创建Loader对象,开始异步加载数据
        return new CursorLoader(this, uri, pro, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // 得到异步加载数据,更新Adapter
        cursorAdapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // 移除adapter使用的Loader,系统会释放不再使用的Loader
        cursorAdapter.swapCursor(null);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        SearchView v = (SearchView) menu.findItem(R.id.menu_search)
                .getActionView();
        v.setOnQueryTextListener(this);
        return true;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        filterName = newText;
        // 使用新的Loader(清空旧的数据)
        getLoaderManager().restartLoader(0, null, this);
        return false;
    }
}

脚本之家有篇文章不错作为补充吧。CursorLoader的用法–jb51

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值