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连接。