Navigation跳转设置页返回后RecyclerView消失,报No adapter attached错误如何解决?
问题根因
你当前代码的核心问题是布局归属逻辑错位:RecyclerView、添加按钮这些组件都定义在HomeFragment的布局fragment_home.xml里,但你把这些组件的初始化、Adapter绑定逻辑全部写在了MainActivity中。
首次启动时MainActivity执行onCreate刚好赶上HomeFragment首次加载布局,findViewById能拿到当时的RecyclerView实例,绑定Adapter后可以正常展示;当你跳转到设置页再返回时,HomeFragment会重建自身的View树,生成新的RecyclerView实例,MainActivity中持有的还是已经销毁的旧实例,新的RecyclerView没有绑定过Adapter,就会输出你看到的警告,同时列表不显示。
修改方案
1. 精简MainActivity代码
删除MainActivity中所有和RecyclerView、添加FAB、Adapter相关的逻辑,仅保留导航、ViewModel初始化的部分,修改后代码如下:
package com.example.shoppinglist import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.lifecycle.ViewModelProvider import androidx.navigation.findNavController import androidx.navigation.ui.setupActionBarWithNavController class MainActivity : AppCompatActivity() { lateinit var viewModel: ViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setupActionBarWithNavController(findNavController(R.id.fragment_main)) // ViewModel保留在Activity级别,后续Fragment可以共享同一个实例 val repository = Repository(Database(this)) val factory = ViewModelFactory(repository) viewModel = ViewModelProvider(this, factory).get(ViewModel::class.java) } override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.fragment_main) return navController.navigateUp() || super.onSupportNavigateUp() } }
2. 把列表逻辑迁移到HomeFragment中
HomeFragment需要负责自身布局内所有组件的初始化、Adapter绑定、事件处理,修改后代码如下:
package com.example.shoppinglist import android.app.Dialog import android.os.Build import android.os.Bundle import android.widget.Button import android.widget.EditText import android.widget.Toast import androidx.annotation.RequiresApi import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.floatingactionbutton.FloatingActionButton import kotlinx.android_synthetic.main.fragment_home.* class HomeFragment : Fragment(), RVAdapter.ListItemClickInterface { lateinit var RVAdapter: RVAdapter lateinit var viewModel: ViewModel override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_home, container, false) } @RequiresApi(Build.VERSION_CODES.N) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // 获取Activity级别的共享ViewModel viewModel = (requireActivity() as MainActivity).viewModel // 初始化RecyclerView val itemsRV = view.findViewById<RecyclerView>(R.id.recyclerView) val addFAB = view.findViewById<FloatingActionButton>(R.id.idFABAdd) RVAdapter = RVAdapter(emptyList(), this) itemsRV.layoutManager = LinearLayoutManager(requireContext()) itemsRV.adapter = RVAdapter // 观察数据变化 viewModel.getAllListItems().observe(viewLifecycleOwner, Observer { RVAdapter.list = it RVAdapter.notifyDataSetChanged() }) // 添加按钮点击事件 addFAB.setOnClickListener { openDialog() } // 设置按钮点击事件 idFABSettings.setOnClickListener { findNavController().navigate(R.id.action_homeFragment_to_settingsFragment) } loadSettings() } @RequiresApi(Build.VERSION_CODES.N) private fun loadSettings(){ val sp = PreferenceManager.getDefaultSharedPreferences(context) val theme = sp.getBoolean("theme_switch",false) } private fun openDialog() { val dialog = Dialog(requireContext()) dialog.setContentView(R.layout.add_dialog) val cancelButton = dialog.findViewById<Button>(R.id.idBtnCancel) val addButton = dialog.findViewById<Button>(R.id.idBtnAdd) val itemEdt = dialog.findViewById<EditText>(R.id.idEditItemName) val itemQuantityEdt = dialog.findViewById<EditText>(R.id.idEditItemQuantity) cancelButton.setOnClickListener { dialog.dismiss() } addButton.setOnClickListener { val itemName: String = itemEdt.text.toString() val itemQuantity: String = itemQuantityEdt.text.toString() if (itemName.isNotBlank() && itemQuantity.isNotBlank()) { val items = ListItems(itemName, itemQuantity) viewModel.insert(items) Toast.makeText(requireContext(), "Item Added", Toast.LENGTH_SHORT).show() dialog.dismiss() } else { Toast.makeText(requireContext(), "Enter All Info To Add Item", Toast.LENGTH_SHORT).show() } } dialog.show() } override fun onItemClick(listItems: ListItems) { viewModel.delete(listItems) Toast.makeText(requireContext(), "Item Deleted", Toast.LENGTH_SHORT).show() } }
额外提示
你当前使用的kotlin-android-extensions已经被官方废弃,后续如果出现控件找不到的问题,可以替换为View Binding实现控件引用,稳定性更高。
内容的提问来源于stack exchange,提问作者Toskorae
相关产品推荐
相关产品推荐

