2.Loader相关类接口(1).对于每个Activity或者Fragment都可用
(2).提供异步加载数据
(3).监视数据资源,当内容改变时重新更新
(4).当配置改变时,自动重新连接最新的cursor,故不需要重新查询数据
3.简单使用Loaders(1).LoaderManager
对于每个activity或者fragment只存在一个与之相关的LoaderManager对象,该LoaderManager对象可以存在多个可供管理loader对象。
(2).LoaderManager.LoaderCallbacks
LoaderManager.LoaderCallbacks是个回掉接口,用于客户端与LoaderManager的交互,loader对象就是在其接口的onCreateLoader()方法中得到,在使用时需要覆盖其方法。
(3).CursorLoader
CursorLoader是AsyncTaskLoader的子类,通过它可以查询ContentResolver并返回一个Cursor对象,并使用该cursor对象在后台线程执行查询操作,以不至于会阻塞主线程,从一个内容提供者去异步加载数据是CursorLoader对象最大用处。
4.loader向下兼容(1).得到LoaderManager对象
[java] view plaincopy
//得到LoaderManager对象
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
// 返回一个new CursorLoader对象
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri uri = Uri.parse("content://com.baidu.provider/music");
return new CursorLoader(MainActivity.this, uri, null, null, null,
null);
}
2).onLoadFinished()
Called when a previously created loader has finished its load.
可以完成对Ui控件的更新,比如更新一个listView列表。一旦应用不在使用,将自动释放loader的数据,不需要使用close();
[java] view plaincopy
// 完成对UI主界面的更新
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if(cursor == null){
Toast.makeText(MainActivity.this, "失败", 1).show();
return;
}
//ui主界面更新相关操作
}
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
// 当检测到数据已经放手改变时,重启指定ID的loader
if(u != null){
MainActivity.this.getLoaderManager().restartLoader(0, null, myLoader);
Toast.makeText(MainActivity.this, "插入成功", 1).show();
}else{
Toast.makeText(MainActivity.this, "插入失败", 1).show();
}
5.应用(1)当前Activity继承FragmentActivity
(2).得到Loadermanager对象
[java] view plaincopy
public void load(View view) {
LoaderManager manager = this.getSupportLoaderManager();//注意,不同
manager.initLoader(0, null, myLoader);
}
(3).其余操作均不变,只不过导包时需要导入android.support.v4下的包
(1).需求
一个listView和一个按钮,点击按钮后使用内容提供者,往数据库中添加数据,同时达到listView动态更新的目的,但是listView回到第一个item,因为在cursor在restart的后,listview又重新设置了adapter,listview初始化后设置适配器可以避免该问题,可参考ListView数据动态更新一文。
(2).代码实现
[java] view plaincopy
public class MainActivity extends Activity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list);
// 1.得到LoaderManager对象
LoaderManager manager = this.getLoaderManager();
manager.initLoader(0, null, myLoader);
}
// 2.覆写LoaderCallbacks相关方法
private LoaderCallbacks<Cursor> myLoader = new LoaderCallbacks<Cursor>() {
// 2.1创建一个新的CursorLoader对象,携带游标
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri uri = Uri.parse("content://com.baidu.provider/music"); //内容提供者的uri信息
return new CursorLoader(MainActivity.this, uri, null, null, null,
null);
}
// 2.2加载完成后,更新UI信息
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if(cursor == null){
Toast.makeText(MainActivity.this, "失败", 1).show();
return;
}
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
// 2.2.1往指定的集合中写入读取到的数据
while (cursor.moveToNext()) {
Map<String, String> map = new HashMap<String, String>();
String id = cursor.getString(cursor.getColumnIndex("_id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String age = cursor.getString(cursor.getColumnIndex("age"));
map.put("id", id);
map.put("name", name);
map.put("age", age);
list.add(map);
}
// 2.2.2新建一个适配器对象
MyAdapter adapter = new MyAdapter();
adapter.setList(list); //设置集合
// 2.2.3为listView设置adapter,更新数据
listView.setAdapter(adapter);
// 2.2.4 设置适配器数据改变通知
adapter.notifyDataSetChanged();
}
public void onLoaderReset(Loader<Cursor> arg0) {
}
};
// 3.自定义适配器类
class MyAdapter extends BaseAdapter {
private List<Map<String, String>> list; //集合,存储数据
public void setList(List<Map<String, String>> list) {
this.list = list;
}
// 3.1得到列表数目,即为集合大小
public int getCount() {
return list.size();
}
public Object getItem(int arg0) {
return list.get(arg0);
}
@Override
public long getItemId(int arg0) {
return 0;
}
// 3.2生成view
public View getView(int position, View view, ViewGroup group) {
View v = null;
// 3.2.1得到或者加载布局对象
if (view == null) {
v = LayoutInflater.from(MainActivity.this).inflate(
R.layout.item, null);
} else {
v = view;
}
// 3.2.2得到相关控件
TextView t1 = (TextView) v.findViewById(R.id.t1);
TextView t2 = (TextView) v.findViewById(R.id.t2);
TextView t3 = (TextView) v.findViewById(R.id.t3);
// 3.2.3设置课件信息
t1.setText(list.get(position).get("id"));
t2.setText(list.get(position).get("name"));
t3.setText(list.get(position).get("age"));
return v; //返回该控件
}
}
// 4.在用户点击向数据库写入数据按钮
public void add(View view) {
final View v = LayoutInflater.from(this).inflate(R.layout.info, null);
//配置对话框信息
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("添加信息")
.setView(v)
.setPositiveButton("提交", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 包含用户名 和 年龄
EditText et_name = (EditText) v.findViewById(R.id.name);
EditText et_age = (EditText) v.findViewById(R.id.age);
String name = et_name.getText().toString();
int age = Integer.parseInt(et_age.getText().toString());
Uri uri = Uri.parse("content://com.baidu.provider/music");
ContentValues values =new ContentValues();
values.put("name", name);
values.put("age", age);
// 根据用户填入的信息,使用内容提供者,提交数据
Uri u = getContentResolver().insert(uri, values);
if(u != null){
// 如果插入数据成功,则提醒loadermanager重新开始loader对象,根据指定的ID
MainActivity.this.getLoaderManager().restartLoader(0, null, myLoader);
Toast.makeText(MainActivity.this, "插入成功", 1).show();
}else{
Toast.makeText(MainActivity.this, "插入失败", 1).show();
}
}
})
.setNegativeButton("取消", null)
.create()
.show();
}
}