Android异步任务和SQLite数据库实例
我有一个问题,我不知道如何解决它。我的应用程序中的一个活动有多个Android异步任务和SQLite数据库实例,android,sqlite,android-asynctask,sqliteopenhelper,Android,Sqlite,Android Asynctask,Sqliteopenhelper,我有一个问题,我不知道如何解决它。我的应用程序中的一个活动有多个AsyncTasks,它们访问单个SQLiteOpenHelper。我在onCreate()中初始化并打开帮助程序,并在onStop()中关闭它。我还检查它是否已在onResume()中初始化 由于我发布了我的应用程序,我在尝试访问DB helper的doInBackground中收到了大量带有Null异常的错误。我知道这是因为数据库在调用doInBackground之前关闭(onStop()) 我的问题是,我应该在哪里关闭DB连接
AsyncTask
s,它们访问单个SQLiteOpenHelper
。我在onCreate()
中初始化并打开帮助程序,并在onStop()
中关闭它。我还检查它是否已在onResume()
中初始化
由于我发布了我的应用程序,我在尝试访问DB helper的doInBackground
中收到了大量带有Null异常的错误。我知道这是因为数据库在调用doInBackground
之前关闭(onStop()
)
我的问题是,我应该在哪里关闭DB连接?在活动中使用DB helper的单个实例并从多个线程(AsyncTasks
)访问它是否正确?或者我应该为每个AsyncTask
这是我活动的简化框架:
public class MyActivity extends Activity{
private DbHelper mDbHelper;
private ArrayList<ExampleObject> objects;
@Override
public void onStop(){
super.onStop();
if(mDbHelper != null){
mDbHelper.close();
mDbHelper = null;
}
}
@Override
public void onResume(){
super.onResume();
if(mDbHelper == null){
mDbHelper = new DbHelper(this);
mDbHelper.open();
}
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
DbHelper mDbHelper = new DbHelper(this);
mDbHelper.open();
}
private class DoSomething extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... arg0) {
objects = mDbHelper.getMyExampleObjects();
return null;
}
@Override
protected void onPostExecute(final Void unused){
//update UI with my objects
}
}
private class DoSomethingElse extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... arg0) {
objects = mDbHelper.getSortedObjects();
return null;
}
@Override
protected void onPostExecute(final Void unused){
//update UI with my objects
}
}
}
公共类MyActivity扩展活动{
私人助理医生;
私有ArrayList对象;
@凌驾
公共void onStop(){
super.onStop();
如果(mDbHelper!=null){
mDbHelper.close();
mDbHelper=null;
}
}
@凌驾
恢复时公开作废(){
super.onResume();
如果(mDbHelper==null){
mDbHelper=新的DbHelper(此);
mDbHelper.open();
}
}
@凌驾
创建(捆绑冰柱)时的公共空间{
超级冰柱;
DbHelper mDbHelper=新的DbHelper(this);
mDbHelper.open();
}
私有类DoSomething扩展了异步任务{
@凌驾
受保护的Void doInBackground(字符串…arg0){
objects=mDbHelper.getMyExampleObjects();
返回null;
}
@凌驾
后期执行时受保护的无效(最终无效未使用){
//用我的对象更新UI
}
}
私有类DoSomethingElse扩展异步任务{
@凌驾
受保护的Void doInBackground(字符串…arg0){
objects=mDbHelper.getSortedObjects();
返回null;
}
@凌驾
后期执行时受保护的无效(最终无效未使用){
//用我的对象更新UI
}
}
}
最好使用一个DB助手。
问题是,当用户离开活动时,DB
关闭,但AsyncTask
仍可能运行。因此,当您尝试访问DB
时,您应该检查它是否不为null,如果它为null
,这可能意味着您的活动
已被销毁,并且取消了该任务。您不需要为每个活动管理DB连接。您可以在android.app.Application的实例中执行此操作,并使用此实例访问数据库。
大概是这样的:
public class MyApplication extends Application {
// Synchronized because it's possible to get a race condition here
// if db is accessed from different threads. This synchronization can be optimized
// thought I wander if it's necessary
public synchronized static SQLiteDatabase db() {
if(self().mDbOpenHelper == null) {
self().mDbOpenHelper = new MyDbOpenHelper();
}
return self().mDbOpenHelper.getWritableDatabase();
}
public static Context context() {
return self();
}
@Override
public void onCreate() {
super.onCreate();
mSelf = this;
}
private static MyApplication self() {
if (self == null) throw new IllegalStateException();
return mSelf;
}
private MyDbOpenHelper mDbOpenHelper;
private static MyApplication mSelf;
}
通过这种方式,您可以确保您的数据库始终是可访问的
是的,拥有一个Db helper实例是一个很好的实践。默认情况下为您进行线程同步。您提到在关闭数据库之前取消异步任务。但是您应该记住,取消AsyncTask只是通知要取消的任务,您需要在doInBackground()中检查isCancelled(),并执行必要的操作来停止DB操作
在关闭数据库之前,您需要检查getStatus()以确保AsyncTask已停止。感谢您的快速响应。我忘了提到,我也有少数例外,如“由于未完成的声明而无法关闭”。这可能意味着当查询在doInBackground()中执行时,我试图在onStop()中关闭DB连接。在关闭数据库之前,我取消了AsyncTask,但仍然出现此错误。知道为什么会这样吗?@Ovidiu你通常把数据库初始化和清理代码放在哪里?(假设有一个DBHelper被多个视图访问)。正如@boulder所说,将其保存在应用程序+1中可能是一个很好的做法-这非常有趣,我将对此进行研究-谢谢!还有一个问题…你会在哪里关闭数据库连接?我不会关闭它。不知道这是否真的有必要。如果你能找到更多的细节,请分享,这很有趣。我想我从来没有用这种方法解决过任何问题。谢谢你让贝克来找我。我将尝试进一步研究这一点“此方法用于模拟流程环境。它永远不会在生产Android设备上调用,在生产Android设备上,通过简单地杀死流程来删除流程;这样做时不会执行任何用户代码(包括此回调)。”从API文档中可以看出,基本上我应该在(!isCancelled){在doInBackground中执行循环内的所有计算?是的,并检查主线程中的getStatus(),以确保异步任务已结束。好的,但如果我在onStop()中检查它,但它尚未结束,该怎么办?那么我在哪里关闭DB连接呢?对于异步任务,建议您在发出取消信号时尽早退出doInBackground。因此,在doInBackground中的while循环中,每当您要执行DB语句时,检查isCancelled()并从那里中断,如果它是真的。在主线程的onStop()中,您应该使用sleep循环,并等待AsyncTask完成,然后再关闭DB连接。