在UI的主线程中异步加载数据库,使得页面比较流畅,以防止查询数据库的记录比较多或者提取数据库记录使用的时间太长会操作UI主线程的阻塞,从而造成相应异常。Loader不能用于增删改,只能用于数据库的查询操作,可以解决阻塞UI主线程的问题。
整体思路:创建一个继承SQLiteOpenHelper的DBHelper类,在·这个类中声明一个数据库名称和版本号码,在onCreate方法中创建数据库表并执行,在onUpgrade方法中暂时不预处理。创建一个继承ContentProvider的StudentContentProvider类,在这个类中定义内容提供者的增删改查操作。在xml文件中定义一个ListView控件,在activity中声明一个LoaderManager对象,定义一个MyAdapter类,然后声明一个MyAdapter对象,定义一个LoaderManager.LoaderCallbacks<Cursor>匿名内部类对象,并在onCreate方法中实例化这个LoaderManager对象,将匿名内部类对象与这个对象关联,绑定listview。重写onMenuItemSelected这个方法,在这个方法中设置点击各个item弹出的删除和添加的操作,在这两个操作中都需要用到内容解析者来调用增删改查方法操作数据,操作完成后要使用Loader重新查询数据,即进行数据的更新,其中增加操作需要使用一个自定义对话框,用于输入添加的文字信息,这个自定义对话框自然也对应一个自定义的xml文件。另外还定义了一个继承AndroidTestCase的MyTest测试单元,在这个测试单元中定义增删改查操作完成对数据库操作的测试。注意:在清单文件AndroidManifest.xml文件中注册provider和测试单元。
activity_main.xml文件:
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
</ListView>
add.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名:" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10" />
</LinearLayout>
DBHelper.java文件:
public class DBHelper extends SQLiteOpenHelper {
private static String name="mydb.db";
private static int version=1;
public DBHelper(Context context) {
super(context, name, null, version);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase database) {
// TODO Auto-generated method stub
// 在数据库中创建一张表,有主键stuid(自增长)、name
String sql="create table student (stuid integer primary key autoincrement,name varchar(64))";
database.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
}
}
StudentContentProvider.java文件:
public class StudentContentProvider extends ContentProvider {
private final static UriMatcher URI_MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
private final static int STUDENT = 1;
private final static int STUDENTS = 2;
private DBHelper helper;
// 添加两条匹配规则
static {
URI_MATCHER.addURI(
"com.example.android_loader_manager.StudentContentProvider",
"student", STUDENTS);
URI_MATCHER.addURI(
"com.example.android_loader_manager.StudentContentProvider",
"student/#", STUDENT);
}
public StudentContentProvider() {
// TODO Auto-generated constructor stub
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
int count=0;//表示影响数据库的行数
int flag=URI_MATCHER.match(uri);
SQLiteDatabase database =helper.getWritableDatabase();
switch (flag) {
case STUDENT:
long stuid=ContentUris.parseId(uri);
String where_value=" stuid= "+stuid;
if(selection!=null&&!selection.equals("")){
where_value+=selection;
}
count=database.delete("student", where_value, selectionArgs);
break;
case STUDENTS:
count=database.delete("student", selection, selectionArgs);
break;
}
return count;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
int flag=URI_MATCHER.match(uri);
switch (flag) {
case STUDENT:
return "vnd.android.cursor.item/student";
case STUDENTS:
return "vnd.android.cursor.dir/students";
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
// TODO Auto-generated method stub
int flag=URI_MATCHER.match(uri);
SQLiteDatabase database=helper.getWritableDatabase();
Uri uri2=null;
switch (flag) {
case STUDENTS:
//id就是插入该行的id的值
long id=database.insert("student", null, contentValues);
uri2=ContentUris.withAppendedId(uri, id);
break;
}
System.out.println("-->>"+uri2.toString());
return uri2;
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
helper=new DBHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// TODO Auto-generated method stub
Cursor cursor=null;
int flag=URI_MATCHER.match(uri);
SQLiteDatabase database=helper.getReadableDatabase();
switch (flag) {
case STUDENT:
long stuid=ContentUris.parseId(uri);
String where_value=" stuid= "+stuid;
if(selection!=null&&!"".equals(selection)){
where_value+=selection;
}
cursor=database.query("student", projection, where_value, selectionArgs, null, null, null);
break;
case STUDENTS:
cursor=database.query("student", projection, selection, selectionArgs, null, null, null);
break;
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
int count=0;
int flag=URI_MATCHER.match(uri);
SQLiteDatabase database=helper.getWritableDatabase();
switch (flag) {
case STUDENT:
long stuid=ContentUris.parseId(uri);
String where_value=" stuid = "+stuid;
if (selection!=null&&!selection.equals("")) {
where_value+=selection;
}
count=database.update("student", values, where_value, selectionArgs);
break;
case STUDENTS:
count=database.update("student", values, selection, selectionArgs);
break;
}
return count;
}
}
MyTest.java文件:
public class MyTest extends AndroidTestCase {
public MyTest() {
// TODO Auto-generated constructor stub
}
public void add() {
// 定义一个内容解析者
ContentResolver contentResolver = getContext().getContentResolver();
ContentValues values = new ContentValues();
values.put("name", "rose");
Uri uri = Uri
.parse("content://com.example.android_loader_manager.StudentContentProvider/student");
contentResolver.insert(uri, values);
}
public void delete() {
// 定义一个内容解析者
ContentResolver contentResolver = getContext().getContentResolver();
Uri uri = Uri
.parse("content://com.example.android_loader_manager.StudentContentProvider/student/1");
int count=contentResolver.delete(uri, null, null);//影响数据库的行数
System.out.println("--count-->"+count);
}
public void query() {
// 定义一个内容解析者
ContentResolver contentResolver = getContext().getContentResolver();
Uri uri = Uri
.parse("content://com.example.android_loader_manager.StudentContentProvider/student");
// 没有这句话是查询所有记录,有这句话是查询id为2的一条记录
Uri uri2=ContentUris.withAppendedId(uri, 2);
Cursor cursor=contentResolver.query(uri2, null, null, null, null);
while (cursor.moveToNext()) {
System.out.println("-->>"+cursor.getString(cursor.getColumnIndex("name")));
}
}
}
MainActivity.java文件:
public class MainActivity extends Activity {
private LoaderManager manager;
private ListView listview;
private MyAdapter adapter=null;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = getLoaderManager();// 加载LoaderManager完成异步加载数据的操作
manager.initLoader(1000, null, callbacks);
listview=(ListView)findViewById(R.id.listView1);
adapter=new MyAdapter(MainActivity.this);
registerForContextMenu(listview);
}
// 处理上下文菜单
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
getMenuInflater().inflate(R.menu.main, menu);
super.onCreateContextMenu(menu, v, menuInfo);
}
@SuppressLint("NewApi")
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
// TODO Auto-generated method stub
AdapterContextMenuInfo info=(AdapterContextMenuInfo)item.getMenuInfo();
switch (item.getItemId()) {
case R.id.del:
// Toast.makeText(MainActivity.this, "del", 1).show();
int position=info.position;
String name=adapter.getItem(position).toString();
Uri uri = Uri
.parse("content://com.example.android_loader_manager.StudentContentProvider/student");
ContentResolver contentResolver=getContentResolver();
// count表示删除后影响数据库的行数
int count=contentResolver.delete(uri, " name=? ", new String[]{name});
if(count>0){
// 相当于重新查询数据库
manager.restartLoader(1000, null, callbacks);
}
break;
case R.id.add:
// 添加自定义对话框,完成用户的数据录入
// Toast.makeText(MainActivity.this, "add", 1).show();
final Dialog dialog=createAddDialog(MainActivity.this);
Button button=(Button)dialog.findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@SuppressLint("NewApi")
@Override
public void onClick(View arg0) {
EditText editText=(EditText)dialog.findViewById(R.id.editText1);
//trim()表示去掉前后空格
String name=editText.getText().toString().trim();
ContentResolver contentResolver=getContentResolver();
Uri uri = Uri
.parse("content://com.example.android_loader_manager.StudentContentProvider/student");
ContentValues values=new ContentValues();
values.put("name", name);
Uri result_uri=contentResolver.insert(uri, values);
if(result_uri!=null){//不为空表示插入成功了
// 重新加载数据
manager.restartLoader(1000, null, callbacks);
dialog.dismiss();
}
}
});
dialog.show();
break;
}
return super.onMenuItemSelected(featureId, item);
}
public Dialog createAddDialog(Context context){
Dialog dialog=new Dialog(context);
dialog.setContentView(R.layout.add);
return dialog;
}
public class MyAdapter extends BaseAdapter{
private List<String> list=null;
private Context context;
public MyAdapter(Context context){
this.context=context;
}
public void setList(List<String> list){
this.list=list;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
TextView view=null;
if(convertView==null){
view=new TextView(context);//context是上下文对象
}else{
view=(TextView)convertView;
}
view.setText(list.get(position).toString());
return view;
}
}
// callbacks是一个匿名内部类
private LoaderManager.LoaderCallbacks<Cursor> callbacks = new LoaderCallbacks<Cursor>() {
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
}
// 完成对UI的数据提取,更新UI的操作
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
// TODO Auto-generated method stub
// 把数据提取出来,放到适配器中完成对UI的更新操作
List<String> list=new ArrayList<String>();
while (cursor.moveToNext()) {
String name=cursor.getString(cursor.getColumnIndex("name"));
list.add(name);
}
adapter.setList(list);
listview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
@SuppressLint("NewApi")
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
// TODO Auto-generated method stub
// 第一种方式
// CursorLoader loader=new CursorLoader(MainActivity.this);
// Uri uri = Uri
// .parse("content://com.example.android_loader_manager.StudentContentProvider/student");
// loader.setUri(uri);
// // API提供的设置loader的方法
// // loader.setProjection(projection);
// // loader.setSelection(selection);
// // loader.setSelectionArgs(selectionArgs);
// // loader.setSortOrder(sortOrder);
Uri uri = Uri
.parse("content://com.example.android_loader_manager.StudentContentProvider/student");
CursorLoader loader = new CursorLoader(MainActivity.this, uri,
null, null, null, null);
return loader;
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}