спорадическое исключение NullPointerException, несмотря на то, что объект не является нулевым

Я получаю спорадическое (1 из ~ 30 раз) исключение NullPointerException в этой строке кода. и я понятия не имею, откуда это берется и как это предотвратить.

public void close() {
    if (mDb!=null)
        mDb.close();
}

mDb — это объект SQliteDatabase, а функция Close реализована в классе Helper.

Что я делаю: я хочу обработать сложный запрос в этой базе данных SQliteDatabase с помощью AsyncTask. Вот код AsyncTask:

private class processCursorTask extends AsyncTask<Integer[], Void, Dataset[]> {
    private DbHelper mDb;

    processCursorTask(DbHelper db) {
        super();
        mDb=db;
    }

    @Override
    protected Dataset[] doInBackground(Integer... args) {
        Dataset[] res=mDb.getCursorFiltered(args);
        mDb.close();
        return res;
    }

    protected void onPostExecute(Dataset[] result) {
        setListView(result);
    }
}

И я создаю эту AsyncTask здесь (из ListFragment):

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    new processCursorTask(new DbHelper(this.getActivity()), mBaseDivision, mBaseValue, mSortOrder, mSortDir).execute();
}

Не совсем понятно, к какому классу принадлежит ваш метод

public void close() {
    if (mDb!=null)
        mDb.close();
}
выше. В любом случае вы звоните
private class processCursorTask extends AsyncTask<Integer[], Void, Dataset[]> {
    private DbHelper mDb;

    processCursorTask(DbHelper db) {
        super();
        mDb=db;
    }

    @Override
    protected Dataset[] doInBackground(Integer... args) {
        Dataset[] res=mDb.getCursorFiltered(args);
        mDb.close();
        return res;
    }

    protected void onPostExecute(Dataset[] result) {
        setListView(result);
    }
}
дважды: один раз в
@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    new processCursorTask(new DbHelper(this.getActivity()), mBaseDivision, mBaseValue, mSortOrder, mSortDir).execute();
}
и один раз в _4_.


person KarlKarlsom    schedule 26.03.2012    source источник
comment
Я не уверен, но попробуй сделать свой mDb volatile   -  person assylias    schedule 26.03.2012
comment
У меня было это раньше, но listFragment, из которого взят приведенный выше код, используется внутри FragmentPager. Когда я использовал один и тот же объект базы данных, он выдавал исключения, когда использовались многие фрагменты. Это моя попытка обойти. И что я не понимаю, почему это исключение nullPointerException возникает только спорадически. И объект базы данных создается только для AsyncTask. Это означает, что не выполняется никакой другой код, кроме метода запроса (который на самом деле представляет собой не более чем rawQuery, за которым следует цикл для преобразования данных в массив).   -  person Dmitry Zaytsev    schedule 26.03.2012


Ответы (2)


Исключение происходит внутри SQLiteDatabase.closeDatabase(), поэтому оно не вызвано тем, что ваш mDb является null.

Как правило, не утруждайте себя закрытием базы данных. Откройте его один раз при запуске приложения и повторно используйте одно и то же соединение во всем приложении. Вы не получаете никакой выгоды от его закрытия, так как транзакционная природа SQLite гарантирует, что все операции записи будут зафиксированы в хранилище при первой же возможности.

EDIT: хорошо, теперь я вижу, что mDb в каждом случае отличается. В любом случае прислушайтесь к моему совету не закрывать БД, и проблема исчезнет.

Нашел решение: проблема заключалась в том, что объект DbHelper был создан в потоке пользовательского интерфейса, но закрыт в рабочем потоке asyncTask. После того, как я переместил .close() в метод onPostExecute(), исключение исчезло.

person Graham Borland    schedule 26.03.2012
comment
Я сталкиваюсь с этим, я попробую ваше решение - person KarlKarlsom; 26.03.2012

Может ли это быть связано с одновременным доступом к экземпляру

private class processCursorTask extends AsyncTask<Integer[], Void, Dataset[]> {
private DbHelper mDb;

processCursorTask(DbHelper db) {
    super();
    mDb=db;
}

@Override
protected Dataset[] doInBackground(Integer... args) {
    Dataset[] res=mDb.getCursorFiltered(args);
    return res;
}

protected void onPostExecute(Dataset[] result) {
    mDb.close();
    setListView(result);
}
}
без надлежащей синхронизации?

private class processCursorTask extends AsyncTask<Integer[], Void, Dataset[]> {
private DbHelper mDb;

processCursorTask(DbHelper db) {
    super();
    mDb=db;
}

@Override
protected Dataset[] doInBackground(Integer... args) {
    Dataset[] res=mDb.getCursorFiltered(args);
    return res;
}

protected void onPostExecute(Dataset[] result) {
    mDb.close();
    setListView(result);
}
}
person KarlKarlsom    schedule 07.06.2012
comment
Я сталкиваюсь с этим, я попробую ваше решение. Как вы уверены, что это работает? У меня был объект, созданный при предварительном выполнении, соединение с БД открывалось и закрывалось в потоке в фоновом режиме, и я получил сбой - person Snake; 16.01.2013
comment
03-26 00:44:20.489: E/SqliteDatabaseCpp(6442): sqlite3_close(0x3b2278) не удалось: 27 03-26 00:44:20.520: W/dalvikvm(6442): threadid=12: поток завершается с необработанным исключением (группа =0x40a691f8) 03-26 00:44:20.520: E/AndroidRuntime(6442): НЕИСПРАВНОЕ ИСКЛЮЧЕНИЕ: AsyncTask #2
03-26 00:44:20.520: E/AndroidRuntime(6442): java.lang.RuntimeException: Произошла ошибка при выполнении doInBackground() 03-26 00:44:20.520: E/AndroidRuntime(6442): at android.os.AsyncTask$3.done(AsyncTask.java:278)
03-26 00:44: 20.520: E/AndroidRuntime(6442): в java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 03-26 00:44:20.520: E/AndroidRuntime(6442): в java.util.concurrent .FutureTask.setException(FutureTask.java:124)
03–26 00:44:20.520: E/AndroidRuntime(6442): в java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)< br> 03-26 00:44:20.520: E/AndroidRuntime(6442): в java.util.concurrent.FutureTask.run(FutureT ask.java:137)
03–26 00:44:20.520: E/AndroidRuntime(6442): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
03–26 00 :44:20.520: E/AndroidRuntime(6442): в java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 03-26 00:44:20.520: E/AndroidRuntime(6442): в java.util. concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 03-26 00:44:20.520: E/AndroidRuntime(6442): в java.lang.Thread.run(Thread.java:856) 03-26 00: 44:20.520: E/AndroidRuntime(6442): Причина: java.lang.NullPointerException
03–26 00:44:20.520: E/AndroidRuntime(6442): at android.database.sqlite.SQLiteDatabase.closeDatabase(SQLiteDatabase .java:1156) 03-26 00:44:20.520: E/AndroidRuntime(6442): в android.database.sqlite.SQLiteDatabase.close(SQLiteDatabase.java:1105) 03-26 00:44:20.520: E/AndroidRuntime (6442): в de.kialelem.trainer.DbHelper.close(DbHelper.java:676) 03-26 00:44:20.520: E/AndroidRun time(6442): в de.kialelem.trainer.ViewContentDatabaseListFragment$processCursorTask.doInBackground(ViewContentDatabaseListFragment.java:48) 03-26 00:44:20.520: E/AndroidRuntime(6442): в de.kialelem.trainer.ViewContentDatabaseListFragment$processCursorTask .doInBackground(ViewContentDatabaseListFragment.java:1) 03-26 00:44:20.520: E/AndroidRuntime(6442): в android.os.AsyncTask$2.call(AsyncTask.java:264) 03-26 00:44:20.520: E/AndroidRuntime(6442): в java.util.concurrent. FutureTask$Sync.innerRun(FutureTask.java:305)
03-26 00:44:20.520: E/AndroidRuntime(6442): ... еще 5 - person Snake; 16.01.2013