title: PageKeyedDataSource loadAfter doesnt get fire
body: <p>In my fragment, I integrated android jetpack paging library and the data source I using <strong>PageKeyedDataSource</strong> with retrofit API callback. </p>
  
  <p>the code runs as excepted and loads the data to <strong>recyclerview</strong> but after I scroll to the bottom, it supposed to load more data by firing <strong>loadAfter</strong> function in data source class but it didn't </p>
  
  <p>I also switched to <strong>ItemKeyedDataSource</strong> still it fails to execute</p>
  
  <p>is my code wrong or the plugin have an issue! but in some demo apps which I found in GitHub works perfectly I followed there code. please if anyone had this problem and fixed let me know
  Edit: Using <strong>AndroidX</strong></p>
  
  <pre><code>public class ReportsDataSource extends PageKeyedDataSource&lt;Integer, ReportItemModel&gt; {
  
      MutableLiveData&lt;NetworkState&gt; networkState = new MutableLiveData&lt;&gt;();
      MutableLiveData&lt;NetworkState&gt; initialLoad = new MutableLiveData&lt;&gt;();
  
      private UserService getUserService;
      private List&lt;Call&lt;?&gt;&gt; compositeDisposable;
      private CompositeDisposable compositeDisposableData;
      private SchedulerProvider schedulerProvider;
      private Completable retryCompletable = null;
  
      public ReportsDataSource(UserService getUserService, List&lt;Call&lt;?&gt;&gt; compositeDisposable, CompositeDisposable compositeDisposableData, SchedulerProvider schedulerProvider) {
          this.getUserService = getUserService;
          this.compositeDisposable = compositeDisposable;
          this.compositeDisposableData = compositeDisposableData;
          this.schedulerProvider = schedulerProvider;
      }
  
  
      @Override
      public void loadInitial(@NonNull LoadInitialParams&lt;Integer&gt; params, @NonNull LoadInitialCallback&lt;Integer, ReportItemModel&gt; callback) {
  
          networkState.postValue(NetworkState.LOADING);
          initialLoad.postValue(NetworkState.LOADING);
  
          loadPage(1, new callback() {
              @Override
              public void get(ReportListModel list) {
                  setRetry(null);
                  networkState.postValue(NetworkState.LOADED);
                  initialLoad.postValue(NetworkState.LOADED);
                  callback.onResult(list.data.items, 1, list.data.next);
              }
  
              @Override
              public void failure(Throwable t) {
                  setRetry(() -&gt; loadInitial(params, callback));
                  NetworkState error = NetworkState.error(t.getMessage());
                  networkState.postValue(error);
                  initialLoad.postValue(error);
              }
          });
      }
  
      @Override
      public void loadBefore(@NonNull LoadParams&lt;Integer&gt; params, @NonNull LoadCallback&lt;Integer, ReportItemModel&gt; callback) {
  
      }
  
      @Override
      public void loadAfter(@NonNull LoadParams&lt;Integer&gt; params, @NonNull LoadCallback&lt;Integer, ReportItemModel&gt; callback) {
  
          networkState.postValue(NetworkState.LOADING);
  
          loadPage(params.key, new callback() {
              @Override
              public void get(ReportListModel list) {
                  setRetry(null);
                  networkState.postValue(NetworkState.LOADED);
                  callback.onResult(list.data.items, list.data.next != params.key ? null : list.data.next);
              }
  
              @Override
              public void failure(Throwable t) {
                  setRetry(() -&gt; loadAfter(params, callback));
                  networkState.postValue(NetworkState.error(t.getMessage()));
              }
          });
      }
  
  
      public static void log(String msg) {
          boolean threadMain = Looper.getMainLooper().getThread() == Thread.currentThread();
          Timber.tag("Thread_finder_" + (threadMain ? "ui" : "none")).d(Thread.currentThread().getId() + " " + msg);
      }
  
      private void loadPage(int i, callback callback) {
          log("loadPage");
          Call&lt;ReportListModel&gt; call = getUserService.getReportsList(i);
          compositeDisposable.add(call);
          try {
              Response&lt;ReportListModel&gt; response = call.execute();
              log("onResponse");
              if (RetrofitHelper.isSuccessful(response)) {
                  callback.get(response.body());
              } else {
                  callback.failure(new Throwable("Model verification is failed"));
              }
          } catch (IOException e) {
              callback.failure(e);
              //e.printStackTrace();
          }
      }
  
      public void retry() {
          if (retryCompletable != null) {
              compositeDisposableData.add(retryCompletable.subscribeOn(schedulerProvider.io()).observeOn(schedulerProvider.ui()).subscribe(() -&gt; {
              }, Timber::d));
          }
      }
  
      private void setRetry(Action action) {
          if (action == null) {
              this.retryCompletable = null;
          } else {
              this.retryCompletable = Completable.fromAction(action);
          }
      }
  
      @NonNull
      public MutableLiveData&lt;NetworkState&gt; getNetworkState() {
          return networkState;
      }
  
      @NonNull
      public MutableLiveData&lt;NetworkState&gt; getInitialLoad() {
          return initialLoad;
      }
  
  
      public interface callback {
          void get(ReportListModel list);
  
          void failure(Throwable t);
      }
  }
  </code></pre>
  
  <p>ViewModel</p>
  
  <pre><code>public class ReportsListViewModel extends ViewModel {
  
      private static final int PAGE_SIZE = 10;
      private Executor executor = Executors.newFixedThreadPool(5);
      public LiveData&lt;PagedList&lt;ReportItemModel&gt;&gt; list;
      private List&lt;Call&lt;?&gt;&gt; compositeDisposable = new ArrayList&lt;&gt;();
      private CompositeDisposable compositeDisposableData = new CompositeDisposable();
      private ReportsDataSourceFactory sourceFactory;
  
  
      public final ObservableBoolean isErrorMessageVisible;
      public final ObservableBoolean isRetryButtonVisible;
      public final ObservableBoolean isLoadingProgressBarVisible;
      public final ObservableBoolean isSwipeRefreshLayoutEnable;
      public final ObservableField&lt;String&gt; errorMessage;
  
  
      public ReportsListViewModel(UserService userService, SchedulerProvider schedulerProvider) {
          sourceFactory = new ReportsDataSourceFactory(userService, compositeDisposable, compositeDisposableData, schedulerProvider);
          PagedList.Config config = new PagedList.Config.Builder()
                  .setPageSize(PAGE_SIZE)
                  .setEnablePlaceholders(false)
                  .build();
  
          list = new LivePagedListBuilder&lt;&gt;(sourceFactory, config).build();
  
          isErrorMessageVisible = new ObservableBoolean(false);
          errorMessage = new ObservableField&lt;&gt;("");
          isRetryButtonVisible = new ObservableBoolean(false);
          isLoadingProgressBarVisible = new ObservableBoolean(true);
          isSwipeRefreshLayoutEnable = new ObservableBoolean(true);
      }
  
  
      @Override
      protected void onCleared() {
          super.onCleared();
          RetrofitStatic.clearRetrofitList(compositeDisposable);
          compositeDisposableData.clear();
      }
  
      public void retry() {
          sourceFactory.getDataSourceLiveData().getValue().retry();
      }
  
      public void refresh() {
          sourceFactory.getDataSourceLiveData().getValue().invalidate();
      }
  
      public LiveData&lt;NetworkState&gt; getNetworkState() {
          return Transformations.switchMap(sourceFactory.getDataSourceLiveData(), ReportsDataSource::getNetworkState);
      }
  
      public LiveData&lt;NetworkState&gt; getRefreshState() {
          return Transformations.switchMap(sourceFactory.getDataSourceLiveData(), ReportsDataSource::getInitialLoad);
      }
  
      public void setInitialLoadingState(NetworkState networkState) {
          isErrorMessageVisible.set((networkState.getMessage() != null));
          errorMessage.set(networkState.getMessage());
  
          isRetryButtonVisible.set(networkState.getStatus() == NetworkStateStatus.FAILED);
          isLoadingProgressBarVisible.set(networkState.getStatus() == NetworkStateStatus.RUNNING);
          isSwipeRefreshLayoutEnable.set(networkState.getStatus() == NetworkStateStatus.SUCCESS);
      }
  }
  </code></pre>
  
  <p>PageListAdapter</p>
  
  <pre><code>public class ReportListAdapter extends PagedListAdapter&lt;ReportItemModel, RecyclerView.ViewHolder&gt; {
  
      public static final DiffUtil.ItemCallback&lt;ReportItemModel&gt; DIFF_CALLBACK = new DiffUtil.ItemCallback&lt;ReportItemModel&gt;() {
  
          @Override
          public boolean areItemsTheSame(@NonNull ReportItemModel oldItem, @NonNull ReportItemModel newItem) {
              return oldItem.reportId == newItem.reportId;
          }
  
          @Override
          public boolean areContentsTheSame(@NonNull ReportItemModel oldItem, @NonNull ReportItemModel newItem) {
              return oldItem.equals(newItem);
          }
      };
      private NetworkState networkState = null;
      private RetryCallback retryCallback;
  
      public ReportListAdapter(RetryCallback retryCallback) {
          super(DIFF_CALLBACK);
          this.retryCallback = retryCallback;
      }
  
      @Override
      public int getItemViewType(int position) {
          if (hasExtraRow() &amp;&amp; position == getItemCount() - 1) {
              return R.layout.item_network_state;
          } else {
              return R.layout.recycler_report_item;
          }
      }
  
      @NonNull
      @Override
      public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
          View view;
          switch (viewType) {
              case R.layout.recycler_report_item:
              default:
                  view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_report_item, parent, false);
                  return new ViewHolder(view);
              case R.layout.item_network_state:
                  view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_network_state, parent, false);
                  return new NetWorkStateHolder(view);
          }
      }
  
      @Override
      public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
          if (holder instanceof ViewHolder) {
              bindView((ViewHolder) holder, position, holder.itemView.getContext());
          } else if (holder instanceof NetWorkStateHolder) {
              bindNetworkView((NetWorkStateHolder) holder, position, holder.itemView.getContext());
          }
      }
  
      private void bindNetworkView(NetWorkStateHolder holder, int position, Context context) {
          NetworkStateItemViewModel mNetworkStateItemViewModel = new NetworkStateItemViewModel(networkState, retryCallback);
          if (holder.binding != null) {
              holder.binding.setViewModel(mNetworkStateItemViewModel);
              holder.binding.executePendingBindings();
          }
      }
  
      @Override
      public int getItemCount() {
          return super.getItemCount() + (hasExtraRow() ? 1 : 0);
      }
  
      private void bindView(ViewHolder holder, int position, Context context) {
          holder.binding.reportId.setText( "Report ID: "+position);
      }
  
      private boolean hasExtraRow() {
          return networkState != null &amp;&amp; networkState != NetworkState.LOADED;
      }
  
      public void setNetworkState(NetworkState newNetworkState) {
          if (getCurrentList() != null) {
              if (getCurrentList().size() != 0) {
                  NetworkState previousState = this.networkState;
                  boolean hadExtraRow = hasExtraRow();
                  this.networkState = newNetworkState;
                  boolean hasExtraRow = hasExtraRow();
                  if (hadExtraRow != hasExtraRow) {
                      if (hadExtraRow) {
                          notifyItemRemoved(super.getItemCount());
                      } else {
                          notifyItemInserted(super.getItemCount());
                      }
                  } else if (hasExtraRow &amp;&amp; previousState != newNetworkState) {
                      notifyItemChanged(getItemCount() - 1);
                  }
              }
          }
      }
  
      public class ViewHolder extends RecyclerView.ViewHolder {
          private final RecyclerReportItemBinding binding;
  
          public ViewHolder(@NonNull View itemView) {
              super(itemView);
              binding = DataBindingUtil.bind(itemView);
          }
      }
  
      public class NetWorkStateHolder extends RecyclerView.ViewHolder {
          private final ItemNetworkStateBinding binding;
          private final NetworkStateItemViewModel mNetworkStateItemViewModel;
  
          public NetWorkStateHolder(@NonNull View itemView) {
              super(itemView);
              mNetworkStateItemViewModel = new NetworkStateItemViewModel(networkState, retryCallback);
              binding = DataBindingUtil.bind(itemView);
              binding.setViewModel(mNetworkStateItemViewModel);
              binding.executePendingBindings();
          }
      }
  }
  </code></pre>
  
  <p>Fragment:</p>
  
  <pre><code>public class ReportsFragment extends ParentFragment implements RetryCallback {
  
      private ReportsFragment.callback callback;
      private FragmentReportsListBinding binding;
      private ReportsListViewModel reportViewModel;
      private ReportListAdapter adapter;
  
  
      public void setup(callback callback) {
          this.callback = callback;
      }
  
      @Nullable
      @Override
      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
          super.onCreateView(inflater, container, savedInstanceState);
          binding = DataBindingUtil.inflate(inflater, R.layout.fragment_reports_list, container, false);
          reportViewModel = ViewModelProviders.of(this, mViewModelFactory).get(ReportsListViewModel.class);
          binding.setViewModel(reportViewModel);
          binding.executePendingBindings();
          initAdapter();
          initSwipeToRefresh();
          return binding.getRoot();
      }
  
      private void initSwipeToRefresh() {
          reportViewModel.getRefreshState().observe(this, networkState -&gt; {
              if (adapter.getCurrentList() != null) {
                  if (adapter.getCurrentList().size() &gt; 0) {
                      binding.usersSwipeRefreshLayout.setRefreshing(networkState != null &amp;&amp; networkState.getStatus() == NetworkState.LOADING.getStatus());
                  } else {
                      setInitialLoadingState(networkState);
                  }
              } else {
                  setInitialLoadingState(networkState);
              }
          });
      }
  
      private void setInitialLoadingState(NetworkState networkState) {
          reportViewModel.setInitialLoadingState(networkState);
      }
  
      private void initAdapter() {
          LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
          adapter = new ReportListAdapter(this);
          binding.recycler.setLayoutManager(linearLayoutManager);
          binding.recycler.setAdapter(adapter);
          reportViewModel.list.observe(this,  adapter::submitList);
          reportViewModel.getNetworkState().observe(this, adapter::setNetworkState);
      }
  
      @Override
      public void retry() {
          reportViewModel.retry();
      }
  
      public interface callback {
  
      }
  }
  </code></pre>
  
  <p>XML</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;layout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"&gt;
  
      &lt;data&gt;
  
          &lt;import type="android.view.View" /&gt;
  
          &lt;variable
              name="viewModel"
              type="dasarahalli.portal.adapters.paging.reports.ReportsListViewModel" /&gt;
      &lt;/data&gt;
  
  
      &lt;androidx.coordinatorlayout.widget.CoordinatorLayout
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical"&gt;
  
          &lt;androidx.swiperefreshlayout.widget.SwipeRefreshLayout
              android:id="@+id/usersSwipeRefreshLayout"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:enabled="@{viewModel.isSwipeRefreshLayoutEnable}"
              app:onRefreshListener="@{viewModel::refresh}"&gt;
  
              &lt;androidx.recyclerview.widget.RecyclerView
                  android:id="@+id/recycler"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent" /&gt;
          &lt;/androidx.swiperefreshlayout.widget.SwipeRefreshLayout&gt;
  
          &lt;LinearLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_gravity="center"
              android:orientation="vertical"
              android:padding="8dp"&gt;
  
              &lt;TextView
                  android:id="@+id/errorMessageTextView"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_gravity="center_horizontal"
                  android:text="@{viewModel.errorMessage}"
                  android:visibility="@{viewModel.isErrorMessageVisible ? View.VISIBLE : View.GONE}" /&gt;
  
              &lt;ProgressBar
                  android:id="@+id/loadingProgressBar"
                  style="?android:attr/progressBarStyle"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_gravity="center"
                  android:visibility="@{viewModel.isLoadingProgressBarVisible ? View.VISIBLE : View.GONE}" /&gt;
  
              &lt;Button
                  android:id="@+id/retryLoadingButton"
                  style="@style/Widget.AppCompat.Button.Colored"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_gravity="center"
                  android:onClick="@{() -&gt; viewModel.retry()}"
                  android:text="RETRY"
                  android:visibility="@{viewModel.isRetryButtonVisible ? View.VISIBLE : View.GONE}" /&gt;
  
          &lt;/LinearLayout&gt;
  
      &lt;/androidx.coordinatorlayout.widget.CoordinatorLayout&gt;
  &lt;/layout&gt;
  </code></pre>