Android AsyncTask 和 SQLite 数据库实例

Posted

技术标签:

【中文标题】Android AsyncTask 和 SQLite 数据库实例【英文标题】:Android AsyncTask and SQLite DB instance 【发布时间】: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
        
    

【问题讨论】:

【参考方案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 连接。

以上是关于Android AsyncTask 和 SQLite 数据库实例的主要内容,如果未能解决你的问题,请参考以下文章

Android中的AsyncTask和接口回调使用详解

Android 对线程封装了:AsyncTask, HandlerThread和线程池。 有知道这三个如何选择吗?

Android面试Android异步任务AsyncTask

Android 手写数据库框架

Android 手写数据库框架

Android,AsyncTask 不调用 onProgressUpdate 和 onPostExecute