2011-09-22 91 views
8

我有一個問題,我不知道如何處理它。我的應用中的一項活動有多個AsyncTask,它們訪問單個SQLiteOpenHelper。我初始化並在onCreate()中打開助手,然後我在onStop()中關閉它。我還檢查它是否已在onResume()中初始化。Android AsyncTask和SQLite數據庫實例

由於我已經發布了我的應用程序,我收到了一些空錯誤,並在doInBackground中嘗試訪問DB幫助程序。我知道這是因爲數據庫在調用doInBackground之前關閉(onStop()),這是公平的。

我的問題是,我應該在哪裏關閉數據庫連接?在活動中使用DB助手的單個實例並從多個線程訪問它是正確的(AsyncTasks)?或者我應該爲每個AsyncTask使用單獨的DB幫助程序實例?

這是我的活動的簡化骨架:

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

您提到您在關閉數據庫之前取消了AsyncTask。但是您應該記住,取消AsyncTask只是表示要取消任務,並且需要在doInBackground()中檢查isCancelled(),並且需要停止DB操作。

在關閉數據庫之前,您需要檢查getStatus()以確保AsyncTask已停止。

+0

所以基本上我應該在doInBackground中使用while(!isCancelled){}並在循環內執行所有計算? – Marqs

+0

是的,並檢查主線程中的getStatus()以確保AsyncTask已結束。 –

+0

好的,但如果我在onStop()中檢查它並沒有結束?那麼我會在哪裏關閉數據庫連接呢? – Marqs

5

這是好事,使用單一DB Helper。 問題是,當用戶離開Activity時,DB已關閉,但AsyncTask仍可能運行。所以當你試圖訪問它時,你應該檢查DB是否爲空,如果是null這可能意味着你的Activity被銷燬並且cancel那個任務。

+0

感謝您的快速響應。我忘了提及我還有一些例外情況說'由於未經確認的陳述而無法關閉'。這可能意味着我試圖在doInBackground()中執行查詢時關閉onStop()中的數據庫連接。在克服數據庫之前,我取消了AsyncTask,但仍然出現此錯誤。任何想法爲什麼發生? – Marqs

+0

@Ovidiu你通常把數據庫初始化和清理代碼放在哪裏? (承認有一個DBHelper被幾個視圖所支持)。 –

+0

@boulder表示,將它保存在應用程序中可能是一種好的做法 –

11

您不需要爲每個活動管理數據庫連接。你可以在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的是始終可以訪問。

是的,有一個Db helper實例是一個很好的習慣。線程同步是默認爲你做的。

+0

+1 - 這非常有趣,我會研究這一點 - 謝謝! – Marqs

+0

還有一個問題......你會在哪裏關閉數據庫連接? – Marqs

+0

我不關閉它。不知道它是否真的有必要。如果你能在這裏找到更多細節,請分享一下,這很有趣。以爲我從來沒有用這種方法解決任何問題。 –