如何在Android应用程序中实现分页库

199 阅读4分钟

安卓系统中的分页

随着数据的增加,我们可能需要在应用程序中少量地显示数据。这可以确保设备的资源不被过度使用。以一个每天都会收到更新的数据库为例。我们不需要显示一周前更新的数据,除非用户要求。

一个好的方法是把数据分成 "页",然后一个 "页 "一个 "页 "地展示给用户。一些restful服务如The Dog API已经采用了这种技术。在Android中,实现这样的工作流程被证明是一个繁琐的过程,如果处理得不好,会变得很混乱。

这就是分页库发挥作用的地方。它通过观察用户的滚动过程来确保数据的干净流动。

基本流程是,一旦用户接近回收器视图的末端,该库就会获取下一组数据并更新回收器视图。在本教程中,我们将把分页库集成到一个Android应用程序中。

注意:本教程在发布时使用了版本2的分页库。第3版在alpha ,不适合用于生产。

前提条件

要完成这篇文章,你将需要。

  • 安装了Android Studio
  • 对Kotlin有基本了解
  • Room库有一些经验。

第1步 - 获取启动代码

你可以在GitHub上下载本教程的启动代码。

在启动代码中,我们有一个RoomDatabase.Callback ,在创建时为我们的本地数据库填充50个用户。我们将使用这些数据来演示分页库。

第2步 - 从房间读取数据

AppDao 接口中,我们有一个函数可以从我们的数据库中读取数据。它的返回类型是DataSource.Factory<Int, User>DataSource ,一旦我们的数据被请求,它就会以页面的形式加载到PagedList

Int 告诉Room要利用一个PositionalDataSource 对象。PositionalDataSource 是在数据的大小已知并且数据是根据其位置分组的情况下使用。如果我们从网络上获取数据,我们将使用PageKeyedDataSource 。这是因为只有当我们从网络上获得响应时才知道数据大小。

第3步 - 设置适配器

适配器用于连接我们的recyclerview和分页数据。在androidkt 目录中,创建一个名为UsersAdapter 的类,并添加以下代码。

class UsersAdapter: PagedListAdapter<User, UserViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
    }
}

我们在PagedListAdapter 中推断出两种类型:每个列表项的数据类型和viewholder

在同一个文件中,创建UserViewHolder 类,并使其扩展到RecyclerView.ViewHolder 类。

class UserViewHolder(): RecyclerView.ViewHolder()

onCreateViewHolder 中添加以下内容,为我们的列表项创建viewholder

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
    return UserViewHolder(ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}

该应用程序使用ViewBinding库,所以我们将绑定类传递给viewholder。

class UserViewHolder(private val binding: ListItemBinding): RecyclerView.ViewHolder(binding.root)

onBindViewHolder ,我们负责将数据绑定到viewholder上。

添加以下代码。

override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
    holder.bind(getItem(position)!!)
}

我们使用getItem 方法来获取列表中基于位置的项目。在viewholder 类中,添加bind 函数,将数据添加到用户界面。

fun bind(user: User) {
    binding.name.text = user.name
    binding.phone.text = user.number.toString()
    binding.profile.load(user.image)
}

该应用程序已经设置了线圈图像库。我们使用load 扩展加载图片。

在一个正常的recyclerview设置中,这将是它的结束,但我们的UsersAdapter 类中仍有一个错误。PagedListAdapter 需要一个diffing 的回调。

在同一文件中,添加以下代码。

private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<User>() {
    override fun areItemsTheSame(oldItem: User, newItem: User) =
        oldItem.number == newItem.number

    override fun areContentsTheSame(oldItem: User, newItem: User) =
        oldItem == newItem

}

我们使用DiffUtil 来检查多个列表中的差异,以便在需要时进行正确的定位和动画。

我们的适配器现在已经可以使用了。

第4步 - 完成工作

在我们的MainViewModel ,获得一个数据库的实例,以便访问道。然后得到数据源并将其转换为LiveData

private val dao = AppDatabase.getDatabase(application).dao()
val users = dao.getUsers().toLiveData(pageSize = 10)

我们传入页面大小来定义有多少个项目将被一次发射出来。现在,我们的数据将有5页,或者说,将有5个PageList 对象被发射出来。

创建一个我们的适配器的实例。然后观察MainActivity 中的值。一旦有值被发射出来,就把列表提交给适配器。

viewModel.users.observe(this, { usersAdapter.submitList(it) })

创建MainActivity 的绑定对象并设置内容布局。使用绑定对象来获取recyclerview并设置适配器。

class MainActivity : AppCompatActivity() {

    private val viewModel: MainViewModel by viewModels()
    private lateinit var binding: ActivityMainBinding
    private val usersAdapter = UsersAdapter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)

        viewModel.users.observe(this, { usersAdapter.submitList(it) })
        binding.recycler.adapter = usersAdapter
        setContentView(binding.root)
    }
}

一旦你运行该应用程序,你应该得到一个用户的列表。

注意:别忘了在应用程序清单中添加互联网权限,以便下载图片。

总结

我们刚刚经历了如何在Android应用程序中实现分页库。这个设置类似于recyclerview的设置,也很简单。该库还能确保在更新列表时有良好的数据流。接下来我们将检查迁移到分页库的第三版。