PageKeyedDataSource loadAfter不会触发 [英] PageKeyedDataSource loadAfter doesnt get fire

查看:558
本文介绍了PageKeyedDataSource loadAfter不会触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的片段中,我使用 PageKeyedDataSource 和改进的API回调集成了android jetpack分页库和数据源。

In my fragment, I integrated android jetpack paging library and the data source I using PageKeyedDataSource with retrofit API callback.

代码按例外方式运行,并将数据加载到 recyclerview ,但是在我滚动到底部之后,它应该通过触发<数据源类中的strong> loadAfter 函数,但没有

the code runs as excepted and loads the data to recyclerview but after I scroll to the bottom, it supposed to load more data by firing loadAfter function in data source class but it didn't

我也切换到了 ItemKeyedDataSource ,但执行失败

I also switched to ItemKeyedDataSource still it fails to execute

我的代码错误或插件有问题!但是在一些我在GitHub上找到的演示应用程序中,我可以按照上面的代码完美地工作。请如果有人遇到此问题并解决,请通知我
编辑:使用 AndroidX

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 Using AndroidX

public class ReportsDataSource extends PageKeyedDataSource<Integer, ReportItemModel> {

    MutableLiveData<NetworkState> networkState = new MutableLiveData<>();
    MutableLiveData<NetworkState> initialLoad = new MutableLiveData<>();

    private UserService getUserService;
    private List<Call<?>> compositeDisposable;
    private CompositeDisposable compositeDisposableData;
    private SchedulerProvider schedulerProvider;
    private Completable retryCompletable = null;

    public ReportsDataSource(UserService getUserService, List<Call<?>> compositeDisposable, CompositeDisposable compositeDisposableData, SchedulerProvider schedulerProvider) {
        this.getUserService = getUserService;
        this.compositeDisposable = compositeDisposable;
        this.compositeDisposableData = compositeDisposableData;
        this.schedulerProvider = schedulerProvider;
    }


    @Override
    public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, ReportItemModel> 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(() -> loadInitial(params, callback));
                NetworkState error = NetworkState.error(t.getMessage());
                networkState.postValue(error);
                initialLoad.postValue(error);
            }
        });
    }

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

    }

    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, ReportItemModel> 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(() -> 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<ReportListModel> call = getUserService.getReportsList(i);
        compositeDisposable.add(call);
        try {
            Response<ReportListModel> 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(() -> {
            }, Timber::d));
        }
    }

    private void setRetry(Action action) {
        if (action == null) {
            this.retryCompletable = null;
        } else {
            this.retryCompletable = Completable.fromAction(action);
        }
    }

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

    @NonNull
    public MutableLiveData<NetworkState> getInitialLoad() {
        return initialLoad;
    }


    public interface callback {
        void get(ReportListModel list);

        void failure(Throwable t);
    }
}

ViewModel

ViewModel

public class ReportsListViewModel extends ViewModel {

    private static final int PAGE_SIZE = 10;
    private Executor executor = Executors.newFixedThreadPool(5);
    public LiveData<PagedList<ReportItemModel>> list;
    private List<Call<?>> compositeDisposable = new ArrayList<>();
    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<String> 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<>(sourceFactory, config).build();

        isErrorMessageVisible = new ObservableBoolean(false);
        errorMessage = new ObservableField<>("");
        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<NetworkState> getNetworkState() {
        return Transformations.switchMap(sourceFactory.getDataSourceLiveData(), ReportsDataSource::getNetworkState);
    }

    public LiveData<NetworkState> 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);
    }
}

PageListAdapter

PageListAdapter

public class ReportListAdapter extends PagedListAdapter<ReportItemModel, RecyclerView.ViewHolder> {

    public static final DiffUtil.ItemCallback<ReportItemModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<ReportItemModel>() {

        @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() && 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 && 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 && 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();
        }
    }
}

片段:

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 -> {
            if (adapter.getCurrentList() != null) {
                if (adapter.getCurrentList().size() > 0) {
                    binding.usersSwipeRefreshLayout.setRefreshing(networkState != null && 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 {

    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="android.view.View" />

        <variable
            name="viewModel"
            type="dasarahalli.portal.adapters.paging.reports.ReportsListViewModel" />
    </data>


    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

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

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:orientation="vertical"
            android:padding="8dp">

            <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}" />

            <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}" />

            <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="@{() -> viewModel.retry()}"
                android:text="RETRY"
                android:visibility="@{viewModel.isRetryButtonVisible ? View.VISIBLE : View.GONE}" />

        </LinearLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>


推荐答案

在上面的代码中,您看到我没有没有在 onBindViewHolder 下调用 getitem ,但是一旦我请求getItem(itemPostion),它全部开始工作了,应该是

In the above code as you can see I didn't have called getitem under onBindViewHolder but once after I requested for getItem(itemPostion) it all started working has it supposed to be

演示项目:

androidx-paging-library-demo-java

这篇关于PageKeyedDataSource loadAfter不会触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆