天天看点

Android Paging library的本地数据Demo

分页库属于架构组件(Architecture Components)的一部分,配合RecyclerView使用,主要用来实现无感分页加载。

官方文档链接为:https://developer.android.google.cn/topic/libraries/architecture/paging

本文参照官方文档来做一个简单的实现,主要分以下几步:

1、导库:

def support_version = '28.0.0-rc01'
implementation "com.android.support:appcompat-v7:$support_version"
implementation "com.android.support:recyclerview-v7:$support_version"
implementation "android.arch.paging:runtime:1.0.1"      

2、创建数据实体:

public class DataBean {
    public int id;
    public String content;

    public int getId() {
        return id;
    }

    public boolean equals(DataBean o) {
        return TextUtils.equals(content, o.content);
    }
}      

3、创建分页适配器:

//类似于RecyclerView.Adapter的写法,只不多了些一次数据比较DiffUtil.ItemCallback
public class ConcertAdapter extends PagedListAdapter<DataBean, ConcertAdapter.ConcertViewHolder> {

    private Context context;

    public ConcertAdapter(Context context) {
        super(DIFF_CALLBACK);
        this.context = context;
    }

    @NonNull
    @Override
    public ConcertViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, viewGroup, false);
        return new ConcertViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ConcertViewHolder concertViewHolder, int position) {
        DataBean dataBean = getItem(position);
        if (dataBean == null) return;
        concertViewHolder.textView.setText(dataBean.content);
    }

    class ConcertViewHolder extends RecyclerView.ViewHolder {

        TextView textView;

        ConcertViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(android.R.id.text1);
        }
    }

    private static DiffUtil.ItemCallback<DataBean> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<DataBean>() {
                @Override
                public boolean areItemsTheSame(DataBean oldItem, DataBean newItem) {
                    return oldItem.getId() == newItem.getId();
                }

                @Override
                public boolean areContentsTheSame(DataBean oldItem, @NonNull DataBean newItem) {
                    return oldItem.equals(newItem);
                }
            };

}      

4、创建模拟加载本地数据的数据源DataSource:

public class LocalTestDataSource extends PositionalDataSource<DataBean> {
    @Override
    public void loadInitial(@NonNull LoadInitialParams params,
                            final @NonNull LoadInitialCallback<DataBean> callback) {
        final int startPosition = 0;
        List<DataBean> list = buildDataList(startPosition, params.requestedLoadSize);
        //将数据回调
        callback.onResult(list, 0);
    }

    @Override
    public void loadRange(@NonNull final LoadRangeParams params,
                          @NonNull final LoadRangeCallback<DataBean> callback) {
        List<DataBean> list = buildDataList(params.startPosition, params.loadSize);
        callback.onResult(list);
    }

    private List<DataBean> buildDataList(int startPosition, int loadSize) {
        List<DataBean> list = new ArrayList<>();
        DataBean bean;
        for (int i = startPosition; i < startPosition + loadSize; i++) {
            bean = new DataBean();
            bean.id = i;
            bean.content = String.format(Locale.getDefault(), "第%d条数据", i + 1);
            list.add(bean);
        }
        return list;
    }
}      

5、创建数据源工厂,其中一个的作用是用来生产第4步的数据源:

public class DataSourceFactory
        extends DataSource.Factory<Integer, DataBean> {

    private MutableLiveData<LocalTestDataSource> mSourceLiveData =
            new MutableLiveData<>();

    @Override
    public DataSource<Integer, DataBean> create() {
        LocalTestDataSource source = new LocalTestDataSource();
        mSourceLiveData.postValue(source);
        return source;

    }
}      

6、创建ViewModel,主要作用是得到与第4步数据源(DataSource)相关联的LiveData:

public class ConcertViewModel extends ViewModel {

    private Executor myExecutor = Executors.newSingleThreadExecutor();

    private PagedList.Config myPagingConfig = new PagedList.Config.Builder()
            .setInitialLoadSizeHint(20)
            .setPageSize(10)
            .setPrefetchDistance(30)
            .setEnablePlaceholders(false)
            .build();

    private DataSource.Factory<Integer, DataBean> myConcertDataSource =
            new DataSourceFactory();

    public LiveData<PagedList<DataBean>> getConcertList() {
        return concertList;
    }

    private LiveData<PagedList<DataBean>> concertList =
            new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig)
                    .setFetchExecutor(myExecutor)
                    .build();

    //用于刷新数据
    public void invalidateDataSource() {
        PagedList<DataBean> pagedList = concertList.getValue();
        if (pagedList != null)
            pagedList.getDataSource().invalidate();
    }

}
      

7、在Activity里使用:

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private SwipeRefreshLayout swipeRefreshLayout;

    private ConcertAdapter mAdapter;
    private ConcertViewModel mViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
        recyclerView = findViewById(R.id.recyclerView);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        mAdapter = new ConcertAdapter(this);
        recyclerView.setAdapter(mAdapter);

        ViewModelProvider provider = new ViewModelProvider(this,
                new ViewModelProvider.AndroidViewModelFactory(getApplication()));
        mViewModel = provider.get(ConcertViewModel.class);
        //LiveData关联到mAdapter,并与Activity相关联
        mViewModel.getConcertList().observe(this, new Observer<PagedList<DataBean>>() {
            @Override
            public void onChanged(@Nullable PagedList<DataBean> dataBeans) {
                mAdapter.submitList(mViewModel.getConcertList().getValue());
            }
        });

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                //刷新数据
                mViewModel.invalidateDataSource();
                swipeRefreshLayout.setRefreshing(false);
            }
        });
    }
}      

相关联的布局文件R.layout.activity_main为:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.v4.widget.SwipeRefreshLayout>      

继续阅读