将对象发送到另一个片段后被更改

问题描述 投票:0回答:2

所以,我有一个很奇怪的问题,我将一个对象从Fragment A传递给Fragment B,我在Fragment B中的新实例中修改了该对象,但是在此之后更改了一个值对象,当我弹出Framgment B时,它也会更改该值,并且该对象现在也针对Fragment A

进行修改

片段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中得到这个对象

片段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中是该​​对象的新实例。

我真的很困惑

android android-fragments kotlin android-architecture-components android-architecture-navigation
2个回答
0
投票

对象引用按值传递

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


0
投票

这实际上不是一个带有明显答案的明显问题。大约2个月前,我收到了这个问题,这也使我感到困惑,因为有时这是您的行为,有时则不是。

首先要注意的是,当您为Fragment提供参数时,会将它们放在Bundle中。该捆绑包在内部存储一个用于字符串键的Map。

因此,当您呼叫fragment.setArguments(bundle)时,基本上就是在“发送地图”。

因此,由于没有发生IPC(与在Activity中通过Intent与Android通话不同),因此在地图中存在相同的对象实例。

直到系统使用Bundle参数的属性,并且确实重新创建了实例

[进程死后(您将应用程序置于后台,Android回收了内存,并在重新启动时Android重建了任务堆栈,并根据从FragmentManager保存到onSaveInstanceState中的现有历史记录重新创建了活动的Fragments),原始传递的参数用于“重新创建”传入的属性。

目前,系统已重新创建了Serializable,如果要导航回去,它将是与最初发送的实例不同的实例。

因此,您获得相同的实例,因为Bundle在内部是地图。

您还可以获取其他实例,因为Android可以重新创建它。

解决方案:在发送实例之前,请使用副本以保持一致的行为。

© www.soinside.com 2019 - 2024. All rights reserved.