关于Paging
使用 Paging 库,您可以轻松在应用的 RecyclerView 中妥善地逐步加载数据。
要添加 Paging 的依赖项,您必须将 Google Maven 代码库添加到项目中。有关详情,请阅读 Google 的 Maven 代码库。
在应用或模块的 build.gradle 文件中添加所需工件的依赖项:
dependencies {
def paging_version = "2.1.1"
implementation "androidx.paging:paging-runtime:$paging_version" // For Kotlin use paging-runtime-ktx
// alternatively - without Android dependencies for testing
testImplementation "androidx.paging:paging-common:$paging_version" // For Kotlin use paging-common-ktx
// optional - RxJava support
implementation "androidx.paging:paging-rxjava2:$paging_version" // For Kotlin use paging-rxjava2-ktx
}
创建项目
- 创建好项目之后添加上述依赖,由于使用到了Room数据库,添加对应依赖,并进行sync同步:
dependencies {
...
def paging_version = "2.1.1"
implementation "androidx.paging:paging-runtime:$paging_version"
def room_version = "2.2.3"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
}
- 制作界面(一个列表两个按键分别生成数据和清空数据)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.9" />
<Button
android:id="@+id/buttonPopulate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生成"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/buttonClear"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline" />
<Button
android:id="@+id/buttonClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清空"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/buttonPopulate"
app:layout_constraintTop_toTopOf="@+id/guideline" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycleView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- 制作列表单元界面cell
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- 创建Entity、Dao、Database类
Student.class:
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "student_table")
public class Student {
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = "student_number")
private int student_number;
//setter and getter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getStudent_number() {
return student_number;
}
public void setStudent_number(int student_number) {
this.student_number = student_number;
}
}
StudentDao
import androidx.paging.DataSource;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
@Dao
public interface StudentDao {
@Insert
void insertStudents(Student... students); //插入数据,允许多个数据,无需具体实现
@Query("DELETE FROM STUDENT_TABLE")
void clearAllStudents();
@Query("SELECT * FROM STUDENT_TABLE ORDER BY id")
//LiveData<List<Student>> getAllStudentsLive(); //之前返回LiveData类型,这次引入Paging则用下面所述方法
DataSource.Factory<Integer, Student> getAllStudents();
}
Database抽象类
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
@Database(entities = {Student.class},version = 1,exportSchema = false) //三个参数(Entity,版本,导出模式)
abstract class StudentsDatabase extends RoomDatabase {
//制作singleton类型数据
private static StudentsDatabase instance;
//静态方法
static synchronized StudentsDatabase getInstance(Context context) { //传参数Context在MainActivity中进行传递
if (instance ==null) {
instance = Room.databaseBuilder(context,StudentsDatabase.class,"students_database")
.build();
}
return instance;
}
//获取Dao
abstract StudentDao getStudentsDao();
}
- 编写Adapter适配器类MyPagedAdapter继承PagedListAdapter
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.paging.PagedListAdapter;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
public class MyPagedAdapter extends PagedListAdapter<Student, MyPagedAdapter.MyViewHolder> {
public MyPagedAdapter() {
super(new DiffUtil.ItemCallback<Student>() {
@Override
public boolean areItemsTheSame(@NonNull Student oldItem, @NonNull Student newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull Student oldItem, @NonNull Student newItem) {
return oldItem.getStudent_number() == newItem.getStudent_number();
}
});
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.cell,parent,false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Student student = getItem(position);
//判空(防止容器 > 内容数据)
if (student ==null) {
holder.textView.setText("loading"); //数据等待加载时显示Loading
} else {
holder.textView.setText(String.valueOf(student.getStudent_number()));
}
}
//编写ViewHolder类 关联cell
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
}
}
- 主界面逻辑代码
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.paging.LivePagedListBuilder;
import androidx.paging.PagedList;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
//声明变量
RecyclerView recyclerView;
Button buttonPopulate,buttonClear;
StudentDao studentDao;
StudentsDatabase studentsDatabase;
MyPagedAdapter pagedAdapter;
LiveData<PagedList<Student>> allStudentsLivePaged; //数据获取的变量
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycleView);
pagedAdapter = new MyPagedAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
recyclerView.setAdapter(pagedAdapter);
//获取studentDao
studentsDatabase = StudentsDatabase.getInstance(this);
studentDao = studentsDatabase.getStudentsDao();
//数据获取
allStudentsLivePaged = new LivePagedListBuilder<>(studentDao.getAllStudents(),5) //两个参数:数据来源,分页加载的数据数量
.build();
allStudentsLivePaged.observe(this, new Observer<PagedList<Student>>() {
@Override
public void onChanged(final PagedList<Student> students) { //LiveData类型的观察
pagedAdapter.submitList(students); //传递
students.addWeakCallback(null, new PagedList.Callback() {
@Override
public void onChanged(int position, int count) { //向数据源请求数据加载时
Log.d("myLog", "onChanged: " + students); //通过myLog观察
}
@Override
public void onInserted(int position, int count) {
}
@Override
public void onRemoved(int position, int count) {
}
});
}
});
//按钮的点击事件
buttonPopulate = findViewById(R.id.buttonPopulate);
buttonClear = findViewById(R.id.buttonClear);
buttonPopulate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Student[] students = new Student[1000];
for (int i = 0;i < 1000;i++) {
Student student = new Student();
student.setStudent_number(i);
students[i] = student;
}
new InsertAsyncTask(studentDao).execute(students);
}
});
buttonClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new ClearAsyncTask(studentDao).execute();
}
});
}
//按钮进行AsyncTask异步处理
static class InsertAsyncTask extends AsyncTask<Student,Void,Void> {
StudentDao studentDao;
public InsertAsyncTask(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Override
protected Void doInBackground(Student... students) {
studentDao.insertStudents(students);
return null;
}
}
static class ClearAsyncTask extends AsyncTask<Void,Void,Void> {
StudentDao studentDao;
public ClearAsyncTask(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Override
protected Void doInBackground(Void... voids) {
studentDao.clearAllStudents();
return null;
}
}
}
运行项目
下拉直至容器内容加载过度时,会显示loading