Recyclerview indexoutofboundsexception с Paging3 и библиотекой выбора (TrygetViewholderForpotisionByDeadline)Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Recyclerview indexoutofboundsexception с Paging3 и библиотекой выбора (TrygetViewholderForpotisionByDeadline)

Сообщение Anonymous »

Я разрабатываю приложение для Android в Java, которое отображает сетку японских символов кандзи с использованием Recyclerview с GridlayoutManager . Я использую библиотеку Android JetPack Paging3 для загрузки данных из локальной базы данных SQLite и библиотеки Androidx.recyclerview.selection, чтобы позволить пользователям выбирать элементы. Похоже, что это вызвано несоответствием данных между тем, что обеспечивает PagingDataAdapter, и тем, что Mayoutmanager ожидает во время прохода макета. Я также не могу воспроизвести эту проблему.

Код: Выделить всё

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)
stack trace 2:

Код: Выделить всё

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 
, SelectionTracker и наблюдает за PagingData . Он также содержит логику, чтобы обновить адаптер.

Код: Выделить всё

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();
});
Что может вызвать эту десинхронизацию между PagingDataAdapter и состоянием макета Recyclerview ? Существует ли известная проблема при объединении Paging3 (с включенными заполнителями), SelectionTracker и признанием данных с помощью Adapter.refresh () , что может привести к этому конкретному типу IndexoutOfBoundSexception ? Любая помощь или альтернативная стратегии отладки будут высоко оценены.

Подробнее здесь: https://stackoverflow.com/questions/797 ... rary-tryge
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»