0

i am implementing paging library in android all works fine if item of all pages are the same. When item of last page items size is 1 rather then 10 it gives a exception. i am using paging library 2.1.1 with androidx.

Exception

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 Class : This is my data source class with is getting data from web service

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 Class

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 Class

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;
}

}

Activity Class

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);
}

}

kashif
  • 1
  • 1

1 Answers1

0

Paging2 doesn't support variable page sizes, you need to migrate to Paging3 (still in alpha) for that functionality. This is partially due to how tiling support was implemented, but Paging3 has rewritten things from the ground up to remove this constraint.

dlam
  • 3,547
  • 17
  • 20
  • can you attach any link or sample for this because i am finding solution from 10 days – kashif Jul 19 '20 at 10:21
  • There are docs with samples here: https://developer.android.com/topic/libraries/architecture/paging/v3-overview. As well as additional samples on Github here: https://github.com/android/architecture-components-samples (PagingSample / PagingWithNetwork) – dlam Jul 19 '20 at 10:49
  • Thanks for this links ... but i am asking for specific how variable page size handle in android paging library 3 ? – kashif Jul 19 '20 at 11:12
  • PagingSource can return different sized pages and Paging3 will handle it. In Paging2, it's actually unsupported to return different sized pages from a DataSource, although it might not crash in all cases. There's no extra code needed for variable page size specifically, although you'll need to migrate to the Paging3 API. There's a .toPagingSource() factory helper to help you do the migration piece-wise. In the DAC link I posted earlier, there is also a pretty detailed migration guide. – dlam Jul 20 '20 at 01:15