未声明Bundle可为空却遇类型不匹配,求非取巧式解决方案
解决Fragment间Bundle传递的类型不匹配问题
先看你的代码场景:
第一个Fragment(UserFragment)中,你初始化了非空的bundle并传递给下一个Fragment:
class UserFragment : Fragment(), View.OnClickListener { private val userBinding: FragmentUserBinding by onCreateView<Fragment, FragmentUserBinding>(R.layout.fragment_user) val user: ObservableField<String> = ObservableField() private var bundle = Bundle() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) userBinding.main = this } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = userBinding.root!! override fun onClick(p0: View?) { runAnimation(500L, Techniques.RubberBand, p0) Handler().postDelayed({ saveUserAndStartLetterFragment() }, 700L) } private fun saveUserAndStartLetterFragment() { var fragment = WordpackChooserFragment() bundle.putString("User",user.get()) fragment.arguments = bundle activity!!.supportFragmentManager.replaceFragment(fragment, activity!!.findViewById(R.id.flContainer)) } }
但在接收方WordpackChooserFragment中,arguments是可空类型(Bundle?),而你声明的bundle是非空的Bundle,所以bundle = arguments会抛出类型不匹配错误:
class WordpackChooserFragment : Fragment(), View.OnClickListener { private val wordpackChooserBinding: FragmentWordpackChooserBinding by onCreateView<Fragment, FragmentWordpackChooserBinding>(R.layout.fragment_wordpack_chooser) private var bundle: Bundle = Bundle() private lateinit var fragment: Fragment override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { wordpackChooserBinding.main = this setRecycler() bundle = arguments // 错误:类型不匹配,必需Bundle,找到Bundle? return wordpackChooserBinding.root } override fun onClick(v: View?) { fragment = RoundsChooserFragment() bundle.putStringArrayList("Wordpack", selectedPack) fragment.arguments = bundle activity!!.supportFragmentManager.replaceFragment(fragment, activity!!.findViewById(R.id.flContainer)) } private fun setRecycler() { wordpackChooserBinding.root.btn_recycler.layoutManager = LinearLayoutManager(this.context) wordpackChooserBinding.root.btn_recycler.adapter = BtnAdapter(this) wordpackChooserBinding.root.btn_recycler.adapter.notifyDataSetChanged() } }
你不想用!!取巧是对的,因为那会隐藏潜在的空指针风险。这里给你几个更合理的解决方案:
1. 空合并运算符处理(最安全推荐)
用?:运算符在arguments为null时创建一个空Bundle,既解决类型问题,又保证代码健壮性:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { wordpackChooserBinding.main = this setRecycler() // 如果arguments不为null就用它,否则新建空Bundle bundle = arguments ?: Bundle() return wordpackChooserBinding.root }
这种方式覆盖了所有场景,哪怕Fragment意外没有收到参数,后续代码也能正常运行。
2. lateinit延迟初始化(适用于参数必传场景)
如果你能确保所有启动WordpackChooserFragment的地方都会传入arguments(比如只有UserFragment会启动它,且一定会设置参数),可以把bundle声明为lateinit var:
// 把原来的private var bundle: Bundle = Bundle()改成 private lateinit var bundle: Bundle override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { wordpackChooserBinding.main = this setRecycler() // 这里用!!是安全的,因为你已经确保参数必传 bundle = arguments!! return wordpackChooserBinding.root }
注意:如果运行时arguments为null,这里会抛出UninitializedPropertyAccessException,所以只有当你能100%控制Fragment的启动方式时才用这个方案。
3. 改为可空类型并安全调用(适用于需要处理空场景)
如果你想明确感知bundle可能为null的情况,可以把它声明为可空类型,在使用时用安全调用:
// 把原来的private var bundle: Bundle = Bundle()改成 private var bundle: Bundle? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { wordpackChooserBinding.main = this setRecycler() bundle = arguments return wordpackChooserBinding.root } override fun onClick(v: View?) { fragment = RoundsChooserFragment() // 安全调用putStringArrayList,bundle为null时不会执行 bundle?.putStringArrayList("Wordpack", selectedPack) fragment.arguments = bundle activity!!.supportFragmentManager.replaceFragment(fragment, activity!!.findViewById(R.id.flContainer)) }
这种方式适合你需要在参数缺失时做特殊处理(比如弹出提示)的场景。
内容的提问来源于stack exchange,提问作者James Fisher
相关产品推荐
相关产品推荐

