AndroidのLoaderManager管理Loader实现异步动态加载数据

来源:互联网 发布:sql pivot 用法 编辑:程序博客网 时间:2024/05/16 07:30

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对象

[java] view plaincopy
  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 等参数信息

[java] view plaincopy
  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, nullnullnull,  
  5.             null);  
  6. }  

2).onLoadFinished()

Called when a previously created loader has finished its load.

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

[java] view plaincopy
  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数据动态更新

[java] view plaincopy
  1. // 当检测到数据已经放手改变时,重启指定ID的loader  
  2. if(u != null){  
  3.     MainActivity.this.getLoaderManager().restartLoader(0null, 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对象

[java] view plaincopy
  1. public void load(View view) {  
  2.     LoaderManager manager = this.getSupportLoaderManager();//注意,不同  
  3.     manager.initLoader(0null, myLoader);  
  4. }  

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

 5.应用

(1).需求

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

(2).代码实现

[java] view plaincopy
  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(0null, 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, nullnullnull,  
  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(0null, 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 0
原创粉丝点击