[英]Saving and restoring Kotlin lambda with savedInstanceState
How to save Kotlin lambda in fragment before the screen rotation? 如何在屏幕旋转之前以片段形式保存Kotlin lambda? It works in Activity but doesn't correct work in the fragment.
它可以在“活动”中运行,但不能纠正片段中的工作。 An exception occurs when executing a lambda expression if it contains calls to methods of the child class of PermissionsFragment, Why?
如果执行lambda表达式包含对PermissionsFragment的子类的方法的调用,则会发生异常,为什么?
Class which stores lambda in itself: 本身存储lambda的类:
class ActionKeeper(var action: ((isGranted: Boolean) -> Unit)? = null) : Serializable
Fragment which saves lambda to ActionKeeper on screen rotation: 在屏幕旋转时将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)
}
}
/* ........ */
}
Class which extends from PermissionsFragment: 从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 exteption: 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)
You might have issue with context
您可能对
context
有疑问
Try below code and let me know : 尝试下面的代码,让我知道:
private fun showToast(text: String) {
toast?.cancel()
activity?.let {
toast = Toast.makeText(it, text, Toast.LENGTH_SHORT).apply { show() }
}
}
Edit: 编辑:
Save object of your ActionKeeper
as: 将
ActionKeeper
对象另存为:
outState.putSerializable("actionKeeper", object: ActionKeeper(action))
The problem in your code is that there are references inside your lambda that will be deallocated (thus, inaccessible) in the future. 您的代码中的问题在于,您的lambda内部有一些引用,这些引用将来会被释放(因此不可访问)。 When saving the state, Android will save the pointers (references) inside that lambda, so it can't point towards invalid memory.
保存状态时,Android会将指针(引用)保存在该lambda中,因此它不能指向无效的内存。
This is better explained here: How to save and restore lambdas in Android? 此处对此有更好的解释: 如何在Android中保存和还原Lambda?
To fix it, in your case, you could have a reference of the callee in one of the lambda parameters, ie 要解决此问题,在您的情况下,您可以在lambda参数之一中引用被调用者,即
private var action: ((Fragment, Boolean) -> Unit)? = null
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.