Android_Loader_使用LoaderManager管理Loader实现异步动态加载数据

本博文为子墨原创,转载请注明出处!

http://blog.csdn.net/zimo2013/article/details/10263339

1.Loader特性:

(1).对于每个Activity或者Fragment都可用
(2).提供异步加载数据
(3).监视数据资源,当内容改变时重新更新
(4).当配置改变时,自动重新连接最新的cursor,故不需要重新查询数据

2.Loader相关类接口

(1).LoaderManager

对于每个activity或者fragment只存在一个与之相关的LoaderManager对象,该LoaderManager对象可以存在多个可供管理loader对象。

(2).LoaderManager.LoaderCallbacks

LoaderManager.LoaderCallbacks是个回掉接口,用于客户端与LoaderManager的交互,loader对象就是在其接口的onCreateLoader()方法中得到,在使用时需要覆盖其方法。

(3).CursorLoader

CursorLoader是AsyncTaskLoader的子类,通过它可以查询ContentResolver并返回一个Cursor对象,并使用该cursor对象在后台线程执行查询操作,以不至于会阻塞主线程,从一个内容提供者去异步加载数据是CursorLoader对象最大用处。

3.简单使用Loaders

(1).得到LoaderManager对象

 
  1. //得到LoaderManager对象

  2. LoaderManager manager = content.getLoaderManager();

(2).初始化loader

在activity的onCreate()方法区或者在fragment的onActivityCreated()方法区中,需要初始化一个Loader对象(可能已经存在或者新创建),getLoaderManager().initLoader(0, null, this);调用initLoader()方法是确保loader对象已经初始化且可用,然而存在下面2种情况

1).ID存在

如果指定ID的loader已经存在,将重新使用最新的loader对象

2).ID不存在

如果指定的ID不存在,通过initLoader()方法,将会触发LoaderManager.LoaderCallbacks的onCreateLoader()方法并返回一个新的loader
虽然通过initLoader()可以得到loader对象,但是我们不需要捕获该对象,但LoaderManager对象可以自动管理loader生命周期,因此不需要直接与loader对象直接交互

(3).实现LoaderCallbacks

以典型的CursorLoader为例,app允许数据在onStart() 和 onStop()函数中传递,一旦的当用户重新进入app,不必等待数据重新加载,LoaderManager.LoaderCallbacks包含下面3个重要函数

1).onCreateLoader()

Instantiate and return a new Loader for the given ID.

当loadermanager调用initLoader()时, 首先检查指定的id是否存在,如果不存在才会触发该方法,通过该方法才能创建一个loader。返回创建的CursorLoader对象,其中可以在创建对象时,指定查询的条件,并携带一个Cursor对象。
CursorLoader接收 uri projection  selection  selectionArgs  sortOrder 等参数信息

 
  1. // 返回一个new CursorLoader对象

  2. public Loader<Cursor> onCreateLoader(int id, Bundle args) {

  3. Uri uri = Uri.parse("content://com.baidu.provider/music");

  4. return new CursorLoader(MainActivity.this, uri, null, null, null,

  5. null);

  6. }

2).onLoadFinished()

Called when a previously created loader has finished its load.

可以完成对Ui控件的更新,比如更新一个listView列表。一旦应用不在使用,将自动释放loader的数据,不需要使用close();

 
  1. // 完成对UI主界面的更新

  2. public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

  3. if(cursor == null){

  4. Toast.makeText(MainActivity.this, "失败", 1).show();

  5. return;

  6. }

  7. //ui主界面更新相关操作

  8. }

3).onLoaderReset()

Called when a previously created loader is being reset, thus making its data unavailable.

(4).重启loader

通过指定相同的loader ID,使用loadermanager的restartLoader()方法,消除就数据,加载新数据,达到动态更新的目的!可参考,ListView数据动态更新

 
  1. // 当检测到数据已经放手改变时,重启指定ID的loader

  2. if(u != null){

  3. MainActivity.this.getLoaderManager().restartLoader(0, null, myLoader);

  4. Toast.makeText(MainActivity.this, "插入成功", 1).show();

  5. }else{

  6. Toast.makeText(MainActivity.this, "插入失败", 1).show();

  7. }

4.loader向下兼容

(1)当前Activity继承FragmentActivity

(2).得到Loadermanager对象

 
  1. public void load(View view) {

  2. LoaderManager manager = this.getSupportLoaderManager();//注意,不同

  3. manager.initLoader(0, null, myLoader);

  4. }

(3).其余操作均不变,只不过导包时需要导入android.support.v4下的包

 5.应用

(1).需求

一个listView和一个按钮,点击按钮后使用内容提供者,往数据库中添加数据,同时达到listView动态更新的目的,但是listView回到第一个item,因为在cursor在restart的后,listview又重新设置了adapter,listview初始化后设置适配器可以避免该问题,可参考ListView数据动态更新一文。

(2).代码实现

 
  1. public class MainActivity extends Activity {

  2. private ListView listView;

  3. @Override

  4. protected void onCreate(Bundle savedInstanceState) {

  5. super.onCreate(savedInstanceState);

  6. setContentView(R.layout.activity_main);

  7. listView = (ListView) findViewById(R.id.list);

  8.  
  9. // 1.得到LoaderManager对象

  10. LoaderManager manager = this.getLoaderManager();

  11. manager.initLoader(0, null, myLoader);

  12. }

  13. // 2.覆写LoaderCallbacks相关方法

  14. private LoaderCallbacks<Cursor> myLoader = new LoaderCallbacks<Cursor>() {

  15. // 2.1创建一个新的CursorLoader对象,携带游标

  16. public Loader<Cursor> onCreateLoader(int id, Bundle args) {

  17. Uri uri = Uri.parse("content://com.baidu.provider/music"); //内容提供者的uri信息

  18. return new CursorLoader(MainActivity.this, uri, null, null, null,

  19. null);

  20. }

  21. // 2.2加载完成后,更新UI信息

  22. public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

  23. if(cursor == null){

  24. Toast.makeText(MainActivity.this, "失败", 1).show();

  25. return;

  26. }

  27. List<Map<String, String>> list = new ArrayList<Map<String, String>>();

  28. // 2.2.1往指定的集合中写入读取到的数据

  29. while (cursor.moveToNext()) {

  30. Map<String, String> map = new HashMap<String, String>();

  31. String id = cursor.getString(cursor.getColumnIndex("_id"));

  32. String name = cursor.getString(cursor.getColumnIndex("name"));

  33. String age = cursor.getString(cursor.getColumnIndex("age"));

  34.  
  35. map.put("id", id);

  36. map.put("name", name);

  37. map.put("age", age);

  38. list.add(map);

  39. }

  40. // 2.2.2新建一个适配器对象

  41. MyAdapter adapter = new MyAdapter();

  42. adapter.setList(list); //设置集合

  43. // 2.2.3为listView设置adapter,更新数据

  44. listView.setAdapter(adapter);

  45. // 2.2.4 设置适配器数据改变通知

  46. adapter.notifyDataSetChanged();

  47. }

  48. public void onLoaderReset(Loader<Cursor> arg0) {

  49. }

  50. };

  51. // 3.自定义适配器类

  52. class MyAdapter extends BaseAdapter {

  53. private List<Map<String, String>> list; //集合,存储数据

  54. public void setList(List<Map<String, String>> list) {

  55. this.list = list;

  56. }

  57. // 3.1得到列表数目,即为集合大小

  58. public int getCount() {

  59. return list.size();

  60. }

  61. public Object getItem(int arg0) {

  62. return list.get(arg0);

  63. }

  64. @Override

  65. public long getItemId(int arg0) {

  66. return 0;

  67. }

  68.  
  69. // 3.2生成view

  70. public View getView(int position, View view, ViewGroup group) {

  71. View v = null;

  72. // 3.2.1得到或者加载布局对象

  73. if (view == null) {

  74. v = LayoutInflater.from(MainActivity.this).inflate(

  75. R.layout.item, null);

  76. } else {

  77. v = view;

  78. }

  79. // 3.2.2得到相关控件

  80. TextView t1 = (TextView) v.findViewById(R.id.t1);

  81. TextView t2 = (TextView) v.findViewById(R.id.t2);

  82. TextView t3 = (TextView) v.findViewById(R.id.t3);

  83. // 3.2.3设置课件信息

  84. t1.setText(list.get(position).get("id"));

  85. t2.setText(list.get(position).get("name"));

  86. t3.setText(list.get(position).get("age"));

  87. return v; //返回该控件

  88. }

  89.  
  90. }

  91. // 4.在用户点击向数据库写入数据按钮

  92. public void add(View view) {

  93. final View v = LayoutInflater.from(this).inflate(R.layout.info, null);

  94. //配置对话框信息

  95. AlertDialog.Builder builder = new AlertDialog.Builder(this);

  96. builder.setTitle("添加信息")

  97. .setView(v)

  98. .setPositiveButton("提交", new OnClickListener() {

  99. @Override

  100. public void onClick(DialogInterface dialog, int which) {

  101. // 包含用户名 和 年龄

  102. EditText et_name = (EditText) v.findViewById(R.id.name);

  103. EditText et_age = (EditText) v.findViewById(R.id.age);

  104. String name = et_name.getText().toString();

  105. int age = Integer.parseInt(et_age.getText().toString());

  106. Uri uri = Uri.parse("content://com.baidu.provider/music");

  107. ContentValues values =new ContentValues();

  108. values.put("name", name);

  109. values.put("age", age);

  110. // 根据用户填入的信息,使用内容提供者,提交数据

  111. Uri u = getContentResolver().insert(uri, values);

  112. if(u != null){

  113. // 如果插入数据成功,则提醒loadermanager重新开始loader对象,根据指定的ID

  114. MainActivity.this.getLoaderManager().restartLoader(0, null, myLoader);

  115. Toast.makeText(MainActivity.this, "插入成功", 1).show();

  116. }else{

  117. Toast.makeText(MainActivity.this, "插入失败", 1).show();

  118. }

  119. }

  120. })

  121. .setNegativeButton("取消", null)

  122. .create()

  123. .show();

  124. }

  125. }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值