【问题标题】:Android AsyncTask and SQLite DB instanceAndroid AsyncTask 和 SQLite 数据库实例
【发布时间】:2011-11-22 18:18:35
【问题描述】:

我有一个问题,我不知道如何解决它。我的应用程序中的一个活动有多个AsyncTasks,它们访问单个SQLiteOpenHelper。我在onCreate() 中初始化并打开帮助程序,并在onStop() 中关闭它。我还检查它是否已经在onResume()中初始化。

自从我发布了我的应用程序后,我在doInBackground 中收到了许多带有 Null 异常的错误,我尝试访问 DB 帮助程序。我知道这是因为数据库在调用 doInBackground 之前关闭(onStop()),这很公平。

我的问题是,我应该在哪里关闭数据库连接?在 Activity 中使用 DB 助手的单个实例并从多个线程访问它(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
        }
    }
}

【问题讨论】:

    标签: android sqlite android-asynctask sqliteopenhelper


    【解决方案1】:

    您不需要为每个活动管理数据库连接。您可以在 android.app.Application 的实例中执行此操作,并使用此实例访问 db。 像这样的:

    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 始终可以访问。

    是的,拥有一个 Db 助手实例是一种很好的做法。默认为您进行线程同步。

    【讨论】:

    • +1 - 这很有趣,我会调查一下 - 谢谢!
    • 还有一个问题……你会在哪里关闭数据库连接?
    • 我没有关闭它。想知道是否真的有必要。如果您能找到更多关于此的详细信息,请分享,这很有趣。以为我从来没有用这种方法遇到任何问题。
    • 感谢您的支持。我将尝试对此进行更多调查
    • "此方法用于模拟进程环境。它永远不会在生产 Android 设备上调用,其中进程通过简单地杀死它们来删除;在以下情况下不会执行任何用户代码(包括此回调)这样做。”来自 API 文档
    【解决方案2】:

    最好使用单个DB Helper。 问题是当用户离开ActivityDB 已关闭但AsyncTask 可能仍会运行。因此,当您尝试访问它时,您应该检查DB 是否不为空,如果它是null,这可能意味着您的Activity 已被销毁并且cancel 该任务已被销毁。

    【讨论】:

    • 感谢您的快速响应。我忘了提到我也有几个例外说“由于未完成的陈述而无法关闭”。这可能意味着当查询在 doInBackground() 中执行时,我尝试在 onStop() 中关闭数据库连接。我在关闭数据库之前取消了 AsyncTask,但我仍然收到此错误。任何想法为什么会发生?
    • @Ovidiu 你通常把DB初始化和清理代码放在哪里? (假设有一个 DBHelper 被多个视图访问)。
    • 正如@boulder 所说,将其保留在应用程序中可能是一个好习惯
    【解决方案3】:

    您提到您在关闭数据库之前取消了 AsyncTask。但是您应该记住,取消 AsyncTask 只是发出要取消任务的信号,您需要检查 doInBackground() 中的 isCancelled() 并执行必要的停止数据库操作。

    在关闭数据库之前,您需要检查 getStatus() 以确保 AsyncTask 已停止。

    【讨论】:

    • 所以基本上我应该在 doInBackground 中使用 while(!isCancelled){} 并在循环内执行所有计算?
    • 是的,并在主线程中检查 getStatus() 以确保 AsyncTask 已结束。
    • 好的,但是如果我在 onStop() 中检查它并且它还没有结束怎么办?那我应该在哪里关闭数据库连接?
    • 对于 AsyncTask,建议您在发出取消信号时尽早退出 doInBackground。因此,在 doInBackground 中的 while 循环中,每当您要执行 DB 语句时,检查 isCancelled() 并从那里中断,如果它是真的。在主线程的 onStop() 中,您应该循环使用 sleep 并等待 AsyncTask 完成,然后再关闭 DB 连接。
    猜你喜欢
    • 1970-01-01
    • 2017-03-22
    • 2017-03-26
    • 2018-07-25
    • 2012-05-25
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多