Android loader的简单使用

来源:互联网 发布:如何升级mac系统 编辑:程序博客网 时间:2024/06/05 23:41

Android Loader 使用

Loader机制说明

  1. 异步加载数据,不阻塞UI线程
  2. 主要相关内容是LoaderManager(抽象类)、LoaderManager.LoaderCallBacks(接口),Loader(普通类)
  3. Loader是异步加载数据的文艺法,2B法是Thread+Handler,普通法是AsyncTask

使用Loader

  1. 在一个Activity(或者Fragment,以下Activity指Activity或Fragment)中实现LoaderManager.LoaderCallBacks,常用的方法是直接用Activity实现该接口
  2. 在Activity中创建Loader对象
  3. 在Activity中使用LoaderManager启动Loader

LoaderManager

  1. 管理多个Loader实例,用id来区分各个Loader
  2. 每个Activity都只有一个LoaderManager,所以不用获得其句柄,要用时直接getLoaderManager()即可,这里返回的当然是LoaderManager的非抽象子类,但是我不用管它具体是什么

LoaderManager的常用方法

  1. initLoader(int id, Bundle args, LoaderCallbacks callback):启动一个Loader,该id的Loader不存在则创建,存在则复用(原先Loader查询到的数据不会丢失)。第二个参数是传给Loader构造器的,当然如果该Loader已经存在,那第二个参数会被忽略
  2. restartLoader(int id, Bundle args, LoaderCallbacks callback):重启一个Loader,丢弃旧数据,重新加载

LoaderManager.LoaderCallBacks需要重写的方法

  1. public android.content.Loader onCreateLoader(int id, Bundle args)
    :Loader被需要创建前调用,args参数就是LoaderManager传进来的,这里必须要创建并返回一个Loader对象
  2. public void onLoadFinished(android.content.Loader loader, Cursor data)
    :Loader加载完数据后调用,data就是加载到的数据
  3. public void onLoaderReset(android.content.Loader loader)
    :Loader被重置时调用,Loader的数据将不可用,因此我需要在这里移除对那些数据的引用

Loader的常用子类

  1. AsyncTaskLoader:抽象类,需要自己实现,而且我不熟。可以在loadInBackground中注册观察者来监视数据变化
  2. CursorLoader:普通类,AsyncTaskLoader的子类,常用。能监听数据变化,当数据变化后,回调onLoadFinished方法。因为它会注册ContentObserver

CursorLoader的使用方法:直接new一个,参数就是数据库查询的参数:
1. uri - 指向数据源的 URI
2. projection - 指定哪些列(columns)会被返回的数组,传入 null 的话会返回所有的数据,这样并不高效。
3. selection - 指定哪些行(rows)会被返回的过滤条件,会被格式化为 SQL 语句中的 WHERE 语法(不要包含 WHERE 自身)。传 null 将返回所有的行。
4. selectionArgs - 如果你在 selection 中使用 ?s 语法,那么这些值会被 selectionArgs 参数替换,替换顺序按照在 selection 中的顺序。
5. sortOrder - 如何对返回结果排序,它会被格式化为 SQL 的 ORDER BY 语句(排除 ORDER BY 自身)。传入 null 的话使用默认顺序(也许是无序的)。

代码示例

这个例子就是一坨粑粑,有空我要换掉它

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {    private RecyclerView recyclerView;    private MyAdapter mAdapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,false));        mAdapter = new MyAdapter();        //明明setAdapter时,Adapter中没数据,下面一条代码才加载数据,而且RecyclerView也没监听数据变化,但是却能正确显示        //原因我想大概是界面显示慢,而数据加载快吧。虽然加载数据的代码比较靠后,但是它的执行速度快        //但是我不建议把这行代码放在这里,所以注释掉它        //recyclerView.setAdapter(mAdapter);        getLoaderManager().initLoader(1,null,this);    }    @Override    public android.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {        return new CursorLoader(MainActivity.this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,new String[]{MediaStore.Audio.Media.TITLE},null,null,MediaStore.Audio.Media.DEFAULT_SORT_ORDER);    }    @Override    public void onLoadFinished(android.content.Loader<Cursor> loader, Cursor data) {        mAdapter.swapCursor(data);        //我觉得这行代码放这里好一些,这里能确保数据已经加载完毕        recyclerView.setAdapter(mAdapter);    }    @Override    public void onLoaderReset(android.content.Loader<Cursor> loader) {    }    class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{        private List<String> datas = new ArrayList<>();        @Override        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);            return new MyViewHolder(view);        }        @Override        public void onBindViewHolder(MyViewHolder holder, int position) {            holder.getTextView().setText(datas.get(position));        }        @Override        public int getItemCount() {            return datas.size();        }        class MyViewHolder extends RecyclerView.ViewHolder {            private TextView textView;            public MyViewHolder(View itemView) {                super(itemView);                textView = (TextView) itemView.findViewById(R.id.textView);            }            public TextView getTextView() {                return textView;            }        }        public void swapCursor(Cursor data){            if(data!=null) {                //这里不用data.moveToFirst(),那样就不能读取表格第一行(下标为0)的数据了                data.moveToPosition(-1);                while (data.moveToNext() && data.getPosition() < 10) {                    datas.add(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)));                }                data.close();            }            else {                datas=null;            }        }    }}