Android PagedList入門,只需五步Java版

最近有接到分頁的需求, 想當然準備使用監聽onScroll然後分段加載, 看到谷歌爸爸出品了Jetpack系列文章有Paging Lib於是點開看了下, 介紹的太複雜了有木有!!! room什麼鬼, ViewModel云云
也許是因爲谷歌想推room, 但是隻想了解分頁的我完全看不下去了, 簡單Demo入門, 記錄如下

新建Activity, 我使用的Fragment+ViewModel的方式, 很方便


1.導入依賴

implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'android.arch.paging:runtime:1.0.0'
implementation 'com.android.support:recyclerview-v7:27.0.2'
//可選, 我習慣使用約束佈局
implementation 'com.android.support.constraint:constraint-layout:1.1.3'

版本不同方法可能有差異, 建議初學使用我這的版本, 方便跟着後面走
首先照着後面的代碼複製一遍, 大概知道有哪些東西

2.新建實體類

class Concert {

    public int id;
    private String name;

    public Concert(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Concert{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int hashCode() {
        return id + name.hashCode();
    }

    @Override
    public boolean equals( Object obj) {
        if (obj instanceof Concert){
            boolean b = ((Concert) obj).id == id && ((Concert) obj).name.equals(name);
            return b;
        }else {
            return false;
        }
    }
}

//使用到的佈局R.layout.paged_list_fragment
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pagedlist"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="256dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

//R.layout.item_concert_list
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/name"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginBottom="8dp"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

3.新建DataSource實現類

import android.arch.paging.PositionalDataSource;
import android.support.annotation.NonNull;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class PositionPageDataSource extends PositionalDataSource<Concert> {

    @Override
    public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<Concert> callback) {
        int requestedLoadSize = params.requestedLoadSize;
        Log.d("ldo","PositionPageDataSource loadInitial "+requestedLoadSize);
        List<Concert> subList = getSubList(0, requestedLoadSize);
        callback.onResult(subList,0,40);
    }

    @Override
    public void loadRange(@NonNull LoadRangeParams params, @NonNull LoadRangeCallback<Concert> callback) {
        Log.d("ldo","PositionPageDataSource loadRange");
        callback.onResult(getSubList(params.startPosition,20));
    }

    public List<Concert> getSubList(int start, int end) {
        Log.d("ldo", "getSubList");
        ArrayList<Concert> strings = new ArrayList<>();
        for (int i = 0; i < end; i++) {
            strings.add(new Concert(start, "" + i));
        }
        return strings;
    }
}

//Factory
import android.arch.paging.DataSource;

public class DataSourceFactorty extends DataSource.Factory<Integer,Concert> {

    @Override
    public DataSource<Integer,Concert> create() {
        return new PositionPageDataSource();
    }
}

4.新建Adapter

import android.arch.paging.PagedListAdapter;
import android.support.annotation.NonNull;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


public class ConcertAdapter extends PagedListAdapter<Concert, ConcertAdapter.ViewHolder> {

    ConcertAdapter() {
        super(showDiffCallBack);
    }

    static DiffUtil.ItemCallback<Concert> showDiffCallBack = new DiffUtil.ItemCallback<Concert>() {

        @Override
        public boolean areItemsTheSame(@NonNull Concert oldItem, @NonNull Concert newItem) {
            return (oldItem).id == (newItem).id;
        }

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

        }
    };

    @NonNull
    @Override
    public ConcertAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_concert_list, null));
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Concert concert = getItem(position);
        holder.v.setText(concert.getId()+"");
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView v;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            this.v = itemView.findViewById(R.id.textView);
        }

    }
}

5.新建Fragment

import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.paging.LivePagedListBuilder;
import android.arch.paging.PagedList;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.android.displayingbitmaps.R;


public class PagedListFragment extends Fragment {

 
    
    private RecyclerView recyclerView;
    public static final int INITIALLOADSIZE = 40;//初始加載數量
    public static final int RELOADSIZE = 20;//往下滑動加載數量
    private LiveData<PagedList<Concert>> data;
    private ConcertAdapter adapter;


    public static PagedListFragment newInstance() {

        return new PagedListFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        View inflate = inflater.inflate(R.layout.paged_list_fragment, container, false);
       
        recyclerView = inflate.findViewById(R.id.recyclerView);
        return inflate;
    }
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    
        
        PagedList.Config config = new PagedList.Config.Builder()
                .setPageSize(INITIALLOADSIZE) // 分頁加載的數量
                .setEnablePlaceholders(false) // 當item爲null是否使用PlaceHolder展示
                .setInitialLoadSizeHint(RELOADSIZE) // 預加載的數量
//                    .setPrefetchDistance(5)
                .build();
        data = new LivePagedListBuilder(new DataSourceFactorty(), config).build();//可以放在ViewModel層處理
        data.observe(this, new Observer<PagedList<Concert>>() {
            @Override
            public void onChanged(@Nullable PagedList<Concert> concerts) {
                Log.d("ldo","onChanged "+concerts.size());
                adapter.submitList(concerts);//調用PagedListAdapter中的方法綁定
            }
        });
        adapter = new ConcertAdapter();
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.setAdapter(adapter);
    }

}

有一個大概認知之後簡單介紹一下各個部分

  • DataSource
    數據處理核心, 最終回調到PagedList
  • LivePagedListBuilder
    關聯DataSource和觀察數據
  • PagedList
    可以理解爲存儲數據的集合容器, 不需要我們過多關注
  • PagedListAdapter
    配合recycleview使用

需要注意的是adapter.submitList(concerts)使用父類的方法設置集合, 採取自己設置list然後notifyDataChaged的方式, PositionPageDataSource裏面的方法不會回調


不同DataSource實現類的區別

目前有三種DataSource實現方式, 上面使用的是PositionalDataSource, 想必你已經看到效果了

  • PositionalDataSource
    適用於上拉加載更多的場景, 如京東商城列表瀏覽, 知乎等
  • ItemKeyedDataSource
    適用於下一part內容依賴當前某個key來獲取, 如獲得下一part的專輯列表, 需要傳入當前歌手來獲取
  • PageKeyedDataSource
    適用於有明顯上下頁的場景, 如支持上一章,下一章跳轉可以使用此種方式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章