前言

今天遇到一个问题,是关于 MutableList.addAll(specifiedCollection)。我发现执行addAll后,列表中的数据就会跟着 specifiedCollection 一同改变,也便是说指向了同一内存引证地址。

上事例

咱们ViewModel中有一个itemDataList,表明水果的价格,如:[ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]

class TestViewModel : ViewModel() {
    private val TAG = "TestViewModel"
    private val itemDataList: MutableList<ItemData> = mutableListOf(
        ItemData("西瓜", 3),
        ItemData("苹果", 2),
    )
    private val _itemDataListMld: MutableLiveData<List<ItemData>> = MutableLiveData<List<ItemData>>().apply {
        postValue(itemDataList)
    }
    val itemDataLd: LiveData<List<ItemData>> = _itemDataListMld
    fun getItemDataList() {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                //重复10次修正动作。
                repeat(10) {
                    //随机修正列表中的数据
                    (0..1).random().let {
                        Log.e(TAG, "getItemDataList: random change index = $it")
                        itemDataList[it].price = (1..100).random()
                    }
                    _itemDataListMld.postValue(itemDataList)
                    delay(1000)
                }
            }
        }
    }
}

当调用ViewModel.getItemDataList()后,就会重复随机修正列表中的数据,并经过postValue将修正后的列表数据给到itemDataLd,告诉给相对应的活跃观察者目标。

Activity中进行观察该itemDataLd目标,在收到数据更新告诉后,打印数据,并对未初始化的oldItemDataList进行初始化。

class TestActivity : AppCompatActivity() {
    private val TAG = "TestActivity"
    private lateinit var binding: ActivityTestBinding
    private lateinit var viewModel: TestViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityTestBinding.inflate(layoutInflater)
        setContentView(binding.root)
        viewModel = ViewModelProvider(this)[TestViewModel::class.java]
        binding.updateListBtn.setOnClickListener {
            viewModel.getItemDataList()
        }
        val oldItemDataList: MutableList<ItemData> = mutableListOf()
        var isInit = false
        viewModel.itemDataLd.observe(this) { newItemDataList **->**
            Log.e(TAG, "onCreate: itemDataLd.observe oldItemDataList = $oldItemDataList")
            Log.e(TAG, "onCreate: itemDataLd.observe newItemDataList = $newItemDataList")
            //关于 oldItemDataList 只进行一次初始化
            if (!isInit) {
                oldItemDataList.clear()
                val isAddAllData = oldItemDataList.addAll(newItemDataList)
                Log.e(TAG, "onCreate: addALL ************************ isAddAllData = $isAddAllData")
                isInit = true
            }
        }
    }
}

经过上述代码,能够看出,咱们只对 oldItemDataList 只进行一次初始化操作,接着后边收到新的newItemDataList数据告诉也不会去修正 oldItemDataList

由于咱们在实例化_itemDataListMld目标时,会立即进行postValue(itemDataList),所以在进入Activity后会立马收到关于itemDataLd最新数据的告诉,打印Log看看。

17:25:47.518 26784-26784   onCreate: itemDataLd.observe oldItemDataList = []
17:25:47.518 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
17:25:47.518 26784-26784   onCreate: addALL ************************ isAddAllData = true

经过Log能够看到,oldItemDataList 一开始是空的,接着关于进行初始化,addAll 操作返回 true,阐明addAll操作成功。

接着,咱们再触发一下 viewModel.getItemDataList 来打印一下Log看看。

17:25:59.310 26784-26965   getItemDataList: random change index = 1
17:25:59.315 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=21)]
17:25:59.315 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=21)]
17:26:00.321 26784-26965   getItemDataList: random change index = 0
17:26:00.323 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=39), ItemData(name=苹果, price=21)]
17:26:00.323 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=39), ItemData(name=苹果, price=21)]
17:26:01.325 26784-26965   getItemDataList: random change index = 0
17:26:01.327 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=63), ItemData(name=苹果, price=21)]
17:26:01.328 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=63), ItemData(name=苹果, price=21)]
17:26:02.330 26784-26965   getItemDataList: random change index = 0
17:26:02.332 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=75), ItemData(name=苹果, price=21)]
17:26:02.332 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=75), ItemData(name=苹果, price=21)]
17:26:03.335 26784-26965   getItemDataList: random change index = 1
17:26:03.337 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=75), ItemData(name=苹果, price=74)]
17:26:03.337 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=75), ItemData(name=苹果, price=74)]
17:26:04.338 26784-26965   getItemDataList: random change index = 1
17:26:04.340 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=75), ItemData(name=苹果, price=44)]
17:26:04.341 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=75), ItemData(name=苹果, price=44)]
17:26:05.344 26784-26965   getItemDataList: random change index = 0
17:26:05.347 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=22), ItemData(name=苹果, price=44)]
17:26:05.347 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=22), ItemData(name=苹果, price=44)]
17:26:06.350 26784-26965   getItemDataList: random change index = 1
17:26:06.353 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=22), ItemData(name=苹果, price=33)]
17:26:06.353 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=22), ItemData(name=苹果, price=33)]
17:26:07.355 26784-26965   getItemDataList: random change index = 0
17:26:07.359 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=91), ItemData(name=苹果, price=33)]
17:26:07.359 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=91), ItemData(name=苹果, price=33)]
17:26:08.360 26784-26965   getItemDataList: random change index = 0
17:26:08.362 26784-26784   onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=46), ItemData(name=苹果, price=33)]
17:26:08.363 26784-26784   onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=46), ItemData(name=苹果, price=33)]

经过Log能够看出,虽然咱们没有对 oldItemDataList 进行新的操作,可是 oldItemDataList 的数据仍是会跟着LiveData推过来的新的List<ItemData>数据改变而改变。

这是为什么呢?

有些同学可能对MutableList不熟悉,kotlin将调集类型分为了只读类型与可变类型。

  • 只读类型:完成只读接口Collection<out E>,供给访问调集元素的操作,。
  • 可变类型:完成可变接口MutableCollection<E>,经过写操作扩展相应的只读接口:增加、删除和更新其元素。

而看MutableList的初始化办法mutableListOf,能够发现本质上其实是ArrayList

public fun <T> mutableListOf(vararg elements: T): MutableList<T> =
    if (elements.size == 0) ArrayList() else ArrayList(ArrayAsCollection(elements, isVarargs = true))

所以,咱们往下看看ArrayListaddAll办法。

ArrayList.java
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

先即将增加的结合转换为数组a,然后经过System.arraycopy()办法将数组a的元素仿制到elementData数组中。

System.arraycopy()Java中的一个办法,用于数组之间的元素仿制。可是该办法仿制的是数组元素的内存引证地址,所以是一个浅仿制办法。

这就触及到了浅仿制知识。

关于浅仿制与深仿制

  • 浅仿制:创立一个新目标,指向被仿制目标的内存引证地址。
  • 深仿制:创立一个新目标,且创立一个新的内存地址,并将被仿制目标的值仿制到新目标中。

举个例子

咱们为需求展现的产品创立一个bean文件,包括产品名称、价格以及来历这几个特点,其间价格与来历的城市是可变特点,其它都是不可变特点。

/**
 * 产品数据
 */
data class ItemData(
    val name: String,//不可变的根本数据类型特点
    var price: Int,//可变的根本数据类型特点
    val source: Source//不可变的引证类型特点
)
/**
 * 来历地址
 */
data class Source(
    var city: String//可变的根本数据类型特点
)

咱们先经过ItemData来创立咱们的第一个产品:苹果。

val originalUser = ItemData("苹果", 20, Source("烟台"))

接着,咱们试着运用浅仿制来创立另一个产品:香蕉。

val copiedUser = originalUser.copy(name = "香蕉")

打印这两个产品出来看看,分别是:

originalUser = ItemData(name=苹果, price=20, source=Source(city=烟台))
copiedUser = ItemData(name=香蕉, price=20, source=Source(city=烟台))

接着,咱们修正一下香蕉的来历信息,将香蕉的来历城市修正为"海南"

println("********* 修正来历 *********")
copiedUser.source.city = "海南"

修正后,再次打印两个产品:

********* 修正来历 *********
originalUser = ItemData(name=苹果, price=20, source=Source(city=海南))
copiedUser = ItemData(name=香蕉, price=20, source=Source(city=海南))

能够看出,虽然咱们只修正了香蕉的来历信息,可是,苹果的来历也随之更改了。

接着,咱们再来修正一下香蕉的价格,将香蕉的价格修正为9999

println("********* 修正价格 *********")
copiedUser.price = 9999

考虑一下,这次,苹果的价格也会跟着香蕉一同更改为9999吗?

上答案!再次打印两个产品:

********* 修正价格 *********
originalUser = ItemData(name=苹果, price=20, source=Source(city=海南))
copiedUser = ItemData(name=香蕉, price=9999, source=Source(city=海南))

经过Log能够看出,这次,苹果的价格并没有随之一同更改

这是为什么呢?

咱们先来看看 data class copy() 办法。

data class copy办法

首先 copy 办法是浅仿制办法,而且是会对主结构函数中的所有特点进行浅仿制。

可是特点又分根本数据类型与引证类型,这两者是有差异的。

  • 根本数据类型:新目标在浅仿制时会直接仿制被仿制目标的根本数据类型值,但这两者之间是独立的值,也便是说,修正这两者之间的任何一个目标的根本数据类型特点都不会影响到别的一个目标。
  • 引证类型:新目标在浅仿制时会仿制被仿制目标的引证。这两者目标持有同一内存引证地址,所以是相关的。也便是说,修正这两者之间的任何一个目标的特点,别的一个目标也会跟着一同产生更改。

所以在上方的例子中,price为可变的根本数据类型特点,仿制目标的值是独立的,所以当咱们更改 copiedUser.price = 9999 时,originalUser.price 并不会随之一同更改。而source为不可变的引证类型特点,浅仿制目标与被仿制目标是相关的,所以当咱们更改 copiedUser.source.city = "海南" 时,originalUser.source 会随之一同更改。

关于originalUsercopiedUser 的内存地址联系图,如下所示

一次由 List.addAll 所引起的深入

处理浅仿制问题

OK,回到初始List.addAll()办法,假如咱们想处理其浅仿制问题,咱们能够这么做。

TestActivity.java
val oldItemDataList: MutableList<ItemData> = mutableListOf()
var isInit = false
viewModel.itemDataLd.observe(this) { newItemDataList ->
    Log.e(TAG, "onCreate: itemDataLd.observe oldItemDataList = $oldItemDataList")
    Log.e(TAG, "onCreate: itemDataLd.observe newItemDataList = $newItemDataList")
    if (!isInit) {
        oldItemDataList.clear()
        //运用循环遍历仿制
        oldItemDataList.forEach { itemData ->
            //运用copy()办法仿制一个新目标
            val addResult = oldItemDataList.add(itemData.copy())
            Log.e(TAG, "onCreate: add ${itemData.name} ${itemData.price} result is -> $addResult")
        }
        isInit = true
    }
}

循环遍历新数据,并运用copy()办法仿制一个新目标出来,然后addoldItemDataList

打印一下Log看看:

09:40:49.830 25724-25724  onCreate: itemDataLd.observe oldItemDataList = []
09:40:49.830 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:49.830 25724-25724  onCreate: add 西瓜 3 result is -> true
09:40:49.831 25724-25724  onCreate: add 苹果 2 result is -> true
09:40:51.435 25724-25933  getItemDataList: random change index = 1
09:40:51.448 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:51.448 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=100)]
09:40:52.445 25724-25935  getItemDataList: random change index = 1
09:40:52.447 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:52.447 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=54)]
09:40:53.450 25724-25935  getItemDataList: random change index = 0
09:40:53.454 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:53.454 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=51), ItemData(name=苹果, price=54)]
09:40:54.453 25724-25935  getItemDataList: random change index = 1
09:40:54.455 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:54.455 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=51), ItemData(name=苹果, price=91)]
09:40:55.458 25724-25935  getItemDataList: random change index = 0
09:40:55.460 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:55.461 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=74), ItemData(name=苹果, price=91)]
09:40:56.462 25724-25935  getItemDataList: random change index = 0
09:40:56.463 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:56.463 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=11), ItemData(name=苹果, price=91)]
09:40:57.467 25724-25934  getItemDataList: random change index = 0
09:40:57.470 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:57.471 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=54), ItemData(name=苹果, price=91)]
09:40:58.472 25724-25934  getItemDataList: random change index = 1
09:40:58.473 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:58.474 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=54), ItemData(name=苹果, price=96)]
09:40:59.475 25724-25934  getItemDataList: random change index = 0
09:40:59.477 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:40:59.478 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=50), ItemData(name=苹果, price=96)]
09:41:00.480 25724-25934  getItemDataList: random change index = 1
09:41:00.483 25724-25724  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]
09:41:00.484 25724-25724  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=50), ItemData(name=苹果, price=73)]

经过Log能够看出,oldItemDataList只会被初始化一次,而且不会跟跟着新数据一同更新内容了,一直维持着初始数据[ItemData(name=西瓜, price=3), ItemData(name=苹果, price=2)]

不知你心里有没有疑问?copy()办法不是浅仿制办法吗?仿制出来的新目标与旧目标不是持有同一内存引证地址么,怎么旧目标内容数据不会跟着新目标一同更改呢?

由于在ItemData特点中,虽然price是可变特点,但也是可变的根本数据类型特点,仿制目标具有独立的值。

data class ItemData(
    val name: String,
    var price: Int//可变的根本数据类型特点
)

咱们能够进一步测试一下,给ItemData增加上source来历,定义为不可变引证类型特点。

data class ItemData(
    val name: String,
    var price: Int,//可变的根本数据类型特点
    val source: Source//不可变引证类型特点
)
data class Source(
    var city: String
)

然后为咱们的初始化数据增加上source特点。

private val itemDataList: MutableList<ItemData> = mutableListOf(
    ItemData("西瓜", 3, Source("宁夏")),
    ItemData("苹果", 2, Source("烟台"))
)

接着,咱们修正一下getItemDataList()办法,随机修正价格与来历数据。

fun getItemDataList() {
    viewModelScope.launch {
        withContext(Dispatchers.IO) {
            repeat(10) {
                (0..1).random().let { index ->
                    Log.e(TAG, "getItemDataList: random change index = $it")
                    (1..100).random().let { randomPrice ->
                        itemDataList[index].apply {
                            //随机修正价格
                            price = (1..100).random()
                            //随机修正来历数据
                            source.city = "${source.city} + $randomPrice"
                        }
                    }
                }
                _itemDataListMld.postValue(itemDataList)
                delay(1000)
            }
        }
    }
}

打印Log查看一下:

11:08:42.304  8184-8184  onCreate: itemDataLd.observe oldItemDataList = []
11:08:42.304  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
11:08:42.304  8184-8184  onCreate: add 西瓜 3 result is -> true
11:08:42.304  8184-8184  onCreate: add 苹果 2 result is -> true
11:08:54.210  8184-8440  getItemDataList: random change index = 1
11:08:54.215  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85))]
11:08:54.215  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=32, source=Source(city=烟台 + 85))]
11:08:55.220  8184-8440  getItemDataList: random change index = 0
11:08:55.223  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85))]
11:08:55.223  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=33, source=Source(city=宁夏 + 29)), ItemData(name=苹果, price=32, source=Source(city=烟台 + 85))]
11:08:56.224  8184-8440  getItemDataList: random change index = 0
11:08:56.226  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85))]
11:08:56.227  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=26, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=32, source=Source(city=烟台 + 85))]
11:08:57.227  8184-8440  getItemDataList: random change index = 1
11:08:57.228  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85 + 19))]
11:08:57.228  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=26, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=60, source=Source(city=烟台 + 85 + 19))]
11:08:58.233  8184-8440  getItemDataList: random change index = 1
11:08:58.235  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85 + 19 + 78))]
11:08:58.236  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=26, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=75, source=Source(city=烟台 + 85 + 19 + 78))]
11:08:59.237  8184-8443  getItemDataList: random change index = 1
11:08:59.239  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85 + 19 + 78 + 52))]
11:08:59.240  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=26, source=Source(city=宁夏 + 29 + 19)), ItemData(name=苹果, price=42, source=Source(city=烟台 + 85 + 19 + 78 + 52))]
11:09:00.242  8184-8443  getItemDataList: random change index = 0
11:09:00.245  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19 + 14)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85 + 19 + 78 + 52))]
11:09:00.245  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=24, source=Source(city=宁夏 + 29 + 19 + 14)), ItemData(name=苹果, price=42, source=Source(city=烟台 + 85 + 19 + 78 + 52))]
11:09:01.247  8184-8443  getItemDataList: random change index = 1
11:09:01.249  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19 + 14)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85 + 19 + 78 + 52 + 14))]
11:09:01.250  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=24, source=Source(city=宁夏 + 29 + 19 + 14)), ItemData(name=苹果, price=52, source=Source(city=烟台 + 85 + 19 + 78 + 52 + 14))]
11:09:02.252  8184-8443  getItemDataList: random change index = 0
11:09:02.255  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19 + 14 + 9)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85 + 19 + 78 + 52 + 14))]
11:09:02.255  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=40, source=Source(city=宁夏 + 29 + 19 + 14 + 9)), ItemData(name=苹果, price=52, source=Source(city=烟台 + 85 + 19 + 78 + 52 + 14))]
11:09:03.255  8184-8443  getItemDataList: random change index = 1
11:09:03.257  8184-8184  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏 + 29 + 19 + 14 + 9)), ItemData(name=苹果, price=2, source=Source(city=烟台 + 85 + 19 + 78 + 52 + 14 + 52))]
11:09:03.257  8184-8184  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=40, source=Source(city=宁夏 + 29 + 19 + 14 + 9)), ItemData(name=苹果, price=44, source=Source(city=烟台 + 85 + 19 + 78 + 52 + 14 + 52))]

经过Log能够看出,oldItemDataList 中的ItemData.source是会跟从新数据一同更新。也进一步证实了运用浅仿制的引证类型特点,仿制目标与被仿制目标之间持有同一内存引证地址。

假如,咱们想对引证类型特点进行深仿制操作,也便是对事例中的source特点进行深仿制,咱们能够这么操作。

var oldItemDataList: List<ItemData> = listOf()
var isInit = false
viewModel.itemDataLd.observe(this) { newItemDataList ->
    Log.e(TAG, "onCreate: itemDataLd.observe oldItemDataList = $oldItemDataList")
    Log.e(TAG, "onCreate: itemDataLd.observe newItemDataList = $newItemDataList")
    if (!isInit) {
        //手动进行设置Source特点
        oldItemDataList = newItemDataList.map { it.copy(source = Source(it.source.city)) }
        isInit = true
    }
}

打印Log看看:

20:17:33.655  9198-9198  onCreate: itemDataLd.observe oldItemDataList = []
20:17:33.655  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:36.706  9198-9945  getItemDataList: random change index = 1
20:17:36.712  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:36.712  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=45, source=Source(city=烟台 + 100))]
20:17:37.714  9198-9945  getItemDataList: random change index = 1
20:17:37.715  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:37.715  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=34, source=Source(city=烟台 + 100 + 68))]
20:17:38.717  9198-9945  getItemDataList: random change index = 1
20:17:38.719  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:38.719  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=10, source=Source(city=烟台 + 100 + 68 + 10))]
20:17:39.719  9198-9945  getItemDataList: random change index = 1
20:17:39.719  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:39.719  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=6, source=Source(city=烟台 + 100 + 68 + 10 + 21))]
20:17:40.721  9198-9945  getItemDataList: random change index = 1
20:17:40.722  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:40.722  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=99, source=Source(city=烟台 + 100 + 68 + 10 + 21 + 9))]
20:17:41.730  9198-9947  getItemDataList: random change index = 1
20:17:41.732  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:41.733  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=8, source=Source(city=烟台 + 100 + 68 + 10 + 21 + 9 + 89))]
20:17:42.735  9198-9945  getItemDataList: random change index = 1
20:17:42.736  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:42.737  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=61, source=Source(city=烟台 + 100 + 68 + 10 + 21 + 9 + 89 + 85))]
20:17:43.740  9198-9945  getItemDataList: random change index = 1
20:17:43.744  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:43.744  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=19, source=Source(city=烟台 + 100 + 68 + 10 + 21 + 9 + 89 + 85 + 40))]
20:17:44.746  9198-9945  getItemDataList: random change index = 1
20:17:44.749  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:44.749  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=19, source=Source(city=烟台 + 100 + 68 + 10 + 21 + 9 + 89 + 85 + 40 + 51))]
20:17:45.752  9198-9945  getItemDataList: random change index = 0
20:17:45.755  9198-9198  onCreate: itemDataLd.observe oldItemDataList = [ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))]
20:17:45.755  9198-9198  onCreate: itemDataLd.observe newItemDataList = [ItemData(name=西瓜, price=87, source=Source(city=宁夏 + 40)), ItemData(name=苹果, price=19, source=Source(city=烟台 + 100 + 68 + 10 + 21 + 9 + 89 + 85 + 40 + 51))]

经过Log能够看出,oldItemDataList的数据不会跟着新数据一同更新,一直保持着初始化数据[ItemData(name=西瓜, price=3, source=Source(city=宁夏)), ItemData(name=苹果, price=2, source=Source(city=烟台))],阐明完成了对引证类型特点的深仿制操作。

当仿制的目标是可变的引证类型特点时,进行浅仿制无法确保数据一致性。由于浅仿制仅仅是仿制目标的内存引证地址,多个目标引证同一个内存引证地址,这在多线程的环境下,就无法确保数据一致性了。所以针对可变的引证类型特点,就应该对其进行深仿制,让仿制的目标具有独立的内存地址,确保其唯一性,然后防止出现一些古怪的Bug。

总结

其实知道了原理之后,事情就变得简单了。当咱们不想oldItemDataList中的元素数据跟从newItemDataList元素数据一同更改时,咱们只需求确保两者的元素数据不是持有同一内存引证地址即可。所以,撇开深浅仿制办法,化繁为简,咱们能够直接实例化一个新目标出来,然后确保其内存引证地址的唯一性。

本文是由MutableList.addAll()延伸出来的学习文章,触及到浅仿制深仿制以及data class的一些相关知识点,也是属于夯实基础的一篇文章,信任掌握了这些小知识点后,对日后剖析问题会有很大的协助。



到此本篇文章就完毕啦,假如你有任何疑问或许不同的想法,欢迎在评论区留言与我一同讨论。

其实共享文章的最大意图正是等待着有人指出我的过错,假如你发现哪里有过错,请毫无保留的指出即可,谦虚请教。

别的,假如你觉得文章不错,对你有所协助,请帮我点个赞,就当鼓励,谢谢