Android Loader 数据异步加载

文章目录

        • 1、简介
        • 2、耗时加载数据常用方式
          • 1) Thread + Handler
          • 2) AsyncTask
          • 3) Loader
        • 3、适用范围
          • 1)Loader 常用的接口
          • 2) 主要代码

1、简介

Loader 是在 Android 3.0 之后引入的api,主要完成单线程好事数据加载,并且能够在数据有更新的时候,通知UI自动刷新。

2、耗时加载数据常用方式

1) Thread + Handler

Android Loader 数据异步加载_第1张图片
优点 :
比较灵活

2) AsyncTask

Android Loader 数据异步加载_第2张图片

优点:
简单,快捷
过程可控
使用的缺点:
对只需要几秒内的线程操作方便

缺点:
在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

3) Loader

Android Loader 数据异步加载_第3张图片

优点:
提供异步加载数据功能;
对数据源变化进行监听,实时更新数据;
在Activity配置发生变化(如横竖屏切换)时不避免数据重复加载;
适用于任何Activity和Fragment;

3、适用范围

我们经常会遇到这种需求,在activity 或者 fragment 里面,我们需要查找某个数据源,并且显示出来。
然后当数据源改变的时候,Ui显示也要自动更新。
一般查找数据的时间,可能比较长,为了避免anr,我们都会通过 Thread + handler 组合来更新,但是这样就比较复杂。好在google推出 Loader 机制来帮我们实现这一功能。

我们 以访问 通讯录数据库同时实时更新UI 为例子。

1)Loader 常用的接口
接口 说明
LoaderManager 和Activity 或 Fragment 相关联的抽象类用来管理一个或者多个Loader实例
Loader 执行异步加载数据的抽象类。这是加载器的基类。我们通常使用CursorLoader,当加载器处于活动状态时,应监控其数据源并在内容变化时,传递新的内容
LoaderManager.LoaderCallback 回调接口,用于客户端与LoaderManager进行交互,比如 可以使用onCreateLoader()回调方法创建新的加载器
AsyncTaskLoader 提供AsyncTask来执行工作的抽象加载器
CursorLoader AsyncTaskLoader的子类,它将查询ContentResolve并返回一个Cursor.
2) 主要代码

布局就一个 listView 不在此显示

package myapplication.lum.com.myloadercontext;

import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.SimpleCursorAdapter;


public class MainActivity extends Activity implements LoaderCallbacks,
        OnQueryTextListener {
    private ListView lv;
    private SimpleCursorAdapter adapter;
    private String curFilter;// 用户当前输入的搜索内容,只有在用户输入的时候才会有,应用程序刚打开的时候没有
    private Uri phoneUri;
    private Cursor cursor;// 记录当前ListView中展示的数据



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CheckPermission checkPermission = new CheckPermission(this);
        checkPermission.checkPermissionExe();
        lv = (ListView) findViewById(R.id.lv);
        phoneUri = Phone.CONTENT_URI;// 电话号码Ur
        //第一个参数 当使用的activity名字
        //第二个参数  要绑定数据的布局
        //第三个参数 游标没有可以设置为空
        //第四个参数 指定 column 中的哪些列的数据将绑定(显示)到 UI 中
        //第五个参数就是要绑定到UI界面的那个组件

        adapter = new SimpleCursorAdapter(MainActivity.this,
                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 });
        lv.setAdapter(adapter);
        // 点击item,打电话:权限
        lv.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView parent, View view,
                                    int position, long id) {
                // 点击到某个item的时候,从cursor取出该item的数据
                cursor.moveToPosition(position);
                //拿出来id,因为要通过id查电话号码
                String idd = cursor.getString(cursor
                        .getColumnIndex(Contacts._ID));

                ContentResolver resolver = getContentResolver();
                //电话号码相关信息都在Phone中
                Cursor cursor2 = resolver.query(phoneUri, new String[] { Phone.DATA1 },
                        Phone.CONTACT_ID + "=?", new String[] { idd }, null);
                if(cursor2.moveToNext()){
                    //取出电话号码
                    String num = cursor2.getString(cursor2.getColumnIndex(Phone.DATA1));
                    System.out.println("==num==="+num);
                    //打电话:权限
                    Intent intent=new Intent();
                    intent.setAction(Intent.ACTION_CALL);
                    intent.setData(Uri.parse("tel://"+num));
                    startActivity(intent);
                }
            }
        });

        getLoaderManager().initLoader(1, null, this);
    }


    @Override
    public Loader onCreateLoader(int id, Bundle args) {
        Uri uri;
        if (curFilter != null) {
            uri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                    Uri.encode(curFilter));
        } else {
            uri = Contacts.CONTENT_URI;
        }
        // 记录的是要查询的列
        String[] projection = new String[] { Contacts._ID,
                Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS,
                Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID,
                Contacts.LOOKUP_KEY, };
        // 查询条件:
        String selection = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                + Contacts.DISPLAY_NAME + " != '' ))";
        CursorLoader loader = new CursorLoader(MainActivity.this, uri,
                projection, selection, null, Contacts.DISPLAY_NAME
                + " COLLATE LOCALIZED ASC");

        return loader;
    }

    @Override
    public void onLoadFinished(Loader loader, Cursor data) {
        adapter.swapCursor(data);
        cursor = data;
    }

    @Override
    public void onLoaderReset(Loader loader) {
        adapter.swapCursor(null);
    }

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

    @Override
    public boolean onQueryTextChange(String newText) {
        curFilter = TextUtils.isEmpty(newText) ? null : newText;
        // 输入内容改变过程中,动态刷新ListVIew
        getLoaderManager().restartLoader(1, null, this);

        return true;
    }

    
}

运行效果:

Android Loader 数据异步加载_第4张图片
我们先是 创建一个 loader 并且给它设置了查询的 数据库的地址和筛选条件,
他就会在后台对数据库进行检测观察,当数据有变化时,它就会回调自己的
onLoadFinished() 函数,我们在这个函数里,通过 adapter.swapCursor(data); 刷新数据。

当然 loader 也可以用来加载自己的数据库,视频,图片等。

文章参考:
Android中CursorLoader的使用、原理及注意事项

Android中CursorAdapter的使用详解

Android Cursor 的使用细节

你可能感兴趣的:(Android,进阶)