使用CursorLoader异步加载SQLite数据
完整源码下载:http://download.csdn.net/detail/q296264785/9686676
设及到的知识点:
1、对SQLite数据的操作。
关于SQLite的使用:http://blog.csdn.net/q296264785/article/details/53155739
2、CursorLoader加载器异步加载数据
同步加载数据的方法:http://blog.csdn.net/q296264785/article/details/53167961
3、内容提供者ContentProvider
内容提供者详解:http://blog.csdn.net/q296264785/article/details/53158873
使用loaders的应用应该包含以下内容:
1、一个Activity或者Fragment。
2、一个LoaderManager的实例。
3、一个CursorLoader来载入被ContentProvider返回的数据。 或者,你可以实现自己的Loader或者AsyncTaskLoader的子类 从而从其他的资源加载数据
LoaderManager.LoaderCallbacks的一个实现 这是你创建新的loader和管理你的已经存在的loader的引用的地方
4、一个展示loader的数据的方法,比如一个SimpleCursorAdapter。
5、一个数据源,比如一个ContentProvider,当你使用一个 CursorLoader的时候。
使用CursorLoader加载器异步加载数据的好处是避免同步查询数据库时阻塞UI线程,通过使用观察者设计模式来告诉使用者(监听者)加载数据的改变来实现实时更新。
演示效果:Button会将两个输入框的数据通过内容提供者存到数据库文件并且动态更新在ListView中
1、创建过程class_cursorloader_contentprovider_test,选择3.0以上版本,因为加载器的功能是API11更新的。
新建3个类:
a、DBHelper 继承 SQLiteOpenHelper,创建数据库用。
b、MProvider 继承 ContentProvider,操作内容提供者用。
c、test 继承 AndroidTestCase,单元测试–调试并且给数据库添加数据使用,记得在清单文件中添加单元测试功能。
数据库的创建和ContentProvider前面有博文已经介绍过,本博文只贴源码,重点介绍异步加载器的使用。
首先需要创建一个数据库,来为Listview提供数据。我创建了一个包含 _pid,name,number 三类的class表格。并且使用单元测试的方法给表class加载了几条数据。
数据库创建类源码:
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, "mydb.db", null, 1);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String sql = "create table class(_pid integer primary key autoincrement,name varchar(64),number varchar(64))";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
单元测试源码:
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.test.AndroidTestCase;
public class test extends AndroidTestCase {
public void create() {
DBHelper dbHelper = new DBHelper(getContext());
SQLiteDatabase database = dbHelper.getReadableDatabase();
ContentValues values = new ContentValues();
values.put("name", "张利利");
values.put("number", "12345");
database.insert("class", null, values);
values.put("name", "李提莫");
values.put("number", "12345");
database.insert("class", null, values);
values.put("name", "王石说");
values.put("number", "12345");
database.insert("class", null, values);
values.put("name", "赵六壳");
values.put("number", "12345");
database.insert("class", null, values);
values.put("name", "郭撒大");
values.put("number", "12345");
database.insert("class", null, values);
values.put("name", "刘䮻明");
values.put("number", "12345");
database.insert("class", null, values);
}
}
解决了数据来源的问题,接下来我们需要创建一个ContentProvider的子类,用来实现对数据库数据的修改操作,本列只需要用到数据库的查找和增加操作,所以只重编写查找以及新增数据的方法。在该类中我们注册了一个监听者,监听者的作用就是当数据有变化时监听者会将信息反馈给调用监听者的对象。
cursor.setNotificationUri(contentResolver, uri);//注册监听
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
public class MProvider extends ContentProvider {
private DBHelper dbHelper;
private ContentResolver contentResolver;
private static String str_Uri = "com.example.class_cursorloader_contentprovider_test.MProvider";
private static final UriMatcher MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
static {
MATCHER.addURI(str_Uri, "class", 1);
MATCHER.addURI(str_Uri, "class/#", 2);
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
dbHelper = new DBHelper(getContext());
contentResolver = getContext().getContentResolver();
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
Cursor cursor = null;
SQLiteDatabase sqLiteDatabase = dbHelper.getReadableDatabase();
switch (MATCHER.match(uri)) {
case 1:// 为1时代表查找全部
cursor = sqLiteDatabase.query("class", projection, selection,
selectionArgs, null, null, sortOrder);
break;
case 2:
long id = ContentUris.parseId(uri);// 截取获取uri的“id”
String str = "_pid = " + id;
if (selection != null && !selection.equals("")) {
str += selection;
}
cursor = sqLiteDatabase.query("class", projection, str,
selectionArgs, null, null, sortOrder);
break;
}
cursor.setNotificationUri(contentResolver, uri);//注册监听
return cursor;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
switch (MATCHER.match(uri)) {
case 1:
return "vnd.android.cursor.dir/class";// 多行操作
case 2:
return "vnd.android.cursor.item/class";// 单行操作
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
Uri uri2 = null;
switch (MATCHER.match(uri)) {
case 1:
SQLiteDatabase sqLiteDatabase = dbHelper.getReadableDatabase();
long id = sqLiteDatabase.insert("class", null, values);
uri2 = ContentUris.withAppendedId(uri, id); // 重组uri
break;
}
contentResolver.notifyChange(uri, null);// 通知监听者数据改变
return uri2;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
}
在MainActivity类中,我要MainActivity 类实现LoaderCallbacks并且返回一个游标参数。为了在listView显示数据还需要一个适配器,我们自定义一个适配器myAdapter继承BaseAdapter,并且为该适配器编写一个XML布局文件,用来实现对Class表格中三列的显示。
MainActivity类
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {
private myAdapter adapter;
private ListView listView;
private LoaderManager loaderManager;
private EditText editText1;
private EditText editText2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loaderManager = getLoaderManager();
listView = (ListView) findViewById(R.id.listview1);
editText1 = (EditText) findViewById(R.id.editText1);// 工号
editText2 = (EditText) findViewById(R.id.editText2);// 名字
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Uri uri = Uri
.parse("content://com.example.class_cursorloader_contentprovider_test.MProvider/class");
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("name", editText2.getText().toString());
values.put("number", editText1.getText().toString());
contentResolver.insert(uri, values);//按键操作,将两个EditText中的数据传递给内容提供者保存到数据库
loaderManager.restartLoader(1111, null, MainActivity.this);
}
});
loaderManager.initLoader(1111, null, this);
}
@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;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// TODO Auto-generated method stub
CursorLoader loader = new CursorLoader(this);
Uri uri = Uri
.parse("content://com.example.class_cursorloader_contentprovider_test.MProvider/class");
loader.setUri(uri);
return loader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// TODO Auto-generated method stub
List<List<String>> list = new ArrayList<List<String>>();
while (data.moveToNext()) {
List<String> data_list = new ArrayList<String>();
data_list.add(data.getString(data.getColumnIndex("_pid")));
data_list.add(data.getString(data.getColumnIndex("name")));
data_list.add(data.getString(data.getColumnIndex("number")));
list.add(data_list);
}
adapter = new myAdapter(list);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();// 通知数据有更新
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// TODO Auto-generated method stub
}
//自定义适配器
class myAdapter extends BaseAdapter {
private List<List<String>> list;
public myAdapter(List<List<String>> list) {
// TODO Auto-generated constructor stub
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
View view = null;
if (convertView == null) {
view = LayoutInflater.from(MainActivity.this).inflate(
R.layout.list, null);
} else {
view = convertView;
}
TextView textView1 = (TextView) view
.findViewById(R.id.list_textView1);
TextView textView2 = (TextView) view
.findViewById(R.id.list_textView2);
TextView textView3 = (TextView) view
.findViewById(R.id.list_textView3);
List<String> list1 = new ArrayList<String>();
list1 = list.get(position);
textView1.setText(list1.get(0));
textView2.setText(list1.get(1));
textView3.setText(list1.get(2));
return view;
}
}
}