安卓系统中的分页
随着数据的增加,我们可能需要在应用程序中少量地显示数据。这可以确保设备的资源不被过度使用。以一个每天都会收到更新的数据库为例。我们不需要显示一周前更新的数据,除非用户要求。
一个好的方法是把数据分成 "页",然后一个 "页 "一个 "页 "地展示给用户。一些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的设置,也很简单。该库还能确保在更新列表时有良好的数据流。接下来我们将检查迁移到分页库的第三版。