Получение значений реляционной базы данных Room с помощью LiveData Transformations

Новичок в Android и Java и пытается учиться, создавая приложение. Но теперь я застрял в правильной выборке реляционных данных и отображении их в RecyclerView (с использованием ListAdapter и Infinite Scroll).

Вот суть того, чем я занимался до сих пор.

Сущности:
Предметы:

@Entity(...)
public class Item {

    @PrimaryKey(autoGenerate = true)
    private long item_id;

    @SerializedName("title")
    @Expose
    private String title = "";

    @Ignore
    @SerializedName("labels")
    @Expose
    private List<String> tags;

    ...
    }

Теги:

@Entity(...)
public class Tag {

    @PrimaryKey(autoGenerate = true)
    private long id;

    @ColumnInfo(name = "tag_name")
    private String tagName;
    ...
}

Связь:

@Entity(...)
public class ItemTags {

    private long item_id;

    private long tag_id;
    ...
}

Модернизация:

public class ApiClient {
    // Init in Constructor
    private final MutableLiveData<List<Item>> mObservableData;
    ...

    public LiveData<List<Item>> getObservableData() {
        return mObservableData;
    }

    public void onResponse(...) {
        ...
        mObservableData.postValue(responseBody.getItems());

    }
}

Репозиторий: вставка в базу данных.

public void getNetworkCallback() {
    if (isFirstCallbackNeeded()) {
        Log.d(TAG, "getNetworkCallback: Called");
        mClient.getFirstCallback();
        insertItemsToDb();
    }
}

private void insertItemsToDb() {
    LiveData<List<Item>> downloadedData = mClient.getObservableData();
        if (items != null) {
            mExecutors.diskIO().execute(() -> {
                List<Long> itemIds = insertAllItems(items);

                for (int i = 0; i < items.size(); i++) {
                    long itemId = itemIds.get(i);
                    Log.d(TAG, "insertItemsToDb: " + itemId);

                    if (itemId != -1) {
                        List<String> labelNames = items.get(i).getTags();
                        for (String labelName : labelNames) {
                            insertUniqueTagName(new Tag(labelName));

                            long tagId = fetchIdByTagName(labelName);
                            insertRelational_ItemTags(new ItemTags(itemId, tagId));
                        }
                    }
                }
        }
    });
}

До этого все хорошо. Когда база данных пуста и после получения ответа, данные успешно вставляются в базу данных.

Но всякий раз, когда я пытаюсь получить теги, относящиеся к каждому элементу, которые будут отображаться в RecyclerView, в то же время, используя Transformations.map, возвращаемый список Tags будет null или пуст.

public LiveData<List<Item>> fetchAllItems() {
    LiveData<List<Item>> itemLiveData = mItemDao.fetchAllItems();
    itemLiveData = Transformations.map(itemLiveData, input -> {
        for (Item item : input) {
            mExecutors.diskIO().execute(() -> {
                long itemId = item.getItem_id();
                Log.d(TAG, "getTransformedObservableItems: itemId: " + itemId);
                List<String> tagNames = fetchRelationalTagNameById(itemId);
                Log.d(TAG, "getTransformedObservableItems: tagNames: " + tagNames);
                item.setTags(tagNames);
            });
        }
        return input;
    });

    return itemLiveData;
}

Бревно:

getTransformedObservableItems: itemId: 1
getTransformedObservableItems: tagNames: []
getTransformedObservableItems: itemId: 2
getTransformedObservableItems: tagNames: []
...

Стоит отметить, что я наблюдаю только за Списком предметов в Дао.

@Query("SELECT * FROM item")
LiveData<List<Item>> fetchAllItems();

ViewModel:

public ItemViewModel(ApiRepository apiRepository) {
    mObservableLiveData = apiRepository.fetchAllItems();
}

public LiveData<List<Item>> getObservableLiveData() {
    return mObservableLiveData;
}

Мероприятия:

repository.getNetworkCallback();
// RecyclerView ListAdapter
mViewModel.getObservableLiveData().observe(this, adapter::submitList);

Что я здесь делаю не так? Логика верна? Любое предложение полезно.

Спасибо.


Обновлять:

После нескольких попыток я обнаружил, что, используя removeObserver() на LiveData<List<Item>> fetchAllItems() в рамках метода insertItemsToDb()onChanged(), я могу добиться результата.

Но, поскольку я использую Executors, к сожалению, removeObserver() не разрешен в фоновых потоках.

Есть ли у кого-нибудь предложения?


РешениеTransformations#switchMap, предложенный @Pycpik

public LiveData<List<Item>> fetchAllTransformedItems() {
    LiveData<List<Item>> itemLiveData = fetchAllItems();
    itemLiveData = Transformations.switchMap(itemLiveData, input -> {
        final MutableLiveData<List<Item>> itemListMutableData = new MutableLiveData<>();
        mExecutors.diskIO().execute(() -> {
            for (Item item : input) {
                long itemId = item.getItem_id();
                List<String> tagNames = fetchRelationalTagNameById(itemId);
                item.setTags(tagNames);
            }
            itemListMutableData.postValue(input);
        });
        return itemListMutableData;
    });

    return itemLiveData;
}
4
0
821
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

мейбе попробуйте foreGround нить или часть кода используйте это

activity.runOnUiThread(() ->{
});

Но я не занимаюсь делом. fetchAllItems находится в классе репозитория.

Rajarshi 10.07.2018 03:03

передать это (контекст) этому классу и передать его в Activity

ppqq 10.07.2018 07:53
Ответ принят как подходящий

Я не совсем в той же ситуации, но ниже показано, как я обрабатываю выборку данных с помощью отношения с использованием switchMap и RxJava. Может быть, это поможет тебе.

public LiveData<List<Item>> fetchAllItems() {
    LiveData<List<Item>> itemLiveData = mItemDao.fetchAllItems();
    itemLiveData = Transformations.switchMap(itemLiveData, input -> {
        MutableLiveData<List<Item>> mutableLiveData = new MutableLiveData<>();
        Completable.fromAction(() -> {
            for (Item item : input) {
                long itemId = item.getItem_id();
                Log.d(TAG, "getTransformedObservableItems: itemId: " + itemId);
                List<String> tagNames = fetchRelationalTagNameById(itemId);
                Log.d(TAG, "getTransformedObservableItems: tagNames: " + tagNames);
                item.setTags(tagNames);
            }
        })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(() -> {mutableLiveData.postValue(input);});
        return mutableLiveData;
    });
    return itemLiveData;
}

И да, я искал примеры того, как работает Transformations.switchMap, и это то, что мне было нужно. Размещение решения.

Rajarshi 10.07.2018 11:41

Другие вопросы по теме