添加setFragmentResultListener后Fragment报did not return View错误如何解决
问题排查与解决方案
核心崩溃原因
你在onCreateView方法执行过程中调用了requireView(),但requireView()需要等onCreateView执行完成、返回根View之后才能正常调用,此时Fragment还未绑定根View,因此直接抛出IllegalStateException异常。
你已经提前通过inflater拿到了inflate后的view对象,直接用这个对象调用findViewById即可,不需要用requireView()。
其他潜在问题
store、amount、date三个TextView没有做初始化,后续直接调用setText会触发空指针崩溃- 同一个TableRow/TextView反复调用
addView会抛出异常:每个View只能挂载到唯一的父布局上,不能重复添加 - 遍历列表给同一个TextView赋值的逻辑无效,执行后只会显示列表的最后一个元素
- 三个
setFragmentResultListener逻辑高度重复,可合并简化
修正后的代码
class HistoryFragment : Fragment() { // 用数据类统一存储消费记录,避免分开维护三个列表 data class ExpenseRecord(val store: String, val amount: String, val date: String) private val expenseList = mutableListOf<ExpenseRecord>() private lateinit var textview2: TextView private lateinit var textView3: TextView private lateinit var textView4: TextView private lateinit var table : TableLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { val view: View = inflater.inflate(R.layout.fragment_history, container, false) // 直接用刚inflate的view找控件,不要用requireView textview2 = view.findViewById(R.id.textView2) textView3 = view.findViewById(R.id.textView3) textView4 = view.findViewById(R.id.textView4) table = view.findViewById(R.id.tableHistorie) // 其他Fragment分三次返回数据的适配逻辑 setFragmentResultListener("requestKey") { _, bundle -> val store = bundle.getString("bundleKey") ?: return@setFragmentResultListener addNewRow(store = store) } setFragmentResultListener("requestKey2") { _, bundle -> val amount = bundle.getString("bundleKey2") ?: return@setFragmentResultListener addNewRow(amount = amount) } setFragmentResultListener("requestKey3") { _, bundle -> val date = bundle.getString("bundleKey3") ?: return@setFragmentResultListener addNewRow(date = date) } // 可优化项:如果能修改另一个Fragment的逻辑,建议把三个参数塞到同一个Bundle返回,仅需一个监听即可 // setFragmentResultListener("requestKey") { _, bundle -> // val store = bundle.getString("bundleKey") ?: return@setFragmentResultListener // val amount = bundle.getString("bundleKey2") ?: return@setFragmentResultListener // val date = bundle.getString("bundleKey3") ?: return@setFragmentResultListener // addNewRow(store, amount, date) // } return view } // 封装添加行的公共逻辑,避免重复代码 private fun addNewRow(store: String = "", amount: String = "", date: String = "") { // 每次添加都新建行和TextView,不要复用同一个对象 val newRow = TableRow(requireContext()) val storeTv = TextView(requireContext()).apply { text = store } val amountTv = TextView(requireContext()).apply { text = amount } val dateTv = TextView(requireContext()).apply { text = date } newRow.addView(storeTv) newRow.addView(amountTv) newRow.addView(dateTv) table.addView(newRow) expenseList.add(ExpenseRecord(store, amount, date)) } }
后续优化建议
- 如果后续需要展示的记录较多,建议用
RecyclerView代替TableLayout实现列表,性能更好、拓展性更强 - 尽量把同一份数据的参数合并到同一个
Bundle中返回,减少冗余的监听逻辑 - 可以给TextView设置统一的边距、样式,表格展示效果更规整
内容的提问来源于stack exchange,提问作者dkiwikid
相关产品推荐
相关产品推荐

