Код: Выделить всё
java.lang.IndexOutOfBoundsException:
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java:6821)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition (RecyclerView.java:6757)
...
at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren (GridLayoutManager.java:182)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout (RecyclerView.java:4346)
Код: Выделить всё
java.lang.IndexOutOfBoundsException:
at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition (RecyclerView.java:6590)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java:6796)
...
at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren (GridLayoutManager.java:182)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout (RecyclerView.java:4346)
< /code>
Вот соответствующий код для моей настройки: < /p>
[b] 1. ViewModel [/b]
public class KanjiListViewModel extends ViewModel {
private final KanjiRepository kanjiRepository;
public final LiveData kanjiPagingData;
private final MutableLiveData currentParameters = new MutableLiveData();
public KanjiListViewModel(KanjiRepository kanjiRepository, ExecutorService databaseExecutor) {
this.kanjiRepository = kanjiRepository;
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(this);
kanjiPagingData = Transformations.switchMap(currentParameters, parameters -> {
Pager pager = new Pager(
new PagingConfig(
/* pageSize */ 100,
/* prefetchDistance */ 40,
/* enablePlaceholders */ true,
/* initialLoadSize */ 100
),
() -> new KanjiPagingSource(
kanjiRepository,
databaseExecutor,
parameters.searchQuery,
parameters.sortingOrder
)
);
return PagingLiveData.cachedIn(PagingLiveData.getLiveData(pager), viewModelScope);
});
}
public void loadKanji(String sortOrder, String query) {
ListDataParameters newParams = new ListDataParameters(query, sortOrder);
if (!newParams.equals(currentParameters.getValue())) {
currentParameters.setValue(newParams);
}
}
}
< /code>
[b] 2. Pagingsource [/b]
извлекает данные из репозитория.public class KanjiPagingSource extends ListenableFuturePagingSource {
private final KanjiRepository kanjiRepository;
private final String query;
private final String sortOrder;
private final ListeningExecutorService executor;
public KanjiPagingSource(/*...constructors...*/) { /*...*/ }
@NonNull
@Override
public ListenableFuture loadFuture(@NonNull LoadParams loadParams) {
final int pageNumber = loadParams.getKey() != null ? loadParams.getKey() : 0;
final int pageSize = loadParams.getLoadSize();
return executor.submit(() -> {
try {
int offset = pageNumber * pageSize;
List kanjiList;
int totalCount;
if (query != null && !query.isEmpty()) {
kanjiList = kanjiRepository.searchKanjiPagination(query, sortOrder, pageSize, offset);
totalCount = kanjiRepository.getKanjiAmountSearchPagination(query);
} else {
kanjiList = kanjiRepository.getAllKanjiSortedPagination(sortOrder, pageSize, offset);
totalCount = kanjiRepository.getKanjiAmountPagination();
}
Integer prevKey = (pageNumber > 0) ? pageNumber - 1 : null;
Integer nextKey = !kanjiList.isEmpty() ? pageNumber + 1 : null;
// Note: itemsBefore = offset, itemsAfter = remaining items
return new LoadResult.Page(kanjiList, prevKey, nextKey, offset, totalCount - (offset + kanjiList.size()));
} catch (Exception e) {
return new LoadResult.Error(e);
}
});
}
@Nullable
@Override
public Integer getRefreshKey(@NonNull PagingState pagingState) {
// Standard refresh key implementation
Integer anchorPosition = pagingState.getAnchorPosition();
if (anchorPosition == null) return null;
LoadResult.Page anchorPage = pagingState.closestPageToPosition(anchorPosition);
if (anchorPage == null) return null;
Integer prevKey = anchorPage.getPrevKey();
if (prevKey != null) return prevKey + 1;
Integer nextKey = anchorPage.getNextKey();
if (nextKey != null) return nextKey - 1;
return null;
}
}
< /code>
[b] 3. Адаптер [/b]
public class KanjiListAdapter extends PagingDataAdapter {
private SelectionTracker selectionTracker;
public KanjiListAdapter(KanjiListAdapterListener listener) {
super(new KanjiDiffCallback());
// ...
}
public void setSelectionTracker(SelectionTracker selectionTracker) {
this.selectionTracker = selectionTracker;
}
@Override
public void onBindViewHolder(@NonNull KanjiTileViewHolder holder, int position) {
Kanji kanji = getItem(position);
if (kanji != null) {
// ... bind data
boolean isSelected = selectionTracker.isSelected((long) kanji.getId());
holder.kanjiTileView.isSelected(isSelected);
} else {
// Placeholder view
holder.kanjiTileView.setKanji(' ');
}
}
// ... ViewHolder and DiffUtil implementation
}
< /code>
[b] 4. Fragment [/b]
Фрагмент устанавливает Recyclerview Код: Выделить всё
public class KanjiList extends Fragment {
private KanjiListAdapter kanjiListAdapter;
private SelectionTracker selectionTracker;
private RecyclerView recyclerView;
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
// ... view binding
setupRecyclerView();
// Observe new PagingData from ViewModel
viewModel.getKanjiPagingData().observe(getViewLifecycleOwner(), kanjiPagingData ->
kanjiListAdapter.submitData(getViewLifecycleOwner().getLifecycle(), kanjiPagingData));
// This is called after some items in the database are modified
handleEvent(KanjiListEvent.AfterKanjiDisabled event) {
recyclerView.post(() -> {
selectionTracker.clearSelection();
kanjiListAdapter.refresh();
});
}
}
private void setupRecyclerView() {
kanjiListAdapter = new KanjiListAdapter(this);
recyclerView.setAdapter(kanjiListAdapter);
// Setup GridLayoutManager
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int minColumnWidth = getResources().getDimensionPixelSize(R.dimen.kanji_tile_min_size);
int maxColumns = Math.max(5, screenWidth / minColumnWidth);
GridLayoutManager layoutManager = new GridLayoutManager(requireContext(), maxColumns);
recyclerView.setLayoutManager(layoutManager);
// Setup SelectionTracker
selectionTracker = new SelectionTracker.Builder(
"kanji_list",
recyclerView,
new KanjiStableIdKeyProvider(kanjiListAdapter),
new KanjiListDetailsLookup(recyclerView),
StorageStrategy.createLongStorage()).build();
kanjiListAdapter.setSelectionTracker(selectionTracker);
}
}
< /code>
Что я попробовал < /h2>
Убедитесь, что все вызовы kanjilistadapter.refresh () завернуты внутри recyclerview.post. Как, например: < /li>
< /ol>
recyclerView.post(() -> {
selectionTracker.clearSelection();
kanjiListAdapter.refresh();
});
Подробнее здесь: https://stackoverflow.com/questions/797 ... rary-tryge