Можете ли вы использовать комнату и не использовать объект LiveData? - PullRequest
1 голос
/ 19 июня 2020

В настоящее время я использую для хранения 5 определенных c кнопок информацию в базе данных (комнате), чтобы сохранять ее при перезагрузках. Мое текущее использование не зависит от изменений данных, потому что единственный, кто меняет данные, - это пользователь при долгом нажатии кнопки (затем я обновляю базу данных). Следовательно, мне не нужна переменная LiveData, и это затрудняет инициализацию моей модели ViewModel.

По сути, поскольку объекты LiveData обновляются только при изменении, мои данные никогда не инициализируются. Таким образом, приложение всегда будет вызывать нулевой указатель при запуске.

Я поделюсь с вами сутью своих настроек, которые были описаны ниже. Я надеюсь, что есть какой-то способ выполнить эту работу, при которой мне не нужно наблюдать за каким-либо объектом LiveData, и я могу просто получать данные при создании экземпляра модели.

Entity:

@Entity(tableName = "myEntity")
public class MyEntity {
    @PrimaryKey
    public int buttonID;

    // other fields...
}

DAO:

@Dao
interface MyDAO {
    @Query("Select * from myDB")
    LiveData<List<MyEntity>> getEntityList();
    // I think this needs to change to just List<MyEntity>?

    // also insert and update here...
}

Репозиторий:

class MyRepository {
    private MyDAO myDAO;
    private LiveData<List<MyEntity>> allEntities;

    MyRepository(Application application) {
        MyDatabase db = MyDatabase.getInstance(application);
        myDAO = db.myDAO();
        allEntities = myDAO.getAllEntities();
    }

    LiveData<List<MyEntity>> getAllEntities() { return allEntities; }

    // Update entity...
}

ViewModel:

public class ViewModel extends AndroidViewModel {
    private MyRepository repository;
    private List<MyEntity> tempList;
    private HashMap<MyEntity> allEntities;

    public ViewModel (Application application) {
        super(application);
        repository = new MyRepository(application);

        Observer<List<MyEntity>> observer = data -> tempList = data;
        ObserveOnce(repository.getAllEntities(), observer); // ObserveOnce implementation found in this answer: https://stackoverflow.com/a/59845763/10013384
        allEntities = new HashMap<>();

        for (int i = 0; i < tempList.size(); i++) { // Nullpointer here, as tempList doesn't have any items yet.
            allEntities.put(tempList.get(i).buttonID, templist.get(i));
        }
    }

    // getter and update methods...
}

Activity:

// ...
protected void onCreate(Bundle savedInstanceState) {
    // ...
    viewModel = new ViewModelProvider(this).get(ViewModel.class);

    // Initialize UI views with data from ViewModel
}

Затем в соответствующие слушатели:

@Override
public boolean onLongClick(View v) {
    int index = (Integer) v.getTag();

    data.get(index).foo = fooNewUIData;
    ButtonArray[index].setText(fooNewUIData);
    ViewModel.update(data.get(index));  // if updated, update the ViewModel and the database
}

Ответы [ 4 ]

1 голос
/ 19 июня 2020

, поскольку объекты LiveData обновляются только при изменении, мои данные никогда не инициализируются

Это не ваша проблема. Ваша проблема в том, что вы думаете, что ObserveOnce() - это блокирующий вызов, и что результаты будут готовы немедленно, когда он вернется. На самом деле LiveData из Room действительно работает с фоновым потоком. Вам нужно реагировать, когда данные доступны в вашем Observer, а не предполагать, что они будут доступны в следующем операторе.

0 голосов
/ 20 июня 2020

Хорошо, спасибо всем за предоставленные ответы и отзывы, я ценю это!

В конечном итоге я согласен с @CommonsWare, что самый простой способ справиться с этим, вероятно, не потреблять ViewModel LiveData . Я предпочитаю настроить Observer как обычно в моем Activity и преобразовать его в нужный мне формат (ArrayList), когда я сохраню эти данные в моем классе Activity.

Проблема, с которой я столкнулся изначально обеспокоенный тем, что данные не отсортированы по моему вкусу, в противном случае можно было бы решить простой сортировкой:

Collections.sort(this.data, (o1, o2) -> Integer.compare(o1.buttonID, o2.buttonID));

Что касается проблемы asyn c, я просто возвращаюсь к разрешению обновления обратного вызова наблюдателя данные по мере их получения (и соответствующим образом обновите пользовательский интерфейс). Если в этой ситуации требуется намного больше данных, возможно, мне понадобится какой-то экран spla sh, пока приложение загружает данные. Но, к счастью, мне пока что не нужно делать ничего из этого. это выходит за рамки этого вопроса.

0 голосов
/ 19 июня 2020

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

Вы также можете использовать потоки to kotlin, чтобы по-прежнему прослушивать изменения и не использовать LiveData

Без LiveData:

List<MyEntity> getAllEntities();

С Kotlin Потоки:

fun getAllEntities(): Flow<List<MyEntity>>

Надеюсь, это поможет !!

0 голосов
/ 19 июня 2020

Да, конечно можно. Просто измените тип возвращаемого значения указанной функции c в вашем DAO с LiveData<MyDataClass> на MyDataClass.

См. Этот Codelab для дальнейшего изучения Room.

...