如何在Android中保存和恢复lambdas?
在Android中实现状态恢复时,如何保存和恢复lambda 我尝试将其保存为可序列化和可打包,但它会引发编译错误如何在Android中保存和恢复lambdas?,android,kotlin,state-restoration,Android,Kotlin,State Restoration,在Android中实现状态恢复时,如何保存和恢复lambda 我尝试将其保存为可序列化和可打包,但它会引发编译错误 有什么方法可以保存和恢复它们,或者我应该寻求其他方法吗?Kotlin lambdas实现Serializable,因此它们不能像以下那样保存: override fun onSaveInstanceState(outState: Bundle) { outState.putSerializable("YOUR_TAG", myLambda as Serializable)
有什么方法可以保存和恢复它们,或者我应该寻求其他方法吗?Kotlin lambdas实现
Serializable
,因此它们不能像以下那样保存:
override fun onSaveInstanceState(outState: Bundle) {
outState.putSerializable("YOUR_TAG", myLambda as Serializable)
super.onSaveInstanceState(outState)
}
同样,要恢复它们:
override fun onCreate(savedInstanceState: Bundle?) {
myLambda = savedInstanceState?.getSerializable("YOUR_TAG") as (MyObject) -> Void
super.onCreate(savedInstanceState)
}
(这显然可以在为您提供savedInstanceState
的任何生命周期事件中完成,因为这只是一个示例)
一些注意事项:
- 保存它们时,需要对它们进行强制转换,否则编译器会抱怨(出于某种原因)
- 需要导入java.io.Serializable
- 将其强制转换回lambda类型的方法将抛出警告
。此强制转换是安全的(假设您正确推断为空!),因此您可以使用Unchecked cast:Serializable?到您的lambdatype
@Suppress(“UNCHECKED_cast”)
必须是MyObject
或Serializable
,否则它会在运行时崩溃Parcelable
{}
中的内容)不能引用稍后将释放的对象。
一个典型的例子是:
// In your MyActivity.kt…
myLambda = { handleLambdaCallback() }
…
private fun handleLambdaCallback() {
…
}
这将在运行时崩溃,因为handleLambdaCallback
隐式访问此
,这将触发尝试递归序列化可由其访问的整个对象图,这将在序列化期间的某个点失败
这个问题的一个解决方案是在lambda中发送一个引用。例如:
// In your MyActivity.kt…
myLambda = { fragment -> (fragment.activity as MyActivity).handleLambdaCallback() }
…
private fun handleLambdaCallback() {
…
}
这样,我们在调用lambda时计算引用,而不是在分配它时。这肯定不是最干净的解决方案,但这是我能提供的最好的解决方案,而且很有效
请随时提出改进和替代解决方案
我应该寻求其他途径吗
是的,没有一个很好的理由这样做,你的代码将不容易测试,你可能会引入内存泄漏
不保存函数,而是保存需要保存的参数(即范围中的变量),并像通常那样调用函数
示例
而不是做
val name = "John Smith"
val sayHello = { "Hi there, $name" }
startActivity(Intent().apply { putExtra("GREETER", sayHello as Serializable) })
创建一个可以在其他地方使用的函数
fun sayHello(name: String) = { "Hi there, $name" }
并稍后使用还原的
名称
参数调用如果您尝试序列化捕获此
的lambda,它将尝试递归序列化可从它访问的整个对象图。我预计这将立即失败,而不是在反序列化时。作为GCd的引用对象不是问题,因为整个包化点都是重建死对象。您必须将lambda强制转换为可序列化的Serializable
的原因应该是,这首先向Kotlin发出信号,以创建可序列化的lambda。lambda在默认情况下不可序列化。没错,它在序列化时失败,而不是在反序列化时失败。对我来说,序列化整个对象图的有趣之处在于,当活动转到onStop lifecycle事件时,它失败了。此外,我还能够在带有参数bundle的片段中成功地传递、检索和类型转换lambda。我不理解lambda方法是如何固有地不稳定并且容易发生内存泄漏的。我认为我的答案改善了内存泄漏,特别是因为现在必须不引用此
。但是,我认为您的方法会使子对象(例如片段)意识到其父对象(即片段必须调用(activity as MyActivity)。sayHello(name)
),这显然是不好的。要么这样,要么我们就采用“委托”(监听器)方法。我遗漏了什么吗?@MarkoTopolnik从定义上讲,lambdas没有错,但是从你开始在作用域中使用变量而不是参数的那一刻起,事情就变得一团糟了:@MarkoTopolnik 1。你不能只看lambda的定义就知道它应该做什么,@MarkoTopolnik 2。出于同样的原因,很难进行测试,很难知道要模拟的依赖项(参数)是什么,您必须将它们定义为范围中可用的变量(而不仅仅是调用函数)