Android AsyncTask и экземпляр SQLite DB - PullRequest
       14

Android AsyncTask и экземпляр SQLite DB

8 голосов
/ 22 сентября 2011

У меня есть проблема, и я не знаю, как к ней подойти. Активность в моем приложении имеет несколько AsyncTask с доступом к одному SQLiteOpenHelper. Я инициализирую и открываю помощник в onCreate() и закрываю его в onStop(). Я также проверяю, было ли оно инициализировано в onResume().

С тех пор как я опубликовал свое приложение, в doInBackground я получил ряд ошибок с Null Exception, когда я пытаюсь получить доступ к помощнику БД. Я знаю, что это происходит потому, что БД закрыта (onStop()) как раз перед вызовом doInBackground, достаточно справедливо.

Мой вопрос: где мне закрыть соединение с БД? Правильно ли использовать один экземпляр помощника БД в Activity и обращаться к нему из нескольких потоков (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
        }
    }
}

Ответы [ 3 ]

11 голосов
/ 22 сентября 2011

Вам не нужно управлять подключением к БД для каждого действия. Вы можете сделать это в экземпляре 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 - хорошая практика. Синхронизация потоков сделана для вас по умолчанию.

5 голосов
/ 22 сентября 2011

Хорошо использовать один DB Helper. Проблема в том, что когда пользователь покидает Activity, DB закрывается, но AsyncTask все еще может работать. Поэтому вы должны проверить, что DB не является нулевым, когда вы пытаетесь получить к нему доступ, и если это null, это может означать, что ваш Activity был уничтожен и cancel эта задача.

1 голос
/ 22 сентября 2011

Вы упомянули, что отменили AsyncTask перед закрытием БД. Но вы должны иметь в виду, что отмена AsyncTask просто сигнализирует о том, что задача должна быть отменена, и вам нужно проверить isCancelled () в doInBackground () и сделать все необходимое для остановки операций БД.

Перед закрытием БД вам необходимо проверить getStatus (), чтобы убедиться, что AsyncTask остановлен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...