Play Store с отчетом sh - IllegalStateException в Room + AsyncTask, но только на Android 10 - PullRequest
3 голосов
/ 18 февраля 2020

У моего приложения одна из основных причин сбоев в отчетах: java.lang.IllegalStateException

Я вижу, откуда оно, это функциональность, которая создает уведомления из БД содержимое в фоновом режиме в течение дня, когда приложение не активно. Интересно то, что это, кажется, происходит только в самой новой Android 10 версии:

Pie charts of the report

Что-то изменилось в как вы обрабатываете данные базы данных в неактивном состоянии приложения?


Вот отчет cra sh:

java.lang.RuntimeException: 
  at android.os.AsyncTask$4.done (AsyncTask.java:399)
  at java.util.concurrent.FutureTask.finishCompletion (FutureTask.java:383)
  at java.util.concurrent.FutureTask.setException (FutureTask.java:252)
  at java.util.concurrent.FutureTask.run (FutureTask.java:271)
  at android.os.AsyncTask$SerialExecutor$1.run (AsyncTask.java:289)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
  at java.lang.Thread.run (Thread.java:919)
Caused by: java.lang.IllegalStateException: 
  at androidx.room.RoomOpenHelper.checkIdentity (RoomOpenHelper.java:139)
  at androidx.room.RoomOpenHelper.onOpen (RoomOpenHelper.java:119)
  at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen (FrameworkSQLiteOpenHelper.java:151)
  at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked (SQLiteOpenHelper.java:428)
  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase (SQLiteOpenHelper.java:317)
  at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase (FrameworkSQLiteOpenHelper.java:96)
  at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase (FrameworkSQLiteOpenHelper.java:54)
  at androidx.room.RoomDatabase.query (RoomDatabase.java:256)
  at androidx.room.util.DBUtil.query (DBUtil.java:54)

  (the next 3 lines are where it's at)
  at com.dev.solidmind.db.dao.MNotificationDao_Impl.getNextNotification (MNotificationDao_Impl.java:75)
  at com.dev.solidmind.repository.NotificationRepository$FetchNextNotifAsyncTask.doInBackground (NotificationRepository.java:58)
  at com.dev.solidmind.repository.NotificationRepository$FetchNextNotifAsyncTask.doInBackground (NotificationRepository.java:41)
  at android.os.AsyncTask$3.call (AsyncTask.java:378)
  at java.util.concurrent.FutureTask.run (FutureTask.java:266)

Что касается кода, у меня есть AlarmManager который вызывает слушателя в какой-то момент в течение дня. В этом слушателе я вызываю AsyncTask, который извлекает данные из БД в фоновом режиме и вызывает метод интерфейса, чтобы уведомить слушателя, когда это будет сделано:

public class NotificationReceiver extends BroadcastReceiver implements NotificationRepository.FetchNextNotifAsyncTask.AsyncResponse {

    private Context context;
    private NotificationRepository repository;
    private MessageNotification nextNotification;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putLong("lastTimeOfNotifTrigger", System.currentTimeMillis());
        editor.apply();

        repository = new NotificationRepository(context);
        repository.startGetNextNotificationAsync(this);
    }

    @Override
    //Callback for when notification object has been retrieved from DB
    public void processFinish(MessageNotification notification) {
        if (notification != null) {
            nextNotification = notification;
            constructNotification();
            setNextAlarm();
        }
    }
...
public class NotificationRepository {
    private MNotificationDao mNotificationDao;
    private SuggestionDao suggestionDao;

    public NotificationRepository(Context context) {
        AppRoomDatabase db = DatabaseCopier.getInstance(context).getRoomDatabase(); //get db from existing file
        mNotificationDao = db.mNotificationDao();
        suggestionDao = db.suggestionDao();
    }

    public void startGetNextNotificationAsync(FetchNextNotifAsyncTask.AsyncResponse delegate) {
        new FetchNextNotifAsyncTask(delegate, mNotificationDao).execute();
    }

    public void setNewNextNotification(int id) {
        new UpdateNextNotifAsyncTask(mNotificationDao).execute(id);
    }

    public void revealSuggestion(int id) {
        new UpdateIsRevealedAsyncTask(suggestionDao).execute(id);
    }

    public void revealPremiumSuggestions() {
        new RevealPremiumAsyncTask(suggestionDao).execute();
    }


    //=== Inner AsyncTask class to run updates in the background ===

    public static class FetchNextNotifAsyncTask extends AsyncTask<Void, Void, MessageNotification> {

        //Interface delegate to notify Activity when done
        public interface AsyncResponse {
            void processFinish(MessageNotification notification);
        }

        private AsyncResponse delegate;
        private MNotificationDao mAsyncTaskDao;

        FetchNextNotifAsyncTask(AsyncResponse delegate, MNotificationDao dao) {
            this.delegate = delegate;
            mAsyncTaskDao = dao;
        }

        @Override
        protected MessageNotification doInBackground(Void... voids) {
            return mAsyncTaskDao.getNextNotification();
        }

        @Override
        protected void onPostExecute(MessageNotification notification) {
            delegate.processFinish(notification);
        }
    }
...

Я нашел связанные вопросы, но они охватывают другие специфические c аспекты, такие как закрытие диалогов или ClickListener:
IllegalStateException при AsyncTask
IllegalStateException asynctask - onPostExecute
Play Store Cra sh Отчет: IllegalStateException на android .view.View $ DeclaredOnClickListener.onClick


Как указано на странице Android Dev:

Выдает IllegalStateException
Если getStatus () возвращает либо AsyncTask.Status # RUNNING, либо AsyncTask.Status # FINISHED.

Так что, кажется, является причиной? Или, может быть, делегат интерфейса?

1 Ответ

3 голосов
/ 20 февраля 2020

checkIdentity выдает, если

Комната не может проверить целостность данных. Похоже, вы изменили схему, но забыли обновить номер версии. Вы можете просто исправить это, увеличив номер версии.

Есть проблема , где

В Room v1 была ошибка, где ha sh было непоследовательным, если поля переупорядочены.

Таким образом, вы могли изменить схему базы данных без обновления версии. Если вы используете старую версию Room , возможно, вы просто переупорядочили определения своих столбцов.

Оба варианта можно исправить, обновив вашу схему.

It Возможно, однако, что ваш прогресс был убит, когда вы только что обновили схему базы данных. Таким образом, новый ha sh не был записан, и база данных вошла в несовместимое состояние.

Это может быть вызвано фоновыми ограничениями в Android 10. Я бы предложил вам заменить BroadcastReceiver с IntentService вы запускаете в режиме переднего плана.

В качестве альтернативы это может быть вызвано упакованной базой данных.

Нет room_master_table, это может быть предварительно заполненная БД, мы должны проверьте, подходит ли оно для использования.

В результате возникает ошибка:

Предварительно упакованная база данных имеет недопустимую схему: ...

Поэтому вам необходимо убедиться, что база данных содержит правильную схему.

...