所以,我有一个很奇怪的问题,我将一个对象从Fragment A传递给Fragment B,我在Fragment B中的新实例中修改了该对象,但是在此之后更改了一个值对象,当我弹出Framgment B时,它也会更改该值,并且该对象现在也针对Fragment A
进行修改...
override fun onItemClick(v: View?, position: Int) {
searchView.clearFocus()
val bundle = Bundle()
bundle.putSerializable("shop", landingAdapter.getItem(position))
findNavController().navigate(R.id.action_navigation_landing_to_shopFragment, bundle)
}
...
现在,从片段B中得到这个对象
private lateinit var shop: Shop
private lateinit var shopAdapter:ShopAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
shopAdapter = ShopAdapter(sharedViewModel, requireContext(),this)
arguments?.let {
shop = it.getSerializable(ARG_SHOP) as Shop
if (shop.products.isNotEmpty()) {
shopAdapter.setItems(shop.products)
}
}
}
现在,当我从片段A获取此Shop对象后,仅使用[]在片段B中对其进行修改
onViewCreated(){
shop.quantity = 1
}
但是当我返回片段A时,Shop对象的数量值现在是1,但是应该不算什么,因为我只更改了片段B上的对象,而不是片段A,并且在片段B中是该对象的新实例。
我真的很困惑
对象引用按值传递
Kotlin中的所有对象引用均按值传递。这意味着该值的副本将传递给方法。但是诀窍在于传递值的副本也会更改对象的实际值。要了解原因,请尝试以下示例:
object ObjectReferenceExample {
fun transform(p:Person) {
p.name = "Person2";
}
}
class Person(var name:String)
fun main() {
val person = Person("Person1");
ObjectReferenceExample.transform(person);
System.out.println(person.name);// output are Person2
}
原因是Kotlin对象变量只是指向内存堆中实际对象的引用。因此,即使Kotlin通过值将参数传递给方法,但如果变量指向对象引用,则实际对象也将被更改。 同样适用于Java
这实际上不是一个带有明显答案的明显问题。大约2个月前,我收到了这个问题,这也使我感到困惑,因为有时这是您的行为,有时则不是。
首先要注意的是,当您为Fragment提供参数时,会将它们放在Bundle中。该捆绑包在内部存储一个用于字符串键的Map。
因此,当您呼叫fragment.setArguments(bundle)
时,基本上就是在“发送地图”。
因此,由于没有发生IPC(与在Activity中通过Intent与Android通话不同),因此在地图中存在相同的对象实例。
即直到系统使用Bundle参数的属性,并且确实重新创建了实例。
[进程死后(您将应用程序置于后台,Android回收了内存,并在重新启动时Android重建了任务堆栈,并根据从FragmentManager保存到onSaveInstanceState中的现有历史记录重新创建了活动的Fragments),原始传递的参数用于“重新创建”传入的属性。
目前,系统已重新创建了Serializable,如果要导航回去,它将是与最初发送的实例不同的实例。
因此,您获得相同的实例,因为Bundle在内部是地图。
您还可以获取其他实例,因为Android可以重新创建它。
解决方案:在发送实例之前,请使用副本以保持一致的行为。