Новичок в 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;
}
мейбе попробуйте foreGround нить или часть кода используйте это
activity.runOnUiThread(() ->{
});
передать это (контекст) этому классу и передать его в Activity
Я не совсем в той же ситуации, но ниже показано, как я обрабатываю выборку данных с помощью отношения с использованием 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, и это то, что мне было нужно. Размещение решения.
Но я не занимаюсь делом.
fetchAllItemsнаходится в классе репозитория.