Android学习笔记——学习了解Loader

Loader简介

Android的Loader是从Android 3.0 Honeycomb中新引入的API,属于支持库的一部分,因此我们可以在支持旧版本时利用该特性。

Loader作用

Loader的作用主要是完成单线程耗时数据异步装载功能,并在数据有更新自动通知UI刷新的作用。因此Loader一般用于ActivityFragment异步加载数据,而无需重新启动一个线程来执行数据加载,异步加载可以用asyncTask,但是Loader自带数据结果监听机制,可以便捷地进行UI更新。

Loader基本原理

Loader对于ActivityFragment中的异步数据读取而言,基本上是最好的实现方法。当我们创建Loader时,Loader会创建一个asyncTask对象,在后台读取数据,当初始加载完成后,Loader会在UI线程中进行同步,也可以通过它来监听正在处理的数据将任何更新同步到UI线程。

Loader的优点

1. 提供异步加载数据功能;
2. 对数据源变化进行监听,实时更新数据;
3. 在Activity配置发生变化(如旋转屏幕)时避免重复加载数据;
4. 适用于任何Activity和Fragment;

使用Loader

创建LoaderManager

LoaderManager是一种与ActivityFragment相关的抽象类,用于管理一个或多个Loader实例,但每个ActivityFragment只拥有一个LoaderManager。通常我们会在ActivityonCreate()方法或者FragmentonActivityCreated()方法内初始化Loader

//准备Loader,可以重新连接一个已有的,也可以启动一个新的。
getLoaderManager().initLoader(0, null, this);

initLoader()方法一共接收三个参数:

  1. 第一个参数表示为Loader标记一个唯一ID,上例中ID为0;

  2. 第二个参数用于Loader初始化,代表提供给Loader构造器的参数,Bundle对象类型,是一个可选参数,上例中传入null;

  3. 第三个参数代表LoaderManager.LoaderCallbacks的回调实现,LoaderManager将调用这个实现来报告Loader事件,需要我们自己来实现。上例中,本地类实现LoaderManager.LoaderCallbacks接口,因此传入this。

上面的initLoader()方法能保证一个Loader被初始化并且激活,因此这个方法的调用会产生两种结果:

  1. 如果代表该Loader的ID已经存在,那么后面创建的Loader就会直接把存在的Loader拿来用;

  2. 如果代表该Loader的ID不存在,那么initLoader()会触发LoaderManager.LoaderCallbacks回调的onCreateLoader()方法创建一个Loader

可以看到,通过initLoader()方法可以将LoaderManager.LoaderCallbacks实例与Loader进行关联,而且当Loader的状态变化时回调。因此,如果调用者正处于开始状态,并且被要求的Loader已经存在同时已经产生了数据,那么系统就会立即调用onLoaderFinished()(前提是在initLoader()调用期间),所以我们必须考虑到这种情况的发生。

ps:initLoader()方法会返回已经创建的Loader,但我们不用获取它的引用,因为LoaderManager会自动管理Loader的生命周期,所以我们只需要使用LoaderManager>LoaderCallbacks中提供的生命周期方法中做自己数据逻辑的处理就可以了。

实现LoaderManager.LoaderCallbacks回调

LoaderManager.LoaderCallbacks是一种回调接口,用于客户端与LoaderManager及进行交互,例如,我们可以使用onCreateLoader()回调方法创建新的Loader

LoaderManager.LoaderCallbacks包含了三种方法:

  1. onCreateLoader(int id, Bundle args)
    这个方法会检查是否已经存在由该ID指定的Loader,如果没有,就会创建一个新的Loader,通常为CursorLoader,也可以实现自己的Loader子类。

  2. onLoadinished()
    将在先前创建的Loader完成加载时使用,每次都调用。

  3. onLoaderReset()
    将创建好的Loader被重置时调用此方法,会清空该Loader的数据,此时onCreateLoader()会重新执行。

Loader使用实例

public static class CursorLoaderListFragment extends ListFragment  
        implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {  

    // 创建显示列表数据的Adapter  
    SimpleCursorAdapter mAdapter;  

    // 创建搜索过滤器  
    String mCurFilter;  

    @Override public void onActivityCreated(Bundle savedInstanceState) {  
        super.onActivityCreated(savedInstanceState);  

        // 如果列表中没有数据,就给控件一些文字去显示.  
        setEmptyText("No phone numbers");  

        // 设置一个ActionBar的菜单栏  
        setHasOptionsMenu(true);  

        // 创建一个空的adapter来显示加载的数据
        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);  

        // 初始化Loader,要么重新连接一个已存在的,要么新建一个
        getLoaderManager().initLoader(0, null, this);  
    }  

    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {  
        //在菜单栏部署一个搜索键
        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) {  
        // 当搜索栏的字符改变时调用,更新搜索过滤器,同时重置Loader来执行新的查询
        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;  
        getLoaderManager().restartLoader(0, null, this);  
        return true;  
    }  

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

    @Override public void onListItemClick(ListView l, View v, int position, long id) {  
        // 写入我们的代码  
        Log.i("FragmentComplexList", "Item clicked: " + id);  
    }  

    // 获取联系人数据  
    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) {  
        // 当一个新的loader需要被创建时调用.本例中仅有一个Loader,  
        //所以我们不需要关心ID.首先设置base URI,URI指向的是联系人  
        Uri baseUri;  
        if (mCurFilter != null) {  
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,  
                    Uri.encode(mCurFilter));  
        } else {  
            baseUri = Contacts.CONTENT_URI;  
        }  

        // 现在创建并返回一个CursorLoader,用于创建一个Cursor,Cursor用于显示数据  
        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) {  
        // 把刚刚创建的Cursor传入
        mAdapter.swapCursor(data);  
    }  

    public void onLoaderReset(Loader<Cursor> loader) {  
        //确保cursor完全关闭
        mAdapter.swapCursor(null);  
    }  
}  

总结

Loader的相关接口

这里写图片描述

Android中加载耗时数据的常用方式

  1. 使用Thread和Handler的传统数据加载方式。
  2. 使用Asyncask异步加载的方式。
  3. 使用LoaderManager的加载方式,博主认为也是最符合面向对象编程思想的一种方式。

AsyncTaskLoader与AsyncTask的区别

优势:

  1. AsyncTaskLoader可以自动更新数据变化,自动处理Activity和Fragment变化造成的影响,适合处理纯数据加载。

  2. AsyncTask允许与UI实时交互以及replace操作。

劣势:

  1. AsyncTaskLoader不能实时通知UI刷新,不能在onLoadFinished时主动切换生命周期;

  2. AsyncTask不会自动处理Activity和Fragment配置变化造成的影响。

以上参考自:Google DeveloperTamic

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值