You need to enable JavaScript to run this app. Kotlin中lateinit修饰的action属性未初始化及Firebase检测的赋值报错修复
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中lateinit修饰的action属性未初始化及Firebase检测的赋值报错修复

报错根因
  • 「lateinit property action has not been initialized」崩溃:DialogFragment会在系统配置变更(屏幕旋转、后台进程被回收重建)时自动生成新实例,你通过setListener手动赋值的lateinit修饰的action属于实例临时状态,重建后会被清空。当用户完成时间选择触发onTimeSet时,未完成初始化的action就会直接抛出运行时异常。
  • Firebase检测标记setListener位置错误:直接给Fragment实例赋值外部回调的写法,会让Fragment隐式持有宿主(Activity/父Fragment)的强引用,当Fragment被系统回收时,外部引用无法被正常释放,会引发内存泄漏,属于Android官方明确禁止的Fragment通信写法,因此会被性能检测规则捕获。
标准修复方案

采用AndroidX官方推荐的FragmentResult跨组件通信机制替代自定义setter回调,彻底解决崩溃和内存泄漏问题:

  1. 调整TimePickerFragment内部逻辑,移除原有action属性和setListener方法,用户选中时间后通过系统提供的结果通道分发数据
  2. 在弹出选择器的宿主页面(Activity/父Fragment)注册结果监听,接收选中的时间值,不需要在弹窗前给Fragment传递任何回调

修改后的TimePickerFragment完整代码:

import android.app.Dialog
import android.app.TimePickerDialog
import android.os.Bundle
import android.text.format.DateFormat
import android.widget.TimePicker
import androidx.fragment.app.DialogFragment
import java.util.*

class TimePickerFragment : DialogFragment(), TimePickerDialog.OnTimeSetListener {

    companion object {
        // 定义唯一的请求Key,用于匹配回调监听
        const val REQUEST_KEY = "time_picker_request"
        // 定义结果存储的Key,用于读取选中的时间
        const val RESULT_TIME_KEY = "selected_time"
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val c = Calendar.getInstance()
        val hour = c.get(Calendar.HOUR_OF_DAY)
        val minute = c.get(Calendar.MINUTE)
        return TimePickerDialog(activity, this, hour, minute, DateFormat.is24HourFormat(activity))
    }

    override fun onTimeSet(view: TimePicker, hourOfDay: Int, minute: Int) {
        val min = if(minute < 10) "0$minute" else minute.toString()
        // 将选中的时间封装为结果,通过系统通道分发
        val result = Bundle().apply {
            putString(RESULT_TIME_KEY, "$hourOfDay:$min")
        }
        parentFragmentManager.setFragmentResult(REQUEST_KEY, result)
        dismiss()
    }
}

宿主页面(以Activity为例)的适配代码:

// 在页面初始化阶段(比如onCreate方法中)注册结果监听
private fun registerTimePickerCallback() {
    supportFragmentManager.setFragmentResultListener(
        TimePickerFragment.REQUEST_KEY,
        this
    ) { _, bundle ->
        val selectedTime = bundle.getString(TimePickerFragment.RESULT_TIME_KEY)
        // 拿到选中的时间字符串后,执行后续业务逻辑
        // 比如更新输入框、存储选中值等
    }
}

// 弹出时间选择器时,直接实例化调用show即可,不需要额外设置回调
fun openTimePicker() {
    val picker = TimePickerFragment()
    picker.show(supportFragmentManager, "time_picker")
}

临时应急方案(不推荐长期使用)
如果暂时无法改动整体通信逻辑,可以通过两个最小调整避免崩溃:

  • 将lateinit var action : (String) -> Unit修改为可空属性:var action: ((String) -> Unit)? = null
  • 在onTimeSet中调用回调时增加判空:action?.invoke("$hourOfDay:$min")
    该方案仅能规避空指针崩溃,依然存在内存泄漏风险,也无法解决配置变更时回调丢失的问题。

内容的提问来源于stack exchange,提问作者Rajiv Mochammad Iqbal Alhadad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 23:45:03