Pagingページングライブラリの基本的な使用


転載はリンクを明記してください:https://blog.csdn.net/feather_wch/article/details/88744255
Android paging libraryはページングライブラリです.
  • は必要に応じてデータをロードして展示し、ネットワークトラフィックとシステム資源の損失
  • を避ける.
    Pagingページングライブラリの基本的な使用
    バージョン番号:2019-03-24(1:30)
    文書ディレクトリ
  • Pagingページングライブラリの基本使用
  • 概要
  • 依存追加
  • データベースにデータをロード
  • RxJava形式
  • placeholders
  • paging configuration
  • invalidate
  • data source type
  • カスタム
  • Consider how content updates work
  • Provide data mapping
  • 参考資料
  • 概要
    1、ページングロードの前世今生
  • ページングロードには、2つのモード
  • があります.
  • 従来のプルアップロードよりも多くのページング効果
  • 無限スクロールのページング効果
  • 2、無限スクロールのこのような無感知のページング効果は間違いなく最も良い
    Paging libraryはこのようなページングライブラリです
    1、Paging libraryのコアコンポーネントはPagedListである
  • は、appに必要なデータ(一部を先にロード)
  • をページ別にロードすることができる.
  • ロードされたデータの変化がある場合、新しいPagedlist LiveData RxJava2
  • に更新される.
    依存関係の追加
    1.Pagingの依存追加(build.gradle)
        /*==========================================
        * Paging   
        *=============================================*/
        implementation "android.arch.paging:runtime:1.0.1"
        implementation "android.arch.paging:rxjava2:1.0.1"     // Paging RxJava2     
    

    データベースへのデータのロード
    1、ActivityでRecyclerViewを使用し、データの傍受を設定する
    public class DailyPlanActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 1. RecyclerView + Adapter,    DataBinding      
            final GoalListAdapter goalListAdapter = new GoalListAdapter(this);
            RecyclerView recyclerView = findViewById(R.id.goal_recyclerview);
            // 【LayoutManager!!!!!】
            recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
            // adapter
            recyclerView.setAdapter(goalListAdapter);
            // 2. ViewModel  LiveData,        PagedListAdapter submitList
            GoalViewModel goalViewModel = ViewModelProviders.of(this, new GoalViewModel.GoalViewModelFactory(this))
                    .get(GoalViewModel.class);
            goalViewModel.getGoalList().observe(this, new Observer<PagedList<Goal>>() {
                @Override
                public void onChanged(@Nullable PagedList<Goal> goals) {
                    // submitList            
                    goalListAdapter.submitList(goals);
                }
            });
        }
    }
    

    Activityのレイアウト
    
    <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:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".DailyPlanActivity">
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/goal_recyclerview"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
    
    android.support.constraint.ConstraintLayout>
    

    2、RecyclerViewのAdapterは、PagedListAdapterから引き継ぐ必要があり、4つの部分の仕事をする必要がある
  • onCreateViewHolder()-ViewHolder
  • を作成
  • public static class GoalViewHolder extends RecyclerView.ViewHolder
  • onBindView()-データとUIのバインド
  • private static DiffUtil.ItemCallback DIFF_CALLBACK新旧データの差異比較
  • public class GoalListAdapter extends PagedListAdapter<Goal, GoalListAdapter.GoalViewHolder>{
        Context mContext;
    
        public GoalListAdapter(Context context) {
            super(DIFF_CALLBACK);
            mContext = context;
        }
    
        @NonNull
        @Override
        public GoalViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(mContext);
            GoalItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.recyclerview_goal_item_layout, parent, false);
            return new GoalViewHolder(binding.getRoot());
        }
    
        @Override
        public void onBindViewHolder(@NonNull GoalViewHolder holder, int position) {
            /**======================================
             * 1、【      】
             *===============================================*/
            GoalItemBinding binding = DataBindingUtil.getBinding(holder.itemView);
            // 1.   User
            Goal goal = getItem(position);
            binding.setGoal(goal);
            // 2.       
            binding.executePendingBindings();
        }
    
        public static class GoalViewHolder extends RecyclerView.ViewHolder{
            public GoalViewHolder(View itemView) {
                super(itemView);
            }
        }
    
        /**=====================================
         * DiffUtil         ,      
         *====================================*/
        private static DiffUtil.ItemCallback<Goal> DIFF_CALLBACK =
                new DiffUtil.ItemCallback<Goal>() {
                    @Override
                    public boolean areItemsTheSame(Goal oldGoal, Goal newGoal) {
                        return oldGoal.getId() == newGoal.getId();
                    }
    
                    @Override
                    public boolean areContentsTheSame(Goal oldGoal,
                                                      Goal newGoal) {
                        return oldGoal.equals(newGoal);
                    }
                };
    }
    
    

    レイアウト
    
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data class="com.hao.featherdailyplan.GoalItemBinding">
            <variable
                name="goal"
                type="com.hao.architecture.Goal"/>
        data>
        <android.support.constraint.ConstraintLayout
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            tools:context="com.hao.architecture.DailyPlanActivity">
    
            <ImageView
                android:id="@+id/goal_icon_img"
                android:layout_width="80dp"
                android:layout_height="80dp"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                tools:src="@drawable/ic_launcher_background"
                android:layout_marginLeft="10dp"/>
    
            <ImageView
                android:id="@+id/goal_start_img"
                android:layout_width="80dp"
                android:layout_height="80dp"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                tools:src="@drawable/ic_launcher_background"
                android:layout_marginRight="10dp">
    
            ImageView>
    
            <TextView
                android:id="@+id/goal_total_hours_txt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toTopOf="@+id/goal_today_hours_txt"
                app:layout_constraintEnd_toStartOf="@+id/goal_start_img"
                tools:text="72.7h"
                android:text='@{String.valueOf(goal.goaltime) + "h"}'
                app:layout_constraintVertical_chainStyle="packed"
                android:layout_marginEnd="10dp"/>
    
            <TextView
                android:id="@+id/goal_today_hours_txt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/goal_total_hours_txt"
                tools:text="3.7h"
                app:layout_constraintEnd_toStartOf="@+id/goal_today_hours_indivitual_txt"/>
    
            <TextView
                android:id="@+id/goal_today_hours_indivitual_txt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toTopOf="@+id/goal_today_hours_txt"
                app:layout_constraintBottom_toBottomOf="@+id/goal_today_hours_txt"
                app:layout_constraintEnd_toStartOf="@+id/goal_today_expected_hours_txt"
                tools:text="/"/>
    
            <TextView
                android:id="@+id/goal_today_expected_hours_txt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toTopOf="@+id/goal_today_hours_txt"
                app:layout_constraintBottom_toBottomOf="@+id/goal_today_hours_txt"
                tools:text="7.7h"
                app:layout_constraintEnd_toEndOf="@+id/goal_total_hours_txt"/>
    
            <TextView
                android:id="@+id/goal_timer_txt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                tools:text="00:10:49"
                app:layout_constraintStart_toEndOf="@id/goal_icon_img"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toTopOf="@+id/goal_title_txt"
                android:layout_marginStart="10dp"/>
    
            <TextView
                android:id="@+id/goal_title_txt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                tools:text="  2019"
                app:layout_constraintStart_toStartOf="@+id/goal_timer_txt"
                app:layout_constraintTop_toBottomOf="@+id/goal_timer_txt"
                app:layout_constraintBottom_toBottomOf="parent"
                android:text="@{goal.title}"/>
        android.support.constraint.ConstraintLayout>
    
    layout>
    

    3、GoalViewModel:内部構造LiveData> mGoalList
    public class GoalViewModel extends ViewModel{
        /**===================================
         * 1、    ,  LiveData>
         *====================================*/
        private GoalDao mGoalDao;
        private LiveData<PagedList<Goal>> mGoalList;
        private static final int PAGE_SIZE = 10;
    
        public LiveData<PagedList<Goal>> getGoalList() {
            if(mGoalList == null){
                mGoalList = new LivePagedListBuilder(mGoalDao.getGoalListFactory(), new PagedList.Config.Builder()
                        .setPageSize(PAGE_SIZE)                         //         
                        .setInitialLoadSizeHint(PAGE_SIZE)              //        
                        .setPrefetchDistance(PAGE_SIZE)
                        .setEnablePlaceholders(true)
                        .build()).build();
            }
            return mGoalList;
        }
    
        /**=============================
         * 2、  “  ” ViewModel     
         *=============================*/
        @SuppressLint("StaticFieldLeak")
        private Context mContext;
        public GoalViewModel(Context context){
            this.mContext = context;
            this.mGoalDao = GoalDatabase.getInstance(mContext).getGoalDao();
        }
        public static class GoalViewModelFactory extends ViewModelProvider.NewInstanceFactory{
            private Context mContext;
            public GoalViewModelFactory(Context context){
                mContext = context;
            }
            @NonNull
            @Override
            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                return (T) new GoalViewModel(mContext);
            }
        }
    
    }
    

    4、Roomデータベース関連:Goal、GoalDao、GoalDabase
    GoalDao:データのクエリーを提供します.コアはDataSource.Factoryを提供することです.
    @Dao
    public interface GoalDao {
    
        @Query("select * from goal")
        Flowable<Goal> queryGoalList();
    
        @Query("select * from goal")
        DataSource.Factory<Integer, Goal> getGoalListFactory();
    
        @Insert
        void insertGoal(Goal... goals);
    
        @Delete
        void deleteGoal(Goal goal);
    
        @Update
        void updateGoal(Goal goal);
    }
    
    

    Goal:データエンティティ
    @Entity
    public class Goal {
        @PrimaryKey
        private int id;
        private int goaltype; // 0:     1:    
        private int analyticsGoalType; //      ,                、  、  、  
        private String title; //   
        private String description; //   
        private long goaltime; //       
        private String goalImgUrl; //      url
        private int goalImgColor; //      
    
        @Embedded(prefix = "begin")
        private Date beginDate;
        @Embedded(prefix = "bend")
        private Date endDate;
    
        public Goal(int id, int goaltype, int analyticsGoalType, String title, String description, long goaltime, String goalImgUrl, int goalImgColor, Date beginDate, Date endDate) {
            this.id = id;
            this.goaltype = goaltype;
            this.analyticsGoalType = analyticsGoalType;
            this.title = title;
            this.description = description;
            this.goaltime = goaltime;
            this.goalImgUrl = goalImgUrl;
            this.goalImgColor = goalImgColor;
            this.beginDate = beginDate;
            this.endDate = endDate;
        }
    
        // xxx
    }
    

    GoalDatabase:データベース
    @Database(entities = {Goal.class}, version = 1, exportSchema = false)
    //     ,    version
    public abstract class GoalDatabase extends RoomDatabase
    {
        private static GoalDatabase INSTANCE;
        private static final Object sLock = new Object();
    
        public abstract GoalDao getGoalDao();
    
        public static GoalDatabase getInstance(Context context) {
            synchronized (sLock) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(), GoalDatabase.class, "goal.db")
                            .build();
                }
                return INSTANCE;
            }
        }
    }
    
    

    RxJava形式
    1、LiveDataをObservableまたはFlowableに置き換える
    RxPagedListBuilderはbuildObservableを呼び出して構築する
    public class GoalViewModel extends ViewModel{
        private Observable<PagedList<Goal>> mGoalList;
    
        public Observable<PagedList<Goal>> getGoalList() {
            if(mGoalList == null){
              // RxPagedListBuilder   
                mGoalList = new RxPagedListBuilder(xxx).buildObservable();
            }
            return mGoalList;
        }
    }
    

    使用
    goalViewModel.getGoalList()
                 .subscribe(flowableList -> goalListAdapter.submitList(flowableList));
    

    placeholders
    paging configuration
    invalidate
    data source type
    ツールバーの
    Consider how content updates work
    Provide data mapping
    参考資料
  • Android公式アーキテクチャコンポーネントPaging:ページングライブラリの設計美学
  • Paging公式文書
  • Android JetpackアーキテクチャコンポーネントのPaging(使用、ソース編)