android - 为 RecyclerView 片段实现 ListAdapter
问题描述
我已经用普通的ViewAdapter成功地完成了这项工作,但我似乎无法让它与ListAdapter一起工作。
这是我完成大部分工作的片段:
class CrimeListFragment: Fragment() {
//Required interface for hosting activities
interface Callbacks {
fun onCrimeSelected(crimeId: UUID)
}
private var callbacks: Callbacks? = null
private lateinit var crimeRecyclerView: RecyclerView
private val crimeListViewModel: CrimeListViewModel by lazy {
ViewModelProviders.of(this).get(CrimeListViewModel::class.java)
}
override fun onAttach(context: Context) {
super.onAttach(context)
callbacks = context as Callbacks?
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_crime_list, container, false)
crimeRecyclerView =
view.findViewById(R.id.crime_recycler_view) as RecyclerView
crimeRecyclerView.layoutManager = LinearLayoutManager(context)
crimeRecyclerView.adapter = CrimeListAdapter(emptyList())
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
crimeListViewModel.crimeListLiveData.observe(
viewLifecycleOwner,
Observer { crimes ->
crimes?.let {
Log.i(TAG, "Got crimes ${crimes.size}")
updateUI(crimes)
}
}
)
}
override fun onDetach() {
super.onDetach()
callbacks = null
}
private fun updateUI(crimes: List<Crime>) {
crimeRecyclerView.adapter = CrimeListAdapter(crimes)
}
companion object {
fun newInstance(): CrimeListFragment {
return CrimeListFragment()
}
}
private inner class CrimeHolder(view: View)
: RecyclerView.ViewHolder(view), View.OnClickListener {
private lateinit var crime: Crime
private val titleTextView = itemView.findViewById<TextView>(R.id.crime_title)
private val dateTextView = itemView.findViewById<TextView>(R.id.crime_date)
private val solvedImageView = itemView.findViewById<ImageView>(R.id.crime_solved)
init {
itemView.setOnClickListener(this)
}
fun bind(crime: Crime) {
this.crime = crime
titleTextView.text = crime.title
dateTextView.text = crime.date.toString()
solvedImageView.visibility = if(crime.isSolved) {
View.VISIBLE
} else {
View.GONE
}
}
override fun onClick(v: View) {
callbacks?.onCrimeSelected(crime.id)
}
}
private inner class CrimeListAdapter(var crimes: List<Crime>)
: ListAdapter<Crime, CrimeHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CrimeHolder {
val view =
layoutInflater.inflate(R.layout.list_item_crime, parent, false)
return CrimeHolder(view)
}
override fun onBindViewHolder(holder: CrimeHolder, position: Int) {
holder.bind(crimes[position])
}
}
private inner class DiffCallback: DiffUtil.ItemCallback<Crime>() {
override fun areItemsTheSame(oldItem: Crime, newItem: Crime): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Crime, newItem: Crime): Boolean {
return oldItem == newItem
}
}
}
这是片段的视图模型:
class CrimeListViewModel: ViewModel() {
private val crimeRepository = CrimeRepository.get()
val crimeListLiveData = crimeRepository.getCrimes() //returns LiveData<List<Crime>>
}
Android 文档中有关于ListAdapter的内容:
虽然使用LiveData是向适配器提供数据的一种简单方法,但这不是必需的 - 您可以在新列表可用时使用submitList(List) 。
我应该在每次更新 UI 时提交一个新列表,而不是创建一个新的ListAdapter对象。但
crimeRecyclerView.adapter
没有任何.submitList()
作用。那么如何传递新列表呢?LiveData对我来说仍然是新的,所以我对此不太清楚。我已经观察到存储在我的视图模型中的LiveData 。那么这次我观察什么呢?还是我只是将代码添加到我现有的Observer中?
最后,当我在这种状态下运行代码时,手机显示一个空的RecyclerView。只
UpdateUI()
被调用,没有任何CrimeListAdapter
函数被调用。我不确定这是一个真正的问题还是上述问题的结果。
解决方案
1.我应该在每次更新 UI 时提交一个新列表,而不是创建一个新的 ListAdapter 对象。但是 crimeRecyclerView.adapter 没有 .submitList() 函数。那么如何传递新列表呢?
crimeRecyclerView.adapter
返回 RecyclerView.Adapter 类型
submitList()
是ListAdapter的一个方法,是RecyclerView.Adapter的子类
在调用该方法之前,您需要从超类转换为子类,就像这样。
(crimeRecyclerView.adapter as CrimeListAdapter).submitList(crimes)
2.LiveData 对我来说仍然是新的,所以我对此不太清楚。我已经观察到存储在我的视图模型中的 LiveData。那么这次我观察什么呢?还是我只是将代码添加到我现有的观察者?
你这部分的代码很好,不需要做更多。
3.最后当我在这种状态下运行代码时,手机显示一个空的RecyclerView。只有 UpdateUI() 被调用,CrimeListAdapter 的任何函数都没有被调用。我不确定这是一个真正的问题还是上述问题的结果。
使用 ListAdapter 最好的部分是您不需要向构造函数提供数据列表(在您的情况下是犯罪)。
回到您的代码,您需要更改 3 件事。
// crimeRecyclerView.adapter = CrimeListAdapter(emptyList())
crimeRecyclerView.adapter = CrimeListAdapter()
和
// crimeRecyclerView.adapter = CrimeListAdapter(crimes)
(crimeRecyclerView.adapter as CrimeListAdapter).submitList(crimes)
和
//private inner class CrimeListAdapter(var crimes: List<Crime>) :
// ListAdapter<Crime, CrimeHolder>(DiffCallback()) {
//
// override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CrimeHolder {
// val view = layoutInflater.inflate(R.layout.list_item_crime, parent, false)
// return CrimeHolder(view)
// }
//
// override fun onBindViewHolder(holder: CrimeHolder, position: Int) {
// holder.bind(crimes[position])
// }
//}
private inner class CrimeListAdapter : ListAdapter<Crime, CrimeHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CrimeHolder {
val view = layoutInflater.inflate(R.layout.list_item_crime, parent, false)
return CrimeHolder(view)
}
override fun onBindViewHolder(holder: CrimeHolder, position: Int) {
holder.bind(getItem(position))
}
}
推荐阅读
- python - 损坏的 DAG:[/airflow/dags/a.py] 无法解密 login=None 的“额外”参数,缺少 FERNET_KEY 配置
- c# - 在 Pylon 中加载和保存 pfs 文件
- css - 如何更改 mat-slide-toggle 的颜色属性/覆盖组件的 CSS?
- java - 自动发送安卓短信
- android - Android NDK:内部错误:armeabi ABI 应该只有一个架构定义。成立:
- c# - 如何在 Xamarin for iOS 中显示具有不同导航的 viewController
- powershell - 没有源目录的复制项
- iis - 无法在本地运行 Kentico 解决方案
- c++ - 处理 C++ 继承时的最佳实践
- jmeter - 当我们增加用户数量时,为什么平均响应时间会减少?