2011-09-22 14 views
8

私は問題があり、どのように接近するのか分かりません。私のアプリのアクティビティには、複数のAsyncTaskがあり、それらは単一のSQLiteOpenHelperにアクセスします。私はonCreate()でヘルパーを初期化して開き、onStop()で閉じています。また、onResume()で初期化されているかどうかを確認します。Android AsyncTaskとSQLite DBインスタンス

私は自分のアプリを公開して以来、私はDBヘルパーにアクセスしようとするdoInBackgroundのヌル例外でエラーの数を受け取りました。私はこれが起こっていることを知っているのは、doInBackgroundが呼び出される直前にDBがクローズ(onStop())されているからです。

私の質問は、どこでDB接続を閉じるべきですか?アクティビティでDBヘルパの単一インスタンスを使用し、複数のスレッド(AsyncTasks)からアクセスするのは正しいですか?または、それぞれAsyncTaskに対して別々のDBヘルパーインスタンスを使用する必要がありますか?

これが私の活動の単純化されたスケルトンです:単一のDB Helperを使用するのは良いです

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

DBを閉じる前にAsyncTaskをキャンセルすると述べました。しかし、AsyncTaskをキャンセルするとキャンセルされるタスクが通知され、doInBackground()でisCancelled()をチェックしてDB操作を停止する必要があることに注意する必要があります。

DBを閉じる前に、getStatus()をチェックしてAsyncTaskが停止していることを確認する必要があります。

+0

基本的にdoInBackgroundでwhile(!isCancelled){}を使用し、ループ内ですべての計算を実行する必要がありますか? – Marqs

+0

はい、主スレッドでgetStatus()をチェックして、AsyncTaskが終了したことを確認してください。 –

+0

OKですが、onStop()でチェックしても終了していない場合はどうなりますか?どこでDB接続を終了しますか? – Marqs

5

。 問題は、ユーザがActivityを離れるときにDBが閉じても、AsyncTaskがまだ実行されている可能性があるということです。だから、あなたがそれにアクセスしようとしているときにDBがヌルでないことを確認する必要があります。もしそれがnullなら、これはあなたのActivityが破壊されたことを意味し、cancelそのタスクです。

+0

お返事ありがとうございます。私は、「unfinalised statementsのために閉じることができない」という例外はほとんどないことを忘れていました。これはおそらく、クエリがdoInBackground()で実行されている間にonStop()でDB接続を閉じることを試みることを意味します。私はDBをclsoingする前にAsyncTaskをキャンセルしますが、私はまだこのエラーが発生します。なぜそれが起こっているすべてのアイデア? – Marqs

+0

@Ovidiuどこに通常DB初期化とクリーンアップコードを入れますか? (DBHelperにはいくつかのビューが用意されています)。 –

+0

@boulderと言っても、それはアプリケーションの中に置いておくのが良い練習かもしれません。 –

11

アクティビティごとにdb接続を管理する必要はありません。このインスタンスを使用して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つのインスタンスを持つことは良い方法です。スレッドの同期はデフォルトで行われます。

+0

+1 - これは非常に興味深いものです。 – Marqs

+0

もう1つの質問... DB接続をどこで終了しますか? – Marqs

+0

私はそれを閉じない。それが本当に必要なのか不思議。これについてもっと詳しく知ることができれば、それは興味深いです。私はこのアプローチに何の問題も与えないと思った。 –