Kotlin中notifyDataSetChanged未生效,列表请求成功但视图无更新如何解决
问题根因
- 核心错误是你创建了两个
ItemsAdapter实例:- 先实例化了
itemsAdapter成员变量,和全局的itemsList绑定 - 给RecyclerView设置adapter时,又重新new了一个新的
ItemsAdapter实例,虽然也绑定了同一个itemsList,但你后续调用notifyDataSetChanged()的是第一个没绑定到RecyclerView的itemsAdapter,所以视图收不到更新通知
- 先实例化了
- 次要问题:你创建了分割线实例但没有添加到RecyclerView中,请求数据前也没有清空旧列表,可能会出现数据重复的情况
修复代码
class ItemsFragmentCp : Fragment(), ItemCellClickListener { private val itemsList = ArrayList<ItemModel>() private lateinit var itemsAdapter: ItemsAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_items, container, false) } override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) { super.onViewCreated(itemView, savedInstanceState) itemsAdapter = ItemsAdapter(itemsList, this) val layoutManager = LinearLayoutManager(itemView.context) val recyclerView = itemView.findViewById<RecyclerView>(R.id.recyclerView) recyclerView.setHasFixedSize(true) recyclerView.layoutManager = layoutManager // 复用已创建的layoutManager,无需重复实例化 recyclerView.adapter = itemsAdapter // 直接使用已初始化的成员变量,不要新建Adapter recyclerView.itemAnimator = DefaultItemAnimator() // 把创建的分割线添加到RecyclerView中 val dividerItemDecoration = DividerItemDecoration( recyclerView.context, layoutManager.orientation ) recyclerView.addItemDecoration(dividerItemDecoration) val activity = requireActivity() val intent = activity.intent val settingsJson = intent.getStringExtra("settingsJson").orEmpty() val settingsData = SettingsLoaderMyCompany(settingsJson) // 加载新数据前清空旧列表,避免重复累加 itemsList.clear() settingsData.getSettings().getEmails().forEach { val har = MyCompanyApiRepo() val sign = har.makeSign() prepareListData(it.getEmail(), sign) } } private fun prepareListData(email :String, sign :String) { val request = ServiceBuilder.buildService(MyCompanyApiEndpoints::class.java) val call = request.getItems(email, sign) call.enqueue(object : Callback<MyCompanyGetItemsList> { @SuppressLint("NotifyDataSetChanged") override fun onResponse(call: Call<MyCompanyGetItemsList>, response: Response<MyCompanyGetItemsList>) { if (response.isSuccessful){ val serverResponse : MyCompanyGetItemsList = response.body()!! serverResponse.items.forEach { val item = ItemModel(it.id, it.name, it.datetime) itemsList.add(item) } // 此时notify的是已绑定到RecyclerView的adapter,可正常触发视图更新 itemsAdapter.notifyDataSetChanged() } else { Log.d("Error", response.toString()) } } override fun onFailure(call: Call<MyCompanyGetItemsList>, t: Throwable) { //Toast.makeText(context, "${t.message}", Toast.LENGTH_SHORT).show() } }) } }
额外优化建议
- 性能优化可以用
notifyItemRangeInserted代替notifyDataSetChanged,避免全量刷新,还能自带列表插入动画 - 尽量用
requireContext()、requireActivity()代替可空的context、getActivity(),减少空指针风险
内容的提问来源于stack exchange,提问作者Maciej
相关产品推荐
相关产品推荐

