修复Android Kotlin文件保存功能中的异常问题

使用 GPT-4o 回答,作者 GPT4oMini.app

问题:

Android开发,用Kotlin语言。实现一个文件保存的功能,部分代码如下: override fun onDestroy() { super.onDestroy() val editText_2: EditText = findViewById(R.id.fileStoreEdit2) val inputText_2 = editText_2.text.toString() save_2(inputText_2) } private fun save_2(inputText: String) { try { val file = File(getExternalFilesDir(null), "testdata02") val writer = BufferedWriter(FileWriter(file)) writer.use { it.write(inputText) } } catch (e: IOException) { e.printStackTrace() } }

执行时,程序报错: FATAL EXCEPTION: main Process: com.example.activitytest, PID: 15501 java.lang.RuntimeException: Unable to destroy activity {com.example.activitytest/com.example.activitytest.FileStoreActivity}: java.lang.IllegalStateException: FragmentManager has been destroyed at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:5889) at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:5919) at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:44) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:190) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2624) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8679) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109) Caused by: java.lang.IllegalStateException: FragmentManager has been destroyed at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1936) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1996) at androidx.fragment.app.FragmentManager.dispatchDestroy(FragmentManager.java:3105) at androidx.fragment.app.FragmentController.dispatchDestroy(FragmentController.java:334) at androidx.fragment.app.FragmentActivity.onDestroy(FragmentActivity.java:330) at androidx.appcompat.app.AppCompatActivity.onDestroy(AppCompatActivity.java:283) at com.example.activitytest.BaseActivityClass.onDestroy(BaseActivityClass.kt:38) at com.example.activitytest.FileStoreActivity.onDestroy(FileStoreActivity.kt:39) at android.app.Activity.performDestroy(Activity.java:8478) at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1355) at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:5874) at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:5919)  at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:44)  at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:190)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2624)  at android.os.Handler.dispatchMessage(Handler.java:110)  at android.os.Looper.loop(Looper.java:219)  at android.app.ActivityThread.main(ActivityThread.java:8679)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109) 

请排除问题,并修复代码

答案:

从错误日志来看,问题出在 onDestroy 方法中调用 findViewById 导致的 IllegalStateException。在 onDestroy 方法中,Activity 的视图层次结构可能已经被销毁,因此调用 findViewById 可能会导致异常。

为了修复这个问题,可以在 onPauseonStop 方法中保存数据,而不是在 onDestroy 中。这样可以确保在视图层次结构被销毁之前完成数据保存。

以下是修复后的代码:

override fun onPause() {
    super.onPause()
    val editText_2: EditText = findViewById(R.id.fileStoreEdit2)
    val inputText_2 = editText_2.text.toString()
    save_2(inputText_2)
}

private fun save_2(inputText: String) {
    try {
        val file = File(getExternalFilesDir(null), "testdata02")
        val writer = BufferedWriter(FileWriter(file))
        writer.use {
            it.write(inputText)
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

在这个修复中,我们将数据保存的逻辑从 onDestroy 移动到了 onPause 方法中。onPause 方法在 Activity 进入后台时调用,此时视图层次结构仍然存在,因此可以安全地调用 findViewById

此外,确保在 AndroidManifest.xml 中声明了写入外部存储的权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

如果你的应用目标 SDK 版本是 23 或更高版本,还需要在运行时请求权限:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_STORAGE)
}

这样可以确保在保存文件时拥有必要的权限。