Android 异步查询数据库
使用AsyncQueryHandler异步查询帮助类,可以实现数据库的增删改查(ContentProvidert提供的数据)。如果数据量较小的时候,使用一般的数据查询就可以实现。但是如果数据量较大,就会出现ANR(Application Not Responding)问题,这个时候也可以使用Handler,但是这样会降低效率,这个时候我们就可以使用Android已经封装好的异步查询框架AsyncQueryHandler。
AsyncQueryHandler内部实现:AsyncQueryHandler类封装了调用者线程与工作线程的交互过程。交互的主体是两个Handler,一个运行在调用者线程中,一个运行在工作者线程中。创建AsyncQueryHandler对象,并通过提供onXXXComplete的回调接口,实现事件的完成处理。
Android API中提供了四个方法:
startInsert:插入
startDelete:删除
startUpdate:更新
startQuery:查询
四种方法,并有响应的onXXXComplete()方法与之相对应.于之相对应的4个onXXXComplete()方法都是空实现,因此我们完成相应调用后进行后续其他的操作可以在onXXXComplete()方法中完成.
使用时直接调用startXXX方法即可。传入的通用参数如下:
参数名 | 含义 |
---|---|
token | 一个令牌,主要用来标识查询,保证唯一即可.需要跟onXXXComplete方法传入的一致。(当然你也可以不一致,同样在数据库的操作结束后会调用对应的onXXXComplete方法 ) |
cookie | 你想传给onXXXComplete方法使用的一个对象。(没有的话传递null即可) |
Uri uri | 进行查询的通用资源标志符 |
projection | 查询的列 |
selection | 限制条件 |
selectionArgs | 查询参数 |
orderBy | 排序条件 |
自定义一个关于本地数据库异步操作的类:
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import com.example.LLL.asyncsqlite.Logger;
import java.util.List;
/**
* 数据库异步框架
* Created by LLL on 2022/9/2.
*/
public class AsyncHandler extends Handler {
private static final String TAG = "MasAsyncQueryHandler";
public static final long SUCCESS = 1;
public static final long FAIL = -1;
private static final int EVENT_ARG_SINGLE_INSERT = 0;
private static final int EVENT_ARG_MULTI_INSERT = 1;
private static final int EVENT_ARG_QUERY = 2;
private static final int EVENT_ARG_UPDATE = 3;
private static final int EVENT_ARG_DELETE = 4;
private static final int EVENT_INIT_DATABASE = 5;
private static Looper sLooper = null;
private Handler mWorkerThreadHandler;
private IAsyncHandlerCallback mIAsyncHandlerCallback;
protected static class SqliteArgs {
public SQLiteDatabase db;
public String table;
public Handler handler;
public IAsyncHandlerCallback callback;
}
protected static final class InsertSingleArgs extends SqliteArgs {
public String nullColumnHack;
public ContentValues values;
public long result;
}
protected static final class InsertMultiArgs extends SqliteArgs {
public String nullColumnHack;
public List<ContentValues> valuesList;
public long result;
}
protected static final class QueryArgs extends SqliteArgs {
public boolean distinct;
public String[] columns;
public String whereClause;
public String[] whereArgs;
public String groupBy;
public String having;
public String orderBy;
public String limit;
public Cursor result;
}
protected static final class UpdateArgs extends SqliteArgs {
public ContentValues values;
public String whereClause;
public String[] whereArgs;
public long result;
}
protected static final class DeleteArgs extends SqliteArgs {
public String whereClause;
public String[] whereArgs;
public long result;
}
protected static final class InitArgs extends SqliteArgs {
public DataBase dbOpenHelper;
public SQLiteDatabase result;
}
public AsyncHandler() {
super();
synchronized (AsyncHandler.class) {
if (sLooper == null) {
HandlerThread thread = new HandlerThread(TAG);
thread.start();
sLooper = thread.getLooper();
}
}
mWorkerThreadHandler = new WorkerHandler(sLooper);
}
/**
* 初始化数据库
*
* @param token 插入数据库标识
* @param dbOpenHelper 数据库
*/
public void initDataBase(int token, DataBase dbOpenHelper, IInitDatabaseCallback callback) {
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_INIT_DATABASE;
InitArgs args = new InitArgs();
args.handler = this;
args.dbOpenHelper = dbOpenHelper;
args.callback = callback;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* 单条插入数据库
*
* @param token 插入数据库标识
* @param db 数据库对象
* @param table 数据库表名
* @param nullColumnHack 当values为空时设置的空列数据
* @param values 插入数据库内容
*/
public void startSingleInsert(int token, SQLiteDatabase db, String table, String nullColumnHack, ContentValues values, ISingleInsertCallback callback) {
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_SINGLE_INSERT;
InsertSingleArgs args = new InsertSingleArgs();
args.handler = this;
args.db = db;
args.table = table;
args.nullColumnHack = nullColumnHack;
args.values = values;
args.callback = callback;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* 多条插入数据库
*
* @param token 插入数据库标识
* @param db 数据库对象
* @param table 数据库表名
* @param nullColumnHack 当values为空时设置的空列数据
* @param valuesList 插入数据库内容
*/
public void startMultiInsert(int token, SQLiteDatabase db, String table, String nullColumnHack, List<ContentValues> valuesList, IMultiInsertCallback callback) {
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_MULTI_INSERT;
InsertMultiArgs args = new InsertMultiArgs();
args.handler = this;
args.db = db;
args.table = table;
args.nullColumnHack = nullColumnHack;
args.valuesList = valuesList;
args.callback = callback;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* 查询数据库
*
* @param token 插入数据库标识
* @param db 数据库对象
* @param table 数据库表名
* @param distinct 是否去除重复项
* @param columns 查询的列数组
* @param whereClause 条件
* @param whereArgs 条件参数数组
* @param groupBy 分组依据
* @param having 过滤
* @param orderBy 排序
* @param limit 限制条数
*/
public void startQuery(int token, SQLiteDatabase db, boolean distinct, String table, String[] columns, String whereClause, String[] whereArgs,
String groupBy, String having, String orderBy, String limit, IQueryCallback callback) {
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_QUERY;
QueryArgs args = new QueryArgs();
args.handler = this;
args.db = db;
args.distinct = distinct;
args.table = table;
args.columns = columns;
args.whereClause = whereClause;
args.whereArgs = whereArgs;
args.groupBy = groupBy;
args.having = having;
args.orderBy = orderBy;
args.limit = limit;
args.callback = callback;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* 更新数据库
*
* @param token 插入数据库标识
* @param db 数据库对象
* @param table 数据库表名
* @param values 更新的内容
* @param whereClause 条件
* @param whereArgs 条件参数数组
*/
public void startUpdate(int token, SQLiteDatabase db, String table, ContentValues values, String whereClause, String[] whereArgs, IUpdateCallback callback) {
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_UPDATE;
UpdateArgs args = new UpdateArgs();
args.handler = this;
args.db = db;
args.table = table;
args.values = values;
args.whereClause = whereClause;
args.whereArgs = whereArgs;
args.callback = callback;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* 删除数据库某条
*
* @param token 插入数据库标识
* @param db 数据库对象
* @param table 数据库表名
* @param whereClause 条件
* @param whereArgs 条件参数数组
*/
public void startDelete(int token, SQLiteDatabase db, String table, String whereClause, String[] whereArgs, IDeleteCallback callback) {
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_DELETE;
DeleteArgs args = new DeleteArgs();
args.handler = this;
args.db = db;
args.table = table;
args.whereClause = whereClause;
args.whereArgs = whereArgs;
args.callback = callback;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
/**
* 数据库处理
*/
protected class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int token = msg.what;
int event = msg.arg1;
InsertSingleArgs insertSingleArgs;
InsertMultiArgs insertMultiArgs;
QueryArgs queryArgs;
UpdateArgs updateArgs;
DeleteArgs deleteArgs;
InitArgs initArgs;
Message reply;
switch (event) {
case EVENT_ARG_SINGLE_INSERT:
insertSingleArgs = (InsertSingleArgs) msg.obj;
insertSingleArgs.result = insertSingleArgs.db.insertOrThrow(insertSingleArgs.table,
insertSingleArgs.nullColumnHack, insertSingleArgs.values);
if ((int) insertSingleArgs.result == -1) {
Logger.e(TAG + " ---->> insert single args failed!");
insertSingleArgs.result = FAIL;
} else {
insertSingleArgs.result = SUCCESS;
}
reply = insertSingleArgs.handler.obtainMessage(token);
reply.obj = insertSingleArgs;
break;
case EVENT_ARG_MULTI_INSERT:
insertMultiArgs = (InsertMultiArgs) msg.obj;
insertMultiArgs.db.beginTransaction();
for (ContentValues values : insertMultiArgs.valuesList) {
insertMultiArgs.result = insertMultiArgs.db.insertOrThrow(insertMultiArgs.table,
insertMultiArgs.nullColumnHack, values);
if ((int) insertMultiArgs.result == -1) {
Logger.e(TAG + " ---->> insert multi args failed!");
insertMultiArgs.result = FAIL;
break;
} else {
insertMultiArgs.result = SUCCESS;
}
}
insertMultiArgs.db.setTransactionSuccessful();
insertMultiArgs.db.endTransaction();
reply = insertMultiArgs.handler.obtainMessage(token);
reply.obj = insertMultiArgs;
break;
case EVENT_ARG_QUERY:
queryArgs = (QueryArgs) msg.obj;
Cursor cursor;
try {
cursor = queryArgs.db.query(queryArgs.distinct, queryArgs.table,
queryArgs.columns, queryArgs.whereClause, queryArgs.whereArgs,
queryArgs.groupBy, queryArgs.having, queryArgs.orderBy, queryArgs.limit);
// 调用这个方法会使得主线程小小的加速,此处先遍历cursor,之后在主线程中去遍历取值时会加速,好像是这样的
if (cursor != null) {
cursor.getCount();
}
} catch (Exception e) {
Logger.e(TAG + " ---->> Exception thrown during handling EVENT_ARG_QUERY", e);
cursor = null;
}
queryArgs.result = cursor;
reply = queryArgs.handler.obtainMessage(token);
reply.obj = queryArgs;
break;
case EVENT_ARG_UPDATE:
updateArgs = (UpdateArgs) msg.obj;
updateArgs.result = updateArgs.db.update(updateArgs.table, updateArgs.values, updateArgs.whereClause, updateArgs.whereArgs);
if ((int) updateArgs.result <= 0) {
Logger.e(TAG + " ---->> update args failed!");
updateArgs.result = FAIL;
} else {
updateArgs.result = SUCCESS;
}
reply = updateArgs.handler.obtainMessage(token);
reply.obj = updateArgs;
break;
case EVENT_ARG_DELETE:
deleteArgs = (DeleteArgs) msg.obj;
deleteArgs.result = deleteArgs.db.delete(deleteArgs.table, deleteArgs.whereClause, deleteArgs.whereArgs);
if ((int) deleteArgs.result <= 0) {
Logger.e(TAG + " ---->> delete args failed!");
deleteArgs.result = FAIL;
} else {
deleteArgs.result = SUCCESS;
}
reply = deleteArgs.handler.obtainMessage(token);
reply.obj = deleteArgs;
break;
case EVENT_INIT_DATABASE:
initArgs = (InitArgs) msg.obj;
initArgs.result = initArgs.dbOpenHelper.getWritableDatabase();
reply = initArgs.handler.obtainMessage(token);
reply.obj = initArgs;
break;
default:
return;
}
reply.arg1 = msg.arg1;
reply.sendToTarget();
}
}
/**
* 数据库处理结果回调
*/
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int token = msg.what;
int event = msg.arg1;
switch (event) {
case EVENT_ARG_SINGLE_INSERT:
InsertSingleArgs insertSingleArgs = (InsertSingleArgs) msg.obj;
if (insertSingleArgs.callback != null) {
if (insertSingleArgs.result == SUCCESS) {
((ISingleInsertCallback) insertSingleArgs.callback).onSingleInsertComplete(token, insertSingleArgs.result);
} else {
insertSingleArgs.callback.onAsyncOperateFailed();
}
}
break;
case EVENT_ARG_MULTI_INSERT:
InsertMultiArgs insertMultiArgs = (InsertMultiArgs) msg.obj;
if (insertMultiArgs.callback != null) {
if (insertMultiArgs.result ==SUCCESS) {
((IMultiInsertCallback) insertMultiArgs.callback).onMultiInsertComplete(token, insertMultiArgs.result);
} else {
insertMultiArgs.callback.onAsyncOperateFailed();
}
}
break;
case EVENT_ARG_QUERY:
QueryArgs queryArgs = (QueryArgs) msg.obj;
if (queryArgs.callback != null) {
if (queryArgs.result != null) {
((IQueryCallback) queryArgs.callback).onQueryComplete(token, queryArgs.result);
} else {
queryArgs.callback.onAsyncOperateFailed();
}
}
break;
case EVENT_ARG_UPDATE:
UpdateArgs updateArgs = (UpdateArgs) msg.obj;
if (updateArgs.callback != null) {
if (updateArgs.result == SUCCESS) {
((IUpdateCallback) updateArgs.callback).onUpdateComplete(token, updateArgs.result);
} else {
updateArgs.callback.onAsyncOperateFailed();
}
}
break;
case EVENT_ARG_DELETE:
DeleteArgs deleteArgs = (DeleteArgs) msg.obj;
if (deleteArgs.callback != null) {
if (deleteArgs.result == SUCCESS) {
((IDeleteCallback) deleteArgs.callback).onDeleteComplete(token, deleteArgs.result);
} else {
deleteArgs.callback.onAsyncOperateFailed();
}
}
break;
case EVENT_INIT_DATABASE:
InitArgs initArgs = (InitArgs) msg.obj;
if (initArgs.callback != null) {
if (initArgs.result != null) {
((IInitDatabaseCallback) initArgs.callback).onInitDatabaseComplete(token, initArgs.result);
} else {
initArgs.callback.onAsyncOperateFailed();
}
}
break;
default:
return;
}
}
}
上面是主要的异步类,主要是先通过一个Handler去操作数据库,然后用另一个Handler去回调给调用者,注意其中的Looper不是主线程的消息队列,下面是异步操作的回调,用于通知发起数据库操作的地方这次数据库操作的结果:
/**
* 数据库异步操作结果回调基类
* Created by LLL on 2022/9/2.
*/
public interface IAsyncHandlerCallback {
void onAsyncOperateFailed();
}
public interface IInitDatabaseCallback extends IAsyncHandlerCallback {
/**
* 初始化成功
*/
void onInitDatabaseComplete(int token, SQLiteDatabase db);
}
public interface ISingleInsertCallback extends IAsyncHandlerCallback {
/**
* 单条插入成功
*/
void onSingleInsertComplete(int token, long result);
}
public interface IMultiInsertCallback extends IAsyncHandlerCallback {
/**
* 多条插入成功
*/
void onMultiInsertComplete(int token, long result);
}
public interface IQueryCallback extends IAsyncHandlerCallback{
/**
* 查询成功
*/
void onQueryComplete(int token, Cursor cursor);
}
public interface IUpdateCallback extends IAsyncHandlerCallback {
/**
* 更新成功
*/
void onUpdateComplete(int token, long result);
}
public interface IDeleteCallback extends IAsyncHandlerCallback {
/**
* 删除成功
*/
void onDeleteComplete(int token, long result);
}