Как предотвратить состояние гонки при работе с теми же данными из базы данных Room с помощью AsyncTask? - PullRequest
0 голосов
/ 26 января 2019

Я работаю над приложением для Android, которое хранит пользовательские объекты "TimeSet" в базе данных. При взаимодействии с таблицей я использую AsyncTask объекты для вставки и обновления строк. Во время тестирования я обнаружил, что эти задачи должны выполняться в определенном порядке (например, строка должна быть вставлена ​​в базу данных перед ее обновлением), и когда они не выполняются должным образом, тесты не выполняются.

Насколько я понимаю, AsyncTask работает по принципу "первым пришел - первым обслужен". В идеале я хочу, чтобы updateAsyncTask() ждал, пока в таблице не появится какая-то строка, прежде чем это произойдет. Я пытался использовать объекты блокировки, чтобы предотвратить это, но у меня не получилось. Я также видел предложение, которое включало в себя отправку какого-то сообщения onPostExecute(), но я не уверен, как заставить это работать для моего кода. Я относительно новичок в работе с Room в Android и считаю эту область особенно запутанной.

Типичный метод тестирования, который обновляет строку:

@Test
public void replaceTodaysTime() {
    mActivityRule.getActivity().mTimeSetViewModel.insert(oldTimeSet);
    mActivityRule.getActivity().sendTimeToDatabase(NEW_WORSE_TIME, EXERCISE_NAME, MOCK_DATE);
    TimeSet timeSet = mActivityRule.getActivity().mTimeSetViewModel.getByName(EXERCISE_NAME);
    assertEquals(NEW_WORSE_TIME, timeSet.getTodaystime());
    assertNotSame(oldTimeSet.getTodaystime(), timeSet.getTodaystime());
}

ViewModel связан с TimeSetRepository

public class TimeSetRepository {

public void insert(TimeSet timeSet) {
    insertAsyncTask iat = new insertAsyncTask(mTimeSetDao);
    timeSetLock.lock();
    try {
        iat.execute(timeSet);
    } finally {
        if(iat.getStatus() == AsyncTask.Status.FINISHED) {
            timeSetLock.unlock();
        }
    }
}

public void updateByName(TimeSet timeSet) {
    while (mAllTimeSets == null && mAllTimeSets.isEmpty()){
        //do nothing!
    }
    updateAsyncTask uat = new updateAsyncTask(mTimeSetDao);
    timeSetLock.lock();
    try {
        uat.execute(timeSet);
    } finally {
        if(uat.getStatus() == AsyncTask.Status.FINISHED) {
            timeSetLock.unlock();
        }
    }
}


static class insertAsyncTask extends AsyncTask<TimeSet, Void, Void> {

    private TimeSetDao mAsyncTimeSetDao;

    insertAsyncTask(TimeSetDao dao) {
        mAsyncTimeSetDao = dao;
    }

    @Override
    protected Void doInBackground(final TimeSet... timeSets) {
        mAsyncTimeSetDao.insertTimeSet(timeSets[0]);
        return null;
    }

}

private static class updateAsyncTask extends AsyncTask<TimeSet, Void, Void> {
    private TimeSetDao mAsyncTimeSetDao;
    updateAsyncTask(TimeSetDao dao) {
        mAsyncTimeSetDao = dao;
    }
    @Override
    protected Void doInBackground(final TimeSet... timeSets) {
        mAsyncTimeSetDao.updateLastAccessed(timeSets[0].getExercisename(), timeSets[0].getLastaccessed());
        mAsyncTimeSetDao.updateTodaysTime(timeSets[0].getExercisename(), timeSets[0].getTodaystime());
        return null;
    }

}


}

Я ожидаю, что oldTimeSet будет вставлен в базу данных, затем будет обновлена ​​строка, а затем, наконец, получит строку как объект. Когда это работает, переменная todaysTime изменилась. Тем не менее, это не всегда работает, иногда возвращает время из oldTimeSet, иногда timeSet в методе теста является нулевым объектом и так далее. Я выполняю подобные действия в других тестах с похожими результатами. Я думаю, что если я смогу решить эту конкретную проблему, я смогу адаптировать решение к остальным тестам.

Спасибо за вашу помощь.

...