[英]How to use Adapter.notifyDataSetChanged() in MainActivity?
我已经创建了一个带有 RecyclerView 的列表,并且希望现在能够在 MainActvitiy 中更新它,上下文来自一个来自 MainActivity 的片段,但我就是不能使用
Adapter.notifyDataSetChanged()
在它工作的片段中,它更新列表,我如何从片段中获取上下文 bz 我如何在 MainActvitiy 中使用Adapter.notifyDataSetChanged()
?
适配器.kt
class Adapter(val context: Context) : RecyclerView.Adapter<Adapter.ViewHolder>() {
var dataList = emptyList<VolvicsModel>()
internal fun setDataList(dataList: List<VolvicsModel>) {
this.dataList = dataList
notifyDataSetChanged()
}
class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
var title : TextView
var name : TextView
var image : ImageView
var liters: TextView
var quantity: TextView
init {
title = itemView.findViewById(R.id.textView9)
image = itemView.findViewById(R.id.imageView)
liters = itemView.findViewById(R.id.liters)
quantity = itemView.findViewById(R.id.quantity)
name = itemView.findViewById(R.id.name)
itemView.setOnLongClickListener {
Toast.makeText(itemView.context, "${title.text}", Toast.LENGTH_SHORT).show()
return@setOnLongClickListener true
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.card_user_volvics, parent, false)
return ViewHolder(view)
}
override fun getItemCount() = dataList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val data = dataList[position]
holder.title.text = data.name
holder.liters.text = data.liters
holder.quantity.text = data.quantity
holder.name.text = data.sort
Glide.with(context).load(data.image).into(holder.image)
}
}
数据列表.kt
var dataList = mutableListOf<VolvicsModel>()
片段.kt
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.fragment_your_volvics, container, false)
recycleView = view.findViewById(R.id.recyclerview_your_volvics)
recycleView.layoutManager = GridLayoutManager(view.context, 2)
recycleView.setHasFixedSize(true)
VolvicsAdapter = Adapter(view.context)
recycleView.adapter = VolvicsAdapter
progressBar = view.findViewById(R.id.progressBar)
LinearLayout = view.findViewById(R.id.linearLayout)
database = FirebaseDatabase.getInstance().getReference("Userdata").child(uid!!)
database.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if(snapshot.child("volvics").exists()) {
dataRequest()
Adapter.notifyDataSetChanged()
database.removeEventListener(this)
}
}
override fun onCancelled(error: DatabaseError) {
println("Error")
}
})
return view
}
通常,全局可访问的可变状态(如您的dataList
)使用起来很危险。 它引入了挑战,就像您观察到的那样,它可以从应用程序的其他地方更改,而其他组件不知道它已更改。 与其尝试在 Activity 和 Fragment 之间添加更多的依赖关系,还不如尝试修复原始问题。
更好的选择是将数据存储在Activity ViewModel中,Activity 和 Fragment 都可以访问以触发更改,并且 Fragment 可以观察和响应。 当片段被通知数据更改时,它可以更新其适配器中的数据。
这是一个示例,其中 Activity ViewModel 包含数据(字符串)列表,并且 Activity 和 Fragment 都可以将内容添加到该列表中。 Fragment 观察列表并在数据发生变化时更新适配器。 这使用ListAdapter ,因此不需要调用notifyDataSetChanged
。
查看模型
ViewModel 包含您要显示的数组。 它是私有数据,需要显示该数据的东西可以观察 LiveData。 任何想要更改该数据的东西都应该通过这里。
class MainViewModel : ViewModel() {
private val dataListLiveData = MutableLiveData<List<String>>()
val dataList: LiveData<List<String>>
get() = dataListLiveData
// This is the source of truth - anything that changes it should go through
// the ViewModel so that its observers can be notified
private val myData = mutableListOf<String>()
// Anything that triggers a change to the data, either by calling an API
// like firebase or locally editing it, should call through the ViewModel
fun addEntry(e: String) {
myData.add(e)
dataListLiveData.postValue(myData)
}
fun getDataFromFirebase() {
// asynchronous calls to Firebase could be triggered here, and when
// complete they can add data to the list and post the updated list
// to the LiveData
}
}
活动
这里的 Activity 获取 ViewModel 并在协程中延迟添加一些数据。 此处的 ViewModel 实例将与 Fragment 获得的实例相同。
class MainActivity : AppCompatActivity() {
private val model: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.setReorderingAllowed(true)
.add(R.id.fragment, ListFragment())
.commit()
}
// slowly add data to the list, one entry every 2 seconds
lifecycleScope.launch {
for(i in 1..5) {
delay(2000)
model.addEntry("Data $i from the activity")
}
}
}
}
分段
Fragment 检索 Activity ViewModel 并观察 LiveData。 当数据发生变化时,Fragment 会更新适配器/视图。 Fragment 还可以通过调用 ViewModel 上的方法来更新数据。
class ListFragment : Fragment() {
private var _binding: FragmentListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val model: MainViewModel by activityViewModels()
val adapter = MyListAdapter()
binding.dataList.adapter = adapter
binding.dataList.layoutManager = LinearLayoutManager(requireContext())
// The fragment observes the list LiveData in the
// ViewModel and updates the adapter when new data
// is posted
model.dataList.observe(viewLifecycleOwner) { newList ->
// put it in the adapter. Using ListAdapter means
// we don't need to call notifyDataSetChanged, it figures
// that out automatically
adapter.submitList(newList.toList())
}
lifecycleScope.launch {
for(i in 1..3) {
delay(1200)
model.addEntry("Data $i from the fragment")
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
适配器
这里的adapter继承自ListAdapter,所以有新数据时可以使用submitList
,不需要手动调用notifyDataSetChanged
。
class MyListAdapter : ListAdapter<String, MyListAdapter.ViewHolder>(DIFF_CALLBACK) {
class ViewHolder(val binding: ListRowBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ListRowBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.binding.item.text = getItem(position)
}
companion object {
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<String>() {
override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem == newItem
}
}
}
}
摇篮
Gradle 文件依赖项是非常标准的,但如果您缺少-ktx
那些,则上述某些方法将不存在。 您还需要激活视图绑定才能使用此示例。
android {
...
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.activity:activity-ktx:1.4.0'
implementation 'androidx.fragment:fragment-ktx:1.4.1'
}
XML
activity_main.xml
- 包含名为R.id.fragment
的FragmentContainer
的活动布局 - 映射到 ActivityMainBindingfragment_list.xml
- 包含名为R.id.data_list
的RecyclerView
的片段布局 - 映射到 FragmentListBindinglist_row.xml
- 包含名为R.id.item
的TextView
的 RecyclerView 行布局 - 映射到 ListRowBinding
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.