Android: база данных INSERT вызывает исключение "getWritableDatabase вызван рекурсивно"

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

java.lang.IllegalStateException: getWritableDatabase вызывается рекурсивно

Данные создаются службой, которая выполняет отдельные асинхронные задачи для загрузки, преобразования и, наконец, для вставки данных. Я не уверен, что объекты контекста, которые я передаю, верны. Обратите внимание на комментарии, которые я добавил к исходному коду. Далее я добавил соответствующие классы и функции. Пожалуйста, оставьте комментарий, если вам нужна дополнительная информация.

public class CustomServiceHelper {

    // This method gets called by the activities.
    public static void loadData(Context context) {
        Intent intent = new Intent(context, CustomService.class);
        context.startService(intent);
    } 
}

...

public class CustomService extends Service {

    private void startStoringTask(Users users) {
        // Passing the context of the service.
        mStoringTask = new StoringTask(this);
        Object[] params = { users };
        mStoringTask.execute(params);
    }
}

...

public class UsersProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        // Not sure if getContext() is correct.
        mDatabase = new CustomDatabase(getContext());
        return true;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        switch (URI_MATCHER.match(uri)) {
        case URI_CODE_USERS:
            long id = mDatabase.insertUsers(values);
            // TODO: Not sure about the return value.
            return ContentUris.withAppendedId(uri, id);
        }
        return null;
    }
}

...

public class CustomDatabase {

    public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {

        CustomSQLiteOpenHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase database) {
            database.execSQL(TABLE_USERS_CREATE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
            throw new UnsupportedOperationException();
        }
    }

    private CustomSQLiteOpenHelper mDatabaseHelper = null;

    public CustomDatabase(Context context) {
        // The context is passed in by the UsersProvider.
        mDatabaseHelper = new CustomSQLiteOpenHelper(context);
    }

    public long insertUsers(ContentValues contentValues) {
        return mDatabaseHelper.getWritableDatabase().insert(
            CustomSQLiteOpenHelper.TABLE_USERS, null, contentValues);
    }
}

...

public class StoringTask extends AsyncTask<Object, Void, Boolean> {

    private Context mContext = null;
    public StoringTask(Context context) {
        mContext = context;
    }

    @Override
    protected Boolean doInBackground(Object... params) {
        Users users = (Users)params[0];
        return storeUser(users);
    }

    private boolean storeUsers(Users users) {
        if (users == null) return false;
        // Not sure if calling getContentResolver on this context is correct.
        ContentResolver contentResolver = mContext.getContentResolver();
        Iterator<User> iterator = users.iterator();
        do {
            User user = iterator.next();
            storeUser(contentResolver, user);
        }
        while (iterator.hasNext());
        return true;
    }

    private void storeUser(ContentResolver contentResolver, User user) {
        ContentValues cv = new ContentValues(1);
        cv.put(CustomDatabase.Contract.COLUMN_NAME, user.name);
        contentResolver.insert(UsersProvider.Contract.URI_USERS, cv);
    }
}

Когда я запускаю приложение в режиме отладки, я оказываюсь в классе фреймворка ThreadPoolExecutor в finally блок из runWorker() метод.


Редактировать:
Вот полная трассировка стека исключений.

java.lang.RuntimeException: An error occured while executing doInBackground()
android.os.AsyncTask$3.done(AsyncTask.java:200)
java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
java.util.concurrent.FutureTask.setException(FutureTask.java:124)
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
java.util.concurrent.FutureTask.run(FutureTask.java:137)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
java.lang.Thread.run(Thread.java:1096)
Caused by: java.lang.IllegalStateException: getWritableDatabase called recursively
android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:81)
com.test.users.database.CustomDatabase.insertUsers(CustomDatabase.java:125)
com.test.users.database.CustomDatabase$CustomSQLiteOpenHelper.insertTestData(CustomDatabase.java:85)
com.test.users.database.CustomDatabase$CustomSQLiteOpenHelper.onCreate(CustomDatabase.java:60)
android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:106)
com.test.users.database.CustomDatabase.insertUsers(CustomDatabase.java:125)
com.test.users.contentprovider.UsersProvider.insert(UsersProvider.java:51)
android.content.ContentProvider$Transport.insert(ContentProvider.java:174)
android.content.ContentResolver.insert(ContentResolver.java:587)
com.test.users.tasks.StoringTask.storeFeature(StoringTask.java:82)
com.test.users.tasks.StoringTask.storeResponse(StoringTask.java:58)
com.test.users.tasks.StoringTask.doInBackground(StoringTask.java:32)
com.test.users.tasks.StoringTask.doInBackground(StoringTask.java:1)
android.os.AsyncTask$2.call(AsyncTask.java:185)
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)

Я не упомянул метод CustomSQLiteOpenHelper.insertTestData() который вызывает getWritableDatabase(), Я называю метод insertTestData() в CustomSQLiteOpenHelper.onCreate(), Сбой происходит каждый раз, когда приложение еще не создало базу данных. Подводя итог, hawaii.five-0 был совершенно прав!

1 ответ

Решение

java.lang.IllegalStateException: getWritableDatabase вызывается рекурсивно

Так что этот вид Exception обычно бросают, когда вы используете getWritableDatabase() или же getReadableDatabase() в onCreate или же onUpgrade методы SQLiteOpenHelper.