【问题标题】:lateinit property not initialized after pick file explorer选择文件资源管理器后未初始化 lateinit 属性
【发布时间】:2020-03-01 00:42:37
【问题描述】:

我有一个活动让用户从资源管理器中选择文件,在onActivityResult() 中检索结果并将结果保存在名为Property 的对象中

我有一个如下的 lateinit 变量:

lateinit var uploadProperties: Property

以及打开资源管理器的代码(已授予权限):

fun openExplorer(property: Property) {
    uploadProperties = property
    val intent = Intent(Intent.ACTION_GET_CONTENT)
    intent.type = Constants.ALL_FILE
    intent.addCategory(Intent.CATEGORY_OPENABLE)
    startActivityForResult(
        Intent.createChooser(intent, getString(R.string.select_file)),
        REQ_FILE
    )
}

然后onActivityResult(),我将数据转换为base64并将其分配给Property

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
        when (requestCode) {
            REQ_FILE -> {
                data?.let {
                    val base64 = data.toBase64()

                    uploadProperties.let {
                        value = base64
                    }
                }
            }
        }
    }
}

问题是,在某些情况下,我收到了有关 crashlytics 的这些错误报告:

Caused by kotlin.UninitializedPropertyAccessException
lateinit property uploadProperties has not been initialized

我尝试了很多次,但只有几次出现这些错误(不知道是什么触发了这个)。但是一些用户抱怨从资源管理器中选择文件后应用程序总是崩溃。我检查了 crashlytics,消息如上所述。

我尝试在startActivityForResult() 之前使用断点进行调试。变量uploadProperties 已经初始化并且值正确。但是在从资源管理器中选择文件后,在某些情况下,应用程序仍然崩溃并显示UninitializedPropertyAccessException

知道是什么导致了这个错误以及如何解决这个问题吗?

【问题讨论】:

  • 您的进程可能已终止,而您的应用程序的 UI 处于后台。或者,由于用户在前台使用存储访问框架 UI 时配置更改,您的 Activity 可能已被销毁并重新创建,作为将控制权返回给您的一部分。
  • 进入开发者选项并启用“不保留活动” - 您的应用每次都会重现该崩溃。
  • 啊,我明白了,这可能是可能的。有什么想法可以解决这些问题吗?
  • 我试图将这些变量作为伴随对象来避免生命周期,但它仍然会发生。

标签: android kotlin kotlin-lateinit


【解决方案1】:

您需要处理应用进程被破坏以释放内存的情况。在您的情况下,存储 uploadProperties 就足够了。

在你的 Activity 中,当它被销毁时首先存储它(我假设你的 Property 类是 Parcelable,如果不写任何你需要稍后恢复它的东西):

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    // ( ... your save instance states if any)
    // store upload properties if they were set up
    if(::uploadProperties.isInitialized)
        outState.putParcelable("uploadProperties", uploadProperties)
}

然后将其恢复到您的onCreate

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // (...)
    if(savedInstanceState?.containsKey("uploadProperties") == true){
        uploadProperties = savedInstanceState.getParcelable("uploadProperties")!!
    }
    // (...)
}

现在更改您的结果回调,使其延迟到您的属性恢复后:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
        when (requestCode) {
            REQ_FILE -> {
                data?.let {
                    val base64 = data.toBase64()
                    // delay using androidx.lifecycle
                    lifecycleScope.launchWhenCreated {
                        uploadProperties.let { it.value = base64 }
                    }
                }
            }
        }
    }
}

【讨论】:

  • 谢谢,我错过了延迟结果回调的部分。我不知道onActivityResult是在onCreate之前调用的
猜你喜欢
  • 1970-01-01
  • 2017-03-03
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 2021-06-11
  • 2017-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多