Индекс библиотеки подкачки Android вне привязанного исключения

Я реализую библиотеку подкачки в Android, все работает нормально, если элементы всех страниц одинаковы. Когда размер элемента последней страницы равен 1, а не 10, возникает исключение. Я использую библиотеку подкачки 2.1.1 с androidx.

Исключение

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.dasfilm.azzeddine.dasfilm, PID: 22472
java.lang.IndexOutOfBoundsException: Index: 4, Size: 4
    at java.util.ArrayList.get(ArrayList.java:437)
    at androidx.paging.PagedStorage.get(PagedStorage.java:152)
    at androidx.paging.PagedList.get(PagedList.java:384)
    at androidx.paging.AsyncPagedListDiffer.getItem(AsyncPagedListDiffer.java:206)
    at androidx.paging.PagedListAdapter.getItem(PagedListAdapter.java:156)
    at com.dasfilm.azzeddine.dasfilm.Views.Adapters.FreshoneProductPaggingAdapter.onBindViewHolder(FreshoneProductPaggingAdapter.java:56)
    at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6781)
    at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6823)
    at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752)
    at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019)
    at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:286)
    at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:343)
    at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:359)
    at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:366)
    at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:397)
    at android.os.Handler.handleCallback(Handler.java:907)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:216)
    at android.app.ActivityThread.main(ActivityThread.java:7625)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)

Класс DataSource: это мой класс источника данных, который получает данные из веб-службы.

public class MoviesInTheaterDataSource extends PageKeyedDataSource<Integer, FreshProduct> {
private static final String TAG = "MoviesInTheaterDataSou";
private ProductApiCall tmdbWebService;
private MutableLiveData<NetworkState> networkState;
private MutableLiveData<NetworkState> initialLoading;
private Executor retryExecutor;

public MoviesInTheaterDataSource(Executor retryExecutor,ProductApiCall webService) {
    tmdbWebService = webService;
    networkState = new MutableLiveData<>();
    initialLoading = new MutableLiveData<>();
    this.retryExecutor = retryExecutor;
}

public MutableLiveData<NetworkState> getNetworkState() {
    return networkState;
}

public MutableLiveData getInitialLoading() {

    return initialLoading;
}

@Override
public void loadInitial(@NonNull final LoadInitialParams<Integer> params, @NonNull final LoadInitialCallback<Integer, FreshProduct> callback) {
    Log.d(TAG, "loadInitial: ");
    initialLoading.postValue(NetworkState.LOADING);
    networkState.postValue(NetworkState.LOADING);

    tmdbWebService.getProductList(1,"","",1);


    tmdbWebService.SetListenersProduct(new ProductApiCall.ListenersProduct() {
        @Override
        public void onSuccess(List<FreshProduct> itemList, int totalPageCount) {
            initialLoading.postValue(NetworkState.LOADING);
            int loadsize = params.requestedLoadSize;
            callback.onResult(itemList, 1, 2);

            networkState.postValue(NetworkState.LOADED);

        }
    });




}

@Override
public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, FreshProduct> callback) {

}

@Override
public void loadAfter(@NonNull final LoadParams<Integer> params, @NonNull final LoadCallback<Integer, FreshProduct> callback) {
    networkState.postValue(NetworkState.LOADING);




    tmdbWebService.getProductList(1,"","",params.key);


    tmdbWebService.SetListenersProduct(new ProductApiCall.ListenersProduct() {
        @Override
        public void onSuccess(List<FreshProduct> itemList, int totalPageCount) {
            initialLoading.postValue(NetworkState.LOADING);
                     networkState.postValue(NetworkState.LOADED);

            callback.onResult(itemList, params.key+1);


            networkState.postValue(NetworkState.LOADED);
        }
    });
}

}

Класс DataSource Factory

public class MoviesInTheaterDataSource extends PageKeyedDataSource<Integer, FreshProduct> {
private static final String TAG = "MoviesInTheaterDataSou";
private ProductApiCall tmdbWebService;
private MutableLiveData<NetworkState> networkState;
private MutableLiveData<NetworkState> initialLoading;
private Executor retryExecutor;

public MoviesInTheaterDataSource(Executor retryExecutor,ProductApiCall webService) {
    tmdbWebService = webService;
    networkState = new MutableLiveData<>();
    initialLoading = new MutableLiveData<>();
    this.retryExecutor = retryExecutor;
}

public MutableLiveData<NetworkState> getNetworkState() {
    return networkState;
}

public MutableLiveData getInitialLoading() {

    return initialLoading;
}

@Override
public void loadInitial(@NonNull final LoadInitialParams<Integer> params, @NonNull final LoadInitialCallback<Integer, FreshProduct> callback) {
    Log.d(TAG, "loadInitial: ");
    initialLoading.postValue(NetworkState.LOADING);
    networkState.postValue(NetworkState.LOADING);

    tmdbWebService.getProductList(1,"","",1);


    tmdbWebService.SetListenersProduct(new ProductApiCall.ListenersProduct() {
        @Override
        public void onSuccess(List<FreshProduct> itemList, int totalPageCount) {
            initialLoading.postValue(NetworkState.LOADING);
            int loadsize = params.requestedLoadSize;
            callback.onResult(itemList, 1, 2);

            networkState.postValue(NetworkState.LOADED);

        }
    });




}

@Override
public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, FreshProduct> callback) {

}

@Override
public void loadAfter(@NonNull final LoadParams<Integer> params, @NonNull final LoadCallback<Integer, FreshProduct> callback) {
    networkState.postValue(NetworkState.LOADING);




    tmdbWebService.getProductList(1,"","",params.key);


    tmdbWebService.SetListenersProduct(new ProductApiCall.ListenersProduct() {
        @Override
        public void onSuccess(List<FreshProduct> itemList, int totalPageCount) {
            initialLoading.postValue(NetworkState.LOADING);
                     networkState.postValue(NetworkState.LOADED);

            callback.onResult(itemList, params.key+1);


            networkState.postValue(NetworkState.LOADED);
        }
    });
}

}

ViewModel Класс

public class MoviesInTheaterViewModel extends ViewModel {
private static final String TAG = "TheaterViewModel";
private LiveData<PagedList<FreshProduct>> moviesInTheaterList;
private LiveData<NetworkState> networkStateLiveData;
private Executor executor;
private LiveData<MoviesInTheaterDataSource> dataSource;


public MoviesInTheaterViewModel() {
    Log.d(TAG, "MoviesInTheaterViewModel: ");
    executor = Executors.newFixedThreadPool(5);
    ProductApiCall webService = new ProductApiCall(MyApp.getInstance().getApplicationContext());
    MoviesInTheaterDataSourceFactory factory = new MoviesInTheaterDataSourceFactory(executor,webService);


    dataSource =  factory.getMutableLiveData();

    networkStateLiveData = Transformations.switchMap(factory.getMutableLiveData(), new Function<MoviesInTheaterDataSource, LiveData<NetworkState>>() {
        @Override
        public LiveData<NetworkState> apply(MoviesInTheaterDataSource source) {
            Log.d(TAG, "apply: network change");
            return source.getNetworkState();
        }
    });

    PagedList.Config pageConfig = (new PagedList.Config.Builder())
            .setEnablePlaceholders(false)
            .setPageSize(10)
            .build();

    moviesInTheaterList = (new LivePagedListBuilder<Integer,FreshProduct>(factory,pageConfig))
                                                .setFetchExecutor(executor)
                                                .build();

}

public LiveData<PagedList<FreshProduct>> getMoviesInTheaterList() {
    Log.d(TAG, "getMoviesInTheaterList: ");
    return moviesInTheaterList;
}

public LiveData<NetworkState> getNetworkStateLiveData() {
    return networkStateLiveData;
}

}

Класс активности

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private MoviesInTheaterViewModel mMoviesViewModel;
private RecyclerView mRecyclerView;
private FreshoneProductPaggingAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.d(TAG, "onCreate: ");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mRecyclerView = findViewById(R.id.list);

    adapter = new FreshoneProductPaggingAdapter(this);

    mMoviesViewModel = ViewModelProviders.of(this).get(MoviesInTheaterViewModel.class);
    mMoviesViewModel.getMoviesInTheaterList().observe(this, new Observer<PagedList<FreshProduct>>() {
        @Override
        public void onChanged(@Nullable PagedList<FreshProduct> movies) {
            Log.d(TAG, "onChanged: "+movies.size());
            adapter.submitList(movies);
        }
    });
    mMoviesViewModel.getNetworkStateLiveData().observe(this, new Observer<NetworkState>() {
        @Override
        public void onChanged(@Nullable NetworkState networkState) {
            Log.d(TAG, "onChanged: network state changed");
            adapter.setNetworkState(networkState);
        }
    });
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false));
    mRecyclerView.setAdapter(adapter);
}

}


person kashif    schedule 12.07.2020    source источник


Ответы (1)


Paging2 не поддерживает переменные размеры страниц, вам необходимо перейти на Paging3 (все еще в альфа-версии) для этой функции. Частично это связано с тем, как была реализована поддержка листов, но Paging3 переписал все с нуля, чтобы удалить это ограничение.

person dlam    schedule 16.07.2020
comment
можете ли вы прикрепить ссылку или образец для этого, потому что я нахожу решение в течение 10 дней - person kashif; 19.07.2020
comment
Здесь есть документы с примерами: developer.android.com/topic/libraries / архитектура / пейджинг /. А также дополнительные образцы на Github здесь: github.com/android/architecture-components-samples (PagingSample / PagingWithNetwork) - person dlam; 19.07.2020
comment
Спасибо за эти ссылки ... но я спрашиваю, как обрабатывается переменный размер страницы в библиотеке подкачки Android 3? - person kashif; 19.07.2020
comment
PagingSource может возвращать страницы разного размера, и Paging3 справится с этим. В Paging2 фактически не поддерживается возвращение страниц разного размера из DataSource, хотя сбой может происходить не во всех случаях. Специально для переменного размера страницы не требуется дополнительный код, хотя вам необходимо перейти на API Paging3. Есть помощник фабрики .toPagingSource (), который поможет вам выполнить миграцию по частям. В ссылке на DAC, которую я разместил ранее, также есть довольно подробное руководство по миграции. - person dlam; 20.07.2020