![](/img/trans.png)
[英]Saving and restoring EditText cursor position in a DialogFragment using savedInstanceState
[英]Saving and restoring Kotlin lambda with savedInstanceState
如何在屏幕旋轉之前以片段形式保存Kotlin lambda? 它可以在“活動”中運行,但不能糾正片段中的工作。 如果執行lambda表達式包含對PermissionsFragment的子類的方法的調用,則會發生異常,為什么?
本身存儲lambda的類:
class ActionKeeper(var action: ((isGranted: Boolean) -> Unit)? = null) : Serializable
在屏幕旋轉時將lambda保存到ActionKeeper的片段:
abstract class PermissionsFragment : Fragment() {
private var action: ((isGranted: Boolean) -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
restoreState(savedInstanceState)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putSerializable("actionKeeper", ActionKeeper(action))
}
private fun restoreState(state: Bundle) {
val keeper = state.getSerializable("actionKeeper") as ActionKeeper
action = keeper.action
}
fun usePermission(permission: String, action: (isGranted: Boolean) -> Unit) {
if (!isPermissionGranted(permission)) {
this.action = action
requestPermissions(arrayOf(permission), 1)
} else {
action(true)
}
}
/* ........ */
}
從PermissionsFragment擴展的類:
class SamplePermissionsFragment : PermissionsFragment() {
private var toast: Toast? = null
private fun doWithPermission() {
usePermission(Manifest.permission.SEND_SMS) { isGranted ->
if (isGranted) {
showToast("Fragment permission granted")
} else {
showToast("Fragment permission refused")
}
}
}
private fun showToast(text: String) {
toast?.cancel()
toast = Toast.makeText(context!!, text, Toast.LENGTH_SHORT).apply { show() }
}
}
Logcat滅絕:
2018-09-27 15:57:17.068 5569-5569/com.alexchurkin.permissionsample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.alexchurkin.permissionsample, PID: 5569
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=65537, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.alexchurkin.permissionsample/com.alexchurkin.permissionsample.fragment.FragmentHostActivity}: kotlin.KotlinNullPointerException
at android.app.ActivityThread.deliverResults(ActivityThread.java:4196)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4239)
at android.app.ActivityThread.-wrap20(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1599)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
Caused by: kotlin.KotlinNullPointerException
at com.alexchurkin.permissionsample.fragment.SamplePermissionsFragment.showToast(SamplePermissionsFragment.kt:56)
at com.alexchurkin.permissionsample.fragment.SamplePermissionsFragment.access$showToast(SamplePermissionsFragment.kt:13)
at com.alexchurkin.permissionsample.fragment.SamplePermissionsFragment$doWithPermission$1.invoke(SamplePermissionsFragment.kt:35)
at com.alexchurkin.permissionsample.fragment.SamplePermissionsFragment$doWithPermission$1.invoke(SamplePermissionsFragment.kt:13)
at com.alexchurkin.fastpermissions.fragments.PermissionsFragment.onRequestPermissionsResult(PermissionsFragment.kt:38)
at android.support.v4.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:860)
at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:7268)
at android.app.Activity.dispatchActivityResult(Activity.java:7120)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4192)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4239)
at android.app.ActivityThread.-wrap20(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1599)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
您可能對context
有疑問
嘗試下面的代碼,讓我知道:
private fun showToast(text: String) {
toast?.cancel()
activity?.let {
toast = Toast.makeText(it, text, Toast.LENGTH_SHORT).apply { show() }
}
}
編輯:
將ActionKeeper
對象另存為:
outState.putSerializable("actionKeeper", object: ActionKeeper(action))
您的代碼中的問題在於,您的lambda內部有一些引用,這些引用將來會被釋放(因此不可訪問)。 保存狀態時,Android會將指針(引用)保存在該lambda中,因此它不能指向無效的內存。
此處對此有更好的解釋: 如何在Android中保存和還原Lambda?
要解決此問題,在您的情況下,您可以在lambda參數之一中引用被調用者,即
private var action: ((Fragment, Boolean) -> Unit)? = null
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.