基于Android官方Paging Library的RecyclerView分页加载框架



我之前写了一篇RecyclerView分页加载机制的文章,是基于Android官方的AsyncListUtil实现的,详情见附录文章1。现在再介绍一种RecyclerView分页加载框架:Android Paging Library。


Android Paging Library是Android官方support-v7支持包中专门做的分页框架,详细文档见谷歌官方文档附录2页面。我写这篇文章时候Paging Library的版本是1.0.0-alpha3。


使用Android Paging Library首先需要在gradle添加引用:

implementation 'android.arch.paging:runtime:1.0.0-alpha3'



下面我写示例代码做一个简单的演示:

1. package
2.   
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17. import
18. import
19. import
20.   
21. import
22. import
23. import
24.   
25. public class MainActivity extends
26. private
27. private
28.   
29. private
30. private
31.   
32. private
33.   
34. @Override
35. protected void
36. super.onCreate(savedInstanceState);  
37.         setContentView(R.layout.activity_main);  
38.   
39. new
40.         makePageList();  
41.   
42.         mRecyclerView = findViewById(R.id.recycler_view);  
43.   
44. new LinearLayoutManager(this);  
45.         mLayoutManager.setOrientation(LinearLayout.VERTICAL);  
46.         mRecyclerView.setLayoutManager(mLayoutManager);  
47.   
48. new
49.         mRecyclerView.setAdapter(mAdapter);  
50.   
51.         mAdapter.setList(mPagedList);  
52.   
53. new
54. private int
55.   
56. @Override
57. public void onScrollStateChanged(RecyclerView recyclerView, int
58. super.onScrollStateChanged(recyclerView, newState);  
59.   
60.                 lastPos = mLayoutManager.findLastVisibleItemPosition();  
61.   
62. //触发Android Paging的加载事务逻辑。
63.             }  
64.         });  
65.     }  
66.   
67. private void
68. new
69. 3) //分页数据的数量。在后面的DataSource之loadRange中,count即为每次加载的这个设定值。
70. 5) //初始化时候,预取数据数量。
71. false)  
72.                 .build();  
73.   
74. new
75.                 .setConfig(mPagedListConfig)  
76.                 .setDataSource(mDataSource)  
77. new BackgroundThreadTask()) //初始化阶段启用
78. new MainThreadTask()) //初始化阶段启动
79.                 .build();  
80.     }  
81.   
82. private class BackgroundThreadTask implements
83. public
84. this.execute(new
85. @Override
86. public void
87. ”BackgroundThreadTask”, “run”);  
88.                 }  
89.             });  
90.         }  
91.   
92. @Override
93. public void execute(@NonNull
94.             runnable.run();  
95.         }  
96.     }  
97.   
98. private class MainThreadTask implements
99. public
100. this.execute(new
101. @Override
102. public void
103. ”MainThreadTask”, “run”);  
104.                 }  
105.             });  
106.         }  
107.   
108. @Override
109. public void execute(@NonNull
110.             runnable.run();  
111.         }  
112.     }  
113.   
114. private class MyDataSource extends
115.   
116. @Override
117. public int
118. return
119.         }  
120.   
121. /
122.           注意,这里需要后台线程化。
123.          
124.           @param startPosition
125.           @param count
126.           @return
127.          /
128. @Override
129. public List<DataBean> loadRange(int startPosition, int
130. ”MyDataSource”, “loadRange:” + startPosition + “,”
131.             List<DataBean> list = loadData(startPosition, count);  
132. return
133.         }  
134.     }  
135.   
136. /
137.       假设这里需要做一些后台线程的数据加载任务。
138.      
139.       @param startPosition
140.       @param count
141.       @return
142.      /
143. private List<DataBean> loadData(int startPosition, int
144. new
145.   
146. for (int i = 0; i < count; i++) {  
147. new
148.             data.id = startPosition + i;  
149. ”zhangphil@”
150.             list.add(data);  
151.         }  
152.   
153. return
154.     }  
155.   
156. private class MyViewHolder extends
157. public
158. public
159.   
160. public
161. super(itemView);  
162.   
163.             text1 = itemView.findViewById(android.R.id.text1);  
164.             text1.setTextColor(Color.RED);  
165.   
166.             text2 = itemView.findViewById(android.R.id.text2);  
167.             text2.setTextColor(Color.BLUE);  
168.         }  
169.     }  
170.   
171. private class MyAdapter extends
172. public
173. super(mDiffCallback);  
174.         }  
175.   
176. @Override
177. public MyViewHolder onCreateViewHolder(ViewGroup parent, int
178. null);  
179. new
180. return
181.         }  
182.   
183. @Override
184. public void onBindViewHolder(MyViewHolder holder, int
185.             DataBean data = mPagedList.get(position);  
186.             holder.text1.setText(String.valueOf(position));  
187.             holder.text2.setText(String.valueOf(data.content));  
188.         }  
189.     }  
190.   
191. private DiffCallback<DataBean> mDiffCallback = new
192.   
193. @Override
194. public boolean areItemsTheSame(@NonNull DataBean oldItem, @NonNull
195. ”DiffCallback”, “areItemsTheSame”);  
196. return
197.         }  
198.   
199. @Override
200. public boolean areContentsTheSame(@NonNull DataBean oldItem, @NonNull
201. ”DiffCallback”, “areContentsTheSame”);  
202. return
203.         }  
204.     };  
205.   
206. private class
207. public int
208. public
209.     }  
210. }

package zhangphil.demo;

import android.arch.paging.PagedList; 
 import android.arch.paging.PagedListAdapter; 
 import android.arch.paging.TiledDataSource; 
 import android.graphics.Color; 
 import android.support.annotation.NonNull; 
 import android.support.v7.app.AppCompatActivity; 
 import android.os.Bundle; 
 import android.support.v7.recyclerview.extensions.DiffCallback; 
 import android.support.v7.widget.LinearLayoutManager; 
 import android.support.v7.widget.RecyclerView; 
 import android.text.TextUtils; 
 import android.util.Log; 
 import android.view.LayoutInflater; 
 import android.view.View; 
 import android.view.ViewGroup; 
 import android.widget.LinearLayout; 
 import android.widget.TextView;import java.util.ArrayList; 
 import java.util.List; 
 import java.util.concurrent.Executor;public class MainActivity extends AppCompatActivity { 
 private PagedList<DataBean> mPagedList; 
 private MyDataSource mDataSource;
private RecyclerView mRecyclerView;
private PagedListAdapter mAdapter;

private LinearLayoutManager mLayoutManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mDataSource = new MyDataSource();
    makePageList();

    mRecyclerView = findViewById(R.id.recycler_view);

    mLayoutManager = new LinearLayoutManager(this);
    mLayoutManager.setOrientation(LinearLayout.VERTICAL);
    mRecyclerView.setLayoutManager(mLayoutManager);

    mAdapter = new MyAdapter();
    mRecyclerView.setAdapter(mAdapter);

    mAdapter.setList(mPagedList);

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        private int lastPos;

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            lastPos = mLayoutManager.findLastVisibleItemPosition();

            mPagedList.loadAround(lastPos);//触发Android Paging的加载事务逻辑。
        }
    });
}

private void makePageList() {
    PagedList.Config mPagedListConfig = new PagedList.Config.Builder()
            .setPageSize(3) //分页数据的数量。在后面的DataSource之loadRange中,count即为每次加载的这个设定值。
            .setPrefetchDistance(5) //初始化时候,预取数据数量。
            .setEnablePlaceholders(false)
            .build();

    mPagedList = new PagedList.Builder()
            .setConfig(mPagedListConfig)
            .setDataSource(mDataSource)
            .setMainThreadExecutor(new BackgroundThreadTask()) //初始化阶段启用
            .setBackgroundThreadExecutor(new MainThreadTask()) //初始化阶段启动
            .build();
}

private class BackgroundThreadTask implements Executor {
    public BackgroundThreadTask() {
        this.execute(new Runnable() {
            @Override
            public void run() {
                Log.d("BackgroundThreadTask", "run");
            }
        });
    }

    @Override
    public void execute(@NonNull Runnable runnable) {
        runnable.run();
    }
}

private class MainThreadTask implements Executor {
    public MainThreadTask() {
        this.execute(new Runnable() {
            @Override
            public void run() {
                Log.d("MainThreadTask", "run");
            }
        });
    }

    @Override
    public void execute(@NonNull Runnable runnable) {
        runnable.run();
    }
}

private class MyDataSource extends TiledDataSource<DataBean> {

    @Override
    public int countItems() {
        return TiledDataSource.COUNT_UNDEFINED;
    }

    /**
     * 注意,这里需要后台线程化。
     *
     * @param startPosition
     * @param count
     * @return
     */
    @Override
    public List<DataBean> loadRange(int startPosition, int count) {
        Log.d("MyDataSource", "loadRange:" + startPosition + "," + count);
        List<DataBean> list = loadData(startPosition, count);
        return list;
    }
}

/**
 * 假设这里需要做一些后台线程的数据加载任务。
 *
 * @param startPosition
 * @param count
 * @return
 */
private List<DataBean> loadData(int startPosition, int count) {
    List<DataBean> list = new ArrayList();

    for (int i = 0; i < count; i++) {
        DataBean data = new DataBean();
        data.id = startPosition + i;
        data.content = "zhangphil@" + data.id;
        list.add(data);
    }

    return list;
}

private class MyViewHolder extends RecyclerView.ViewHolder {
    public TextView text1;
    public TextView text2;

    public MyViewHolder(View itemView) {
        super(itemView);

        text1 = itemView.findViewById(android.R.id.text1);
        text1.setTextColor(Color.RED);

        text2 = itemView.findViewById(android.R.id.text2);
        text2.setTextColor(Color.BLUE);
    }
}

private class MyAdapter extends PagedListAdapter<DataBean, MyViewHolder> {
    public MyAdapter() {
        super(mDiffCallback);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(getApplicationContext()).inflate(android.R.layout.simple_list_item_2, null);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        DataBean data = mPagedList.get(position);
        holder.text1.setText(String.valueOf(position));
        holder.text2.setText(String.valueOf(data.content));
    }
}

private DiffCallback<DataBean> mDiffCallback = new DiffCallback<DataBean>() {

    @Override
    public boolean areItemsTheSame(@NonNull DataBean oldItem, @NonNull DataBean newItem) {
        Log.d("DiffCallback", "areItemsTheSame");
        return oldItem.id == newItem.id;
    }

    @Override
    public boolean areContentsTheSame(@NonNull DataBean oldItem, @NonNull DataBean newItem) {
        Log.d("DiffCallback", "areContentsTheSame");
        return TextUtils.equals(oldItem.content, newItem.content);
    }
};

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

代码实现的功能很简单,当RecyclerView不断下滑时,就触发分页加载,把RecyclerView后续使用的数据分页加载显示出来。暂时我将现阶段对Android Paging Library技术的心得记录下来,作为我学习Android Paging Library技术的阶段性备忘录。这部分代码还有待进一步完善,Android Paging Library技术细节后续会继续跟进研究。