Paging Libraryを使用して、ItemKeyedDataSource
を使用してネットワークからデータをロードしています。ユーザーが編集できるアイテムを取得した後、この更新はMemoryキャッシュ内で行われます(Roomなどのデータベースは使用されません)。
PagedList
自体は更新できないため(議論 ここ )、PagedList
を再作成してPagedListAdapter
に渡す必要があります。
更新自体は問題ありませんが、recyclerView
を新しいPagedList
で更新した後、リストはリストの先頭にジャンプし、previousスクロールを破棄しますポジション。 Roomでの動作など、スクロール位置を維持しながらPagedListを更新する方法はありますか?
DataSourceは次のように実装されます:
public class MentionKeyedDataSource extends ItemKeyedDataSource<Long, Mention> {
private Repository repository;
...
private List<Mention> cachedItems;
public MentionKeyedDataSource(Repository repository, ..., List<Mention> cachedItems){
super();
this.repository = repository;
this.teamId = teamId;
this.inboxId = inboxId;
this.filter = filter;
this.cachedItems = new ArrayList<>(cachedItems);
}
@Override
public void loadInitial(@NonNull LoadInitialParams<Long> params, final @NonNull ItemKeyedDataSource.LoadInitialCallback<Mention> callback) {
Observable.just(cachedItems)
.filter(() -> return cachedItems != null && !cachedItems.isEmpty())
.switchIfEmpty(repository.getItems(..., params.requestedLoadSize).map(...))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
@Override
public void loadAfter(@NonNull LoadParams<Long> params, final @NonNull ItemKeyedDataSource.LoadCallback<Mention> callback) {
repository.getOlderItems(..., params.key, params.requestedLoadSize)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
@Override
public void loadBefore(@NonNull LoadParams<Long> params, final @NonNull ItemKeyedDataSource.LoadCallback<Mention> callback) {
repository.getNewerItems(..., params.key, params.requestedLoadSize)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> callback.onResult(response.data.list));
}
@NonNull
@Override
public Long getKey(@NonNull Mention item) {
return item.id;
}
}
PagedListは次のように作成されます:
PagedList.Config config = new PagedList.Config.Builder()
.setPageSize(PAGE_SIZE)
.setInitialLoadSizeHint(preFetchedItems != null && !preFetchedItems.isEmpty()
? preFetchedItems.size()
: PAGE_SIZE * 2
).build();
pagedMentionsList = new PagedList.Builder<>(new MentionKeyedDataSource(mRepository, team.id, inbox.id, mCurrentFilter, preFetchedItems)
, config)
.setFetchExecutor(ApplicationThreadPool.getBackgroundThreadExecutor())
.setNotifyExecutor(ApplicationThreadPool.getUIThreadExecutor())
.build();
PagedListAdapterは次のように作成されます:
public class ItemAdapter extends PagedListAdapter<Item, ItemAdapter.ItemHolder> { //Adapter from google guide, Nothing special here.. }
mAdapter = new ItemAdapter(new DiffUtil.ItemCallback<Mention>() {
@Override
public boolean areItemsTheSame(Item oldItem, Item newItem) {
return oldItem.id == newItem.id;
}
@Override
public boolean areContentsTheSame(Item oldItem, Item newItem) {
return oldItem.equals(newItem);
}
});
、次のように更新されます:
mAdapter.submitList(pagedList);
loadInitial
の実装で_androidx.paging.ItemKeyedDataSource.LoadInitialParams#requestedInitialKey
_を使用しておらず、使用する必要があると思います。
自動生成されたRoom DAOコードItemKeyedDataSource
で使用されるLimitOffsetDataSource
の別の実装を調べました。 loadInitial
の実装には、次のものが含まれます( Apache 2.0ライセンス コードが続きます):
// bound the size requested, based on known count final int firstLoadPosition = computeInitialLoadPosition(params, totalCount); final int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);
...これらの関数は_params.requestedStartPosition
_、_params.requestedLoadSize
_および_params.pageSize
_を使用して何かを実行します。
新しいPagedList
を渡すときは常に、ユーザーが現在スクロールしている要素が含まれていることを確認する必要があります。それ以外の場合、PagedListAdapterはこれをこれらの要素の削除として扱います。その後、loadAfterまたはloadBeforeアイテムがこれらの要素をロードすると、これらの要素の後続の挿入としてそれらが処理されます。表示されているアイテムの削除と挿入を行わないようにする必要があります。一番上までスクロールしているように聞こえるため、誤ってすべてのアイテムを削除してすべて挿入している可能性があります。
PagedListsでRoomを使用するときにこれが機能すると私が考える方法は次のとおりです。
params.requestedStartPosition
_を可視要素に設定してloadInitial
を呼び出します。loadBefore
またはloadAfter
を呼び出すことができます。それがあなたがしようとしていることにどのように対応するのかはわかりませんが、多分それは役に立ちますか?新しいPagedListを提供するときは常に、以前のリストと比較され、偽の挿入や削除がないことを確認する必要があります。そうしないと、混乱する可能性があります。
PAGE_SIZEが十分に大きくない問題も確認しました。ドキュメントでは、一度に表示できる要素の最大数の数倍を推奨しています。