Kotlin Android中MainActivity的public var dataList在Fragment无法访问
代码示例配图说明:配图上半部分为
dataList在MainActivity中的定义逻辑,下半部分为向dataList添加元素后启动Fragment的流程
在MainActivity中定义了public修饰的dataList变量,存在如下异常表现:
- MainActivity的onCreate方法内可以正常读取到刚添加到
dataList中的新增元素 - 在Fragment中通过如下代码访问时,仅能读取到
dataList的初始默认值,无法获取后续新增的内容
mainAdapter = todoAdapter(MainActivity().dataList[0][2])
核心诉求:调整配置让Fragment可以正常获取到dataList中后续新增的元素。
问题根因
你在Fragment中写的MainActivity()本质是手动创建了一个全新的MainActivity实例,这个新实例没有经过系统的Activity生命周期调度,也不会执行你之前向dataList添加元素的业务逻辑,内部存储的dataList只会是类初始化时的默认值,根本不是当前Fragment附着的、已经完成元素添加的真实宿主Activity实例。
可落地的解决方法
方法1:读取真实附着的宿主Activity实例
不要手动new Activity,通过Fragment自带的生命周期回调拿到当前附着的真实MainActivity实例,再读取对应的dataList:
private lateinit var hostActivity: MainActivity // 在onAttach阶段拿到宿主Activity实例,避免后续空指针 override fun onAttach(context: Context) { super.onAttach(context) hostActivity = context as MainActivity } // 读取数据的时机要放在onViewCreated及之后的生命周期节点 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mainAdapter = todoAdapter(hostActivity.dataList[0][2]) }
注意:不要在Fragment的初始化阶段、onCreateView之前的节点读取dataList,避免出现宿主Activity的dataList还没完成赋值添加就被读取的空指针问题。
方法2:通过官方参数传递解耦,避免强绑定Activity
如果不想让Fragment和MainActivity形成强依赖,在启动Fragment时通过官方提供的Bundle参数机制把dataList数据传递过去,Fragment从自身携带的参数中读取数据,这种写法在页面配置变更(比如屏幕旋转重建)时也不会丢失数据:
// 启动Fragment时完成数据传参 val targetFragment = YourFragment().apply { arguments = bundleOf( "key_data_list" to dataList ) } supportFragmentManager.commit { replace(R.id.fragment_container, targetFragment) } // Fragment内部读取传递过来的参数 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val passedData = arguments?.getSerializable("key_data_list") as? ArrayList<MutableList<Any>> mainAdapter = todoAdapter(passedData?.getOrNull(0)?.getOrNull(2).toString()) }
真正的全局数据共享实现思路
如果需要跨多个页面、跨生命周期全局共享dataList数据,不要用Activity的public成员变量存储,这类写法很容易引发当前遇到的空实例读取问题,还会因为页面重建导致数据丢失,推荐更稳妥的实现:
- 将
dataList存储在应用级的单例Repository层,配合Jetpack ViewModel实现跨页面的统一数据读取,数据生命周期跟随应用进程,不会因为页面切换、重建丢失 - 不要将自定义的public成员变量写在Activity中作为全局变量使用,这类写法既没有统一的数据生命周期管理,也容易被其他模块随意修改引发不可预期的bug
内容的提问来源于stack exchange,提问作者Emre

