![](/img/trans.png)
[英]Implement FirestoreQuery with LiveData updates : Android Firestore RecyclerView
[英]Android Livedata updates his states with copy of objects
嗨,我想我現在真的不知道實時數據是如何工作的。
我有一個帶有預填充值的二維數組。
val randomboard =
arrayOf(arrayOf(0, 0, 0, 0), arrayOf(0, 0, 0, 0), arrayOf(0, 0, 0, 0), arrayOf(0, 0, 0, 0))
還有一個實時數據 Object,它只在我的 ViewModel 的初始化 Function 發布一次我的陣列的當前 State。
init {
_preFillButtons.postValue(randomboard.copyOf())
}
所以我希望只有我的數組的當前 State 和沒有未來的狀態被推送到我的 LiveData 對象所以我給了它我的數組的副本。
當我改變我的陣列隨機板的任何值然后像我的方向一樣改變時,我的 livedata object 在他的 state 中只有這個新值,沒有我將任何新的 State 推到那個 LiveData object。
也許 Livedata object 不是我需要的,但我不知道為什么連副本 object 都更新了。
更新:
完整代碼
class GameActivity : AppCompatActivity(), View.OnClickListener {
val viewModel: GameViewModel by viewModels()
val buttonIDs = arrayOf(
intArrayOf(R.id.button1, R.id.button2, R.id.button3, R.id.button4),
intArrayOf(R.id.button5, R.id.button6, R.id.button7, R.id.button8),
intArrayOf(R.id.button9, R.id.button10, R.id.button11, R.id.button12),
intArrayOf(R.id.button13, R.id.button14, R.id.button15, R.id.button16)
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.preFillButtons.observe(this) {
prefillButtons(it)
}
}
private fun prefillButtons(board: Array<Array<Int>>) {
for (row in 0..3) {
for (col in 0..3) {
val button = findViewById<Button>(buttonIDs[row][col])
button.setTag(R.id.row, row)
button.setTag(R.id.column, col)
button.setOnClickListener(this)
if (board[row][col] != 0) {
button.text = board[row][col].toString()
button.isEnabled = false
} else {
button.text = getString(R.string.defaultbuttontext)
button.isEnabled = true
}
}
}
}
override fun onClick(view: View?) {
val button = view as? Button
if (button != null) {
val row = button.getTag(R.id.row) as Int
val col = button.getTag(R.id.column) as Int
showAlertDialog(col, row)
}
}
private fun showAlertDialog(col: Int, row: Int) {
val builder = AlertDialog.Builder(this)
builder.setItems(R.array.choices) { dialogInterface: DialogInterface, i: Int ->
if (i != 4) {
viewModel.trySetValue(row, col, i + 1)
}
}
builder.setTitle(getString(R.string.dialogtitle, row + 1, col + 1))
builder.show()
}
}
視圖模型:
class GameViewModel : ViewModel() {
val preFillButtons: LiveData<Array<Array<Int>>>
get() = _preFillButtons
private val _preFillButtons = MutableLiveData<Array<Array<Int>>>()
val randomboard =
arrayOf(arrayOf(0, 0, 0, 0), arrayOf(0, 0, 0, 0), arrayOf(0, 0, 0, 0), arrayOf(0, 0, 0, 0))
init {
_preFillButtons.postValue(randomboard.copyOf())
}
fun trySetValue(row: Int, col: Int, num: Int) {
randomboard[0][0] = 1
}
}
屏幕旋轉后(配置更改后)看到新的 state 與 LiveData 的工作方式無關。 您正在正確觀察您的 LiveData。
所以我希望只有我的數組的當前 State 和沒有未來的狀態被推送到我的 LiveData 對象所以我給了它我的數組的副本。
這里稍作更正,您給了它一個數組的淺表副本。 淺拷貝是原始數組的副本,但如果項目是實例(對對象的引用),它們將通過引用進行復制。 這意味着對數組副本中項目的更改也會影響原始數組中的項目,因為它是相同的引用(=相同的實例)。
因為你有一個 arrays 的數組,你的數組中的項目是 4 個其他 arrays 的實例。當你在randomboard
中更改trySetValue
內的值時,你每次都會訪問相同的 4 個數組實例。
arrayOf
調用創建一個新的數組實例並用作為參數提供的值填充它。 因此,您對randomboard
的初始分配會創建 5 個數組實例:
randomboards
這段代碼通過引用比較值,顯示主數組是一個新實例(因為調用了copyOf
),但里面的 arrays 是相同的實例。
init {
val copy = randomboard.copyOf()
Log.d("Test", "copy === randomboard: ${copy === randomboard}") // false
Log.d("Test", "copy[0] === randomboard[0]: ${copy[0] === randomboard[0]}") // true
Log.d("Test", "copy[1] === randomboard[1]: ${copy[1] === randomboard[1]}") // true
Log.d("Test", "copy[2] === randomboard[2]: ${copy[2] === randomboard[2]}") // true
Log.d("Test", "copy[3] === randomboard[3]: ${copy[3] === randomboard[3]}") // true
//...
}
如果你不想改變影響數組的副本,你必須做一個深拷貝。 您可以通過在源數組上調用.map
或使用Array<T>(size: Int, init: (Int) -> T)
將初始化器 function 作為第二個參數的構造函數來實現。
通過在源數組上調用map
init {
val deepCopy = randomboard.map { it.copyOf() }.toTypedArray()
_preFillButtons.postValue(deepCopy)
}
通過使用Array<T>(size: Int, init: (Int) -> T)
構造函數
init {
// Same as: val deepCopy = Array(randomboard.size) { idx -> randomboard[idx].copyOf() } }
val deepCopy = randomboard.let { Array(it.size) { idx -> it[idx].copyOf() } }
_preFillButtons.postValue(deepCopy)
}
然后,如果您通過引用比較所有值,您將看到現在內部 arrays 也是一個新實例。
init {
val deepCopy = randomboard.map { it.copyOf() }.toTypedArray()
Log.d("Test", "deepCopy === randomboard: ${deepCopy === randomboard}") // false
Log.d("Test", "deepCopy[0] === randomboard[0]: ${deepCopy[0] === randomboard[0]}") // false
Log.d("Test", "deepCopy[1] === randomboard[1]: ${deepCopy[1] === randomboard[1]}") // false
Log.d("Test", "deepCopy[2] === randomboard[2]: ${deepCopy[2] === randomboard[2]}") // false
Log.d("Test", "deepCopy[3] === randomboard[3]: ${deepCopy[3] === randomboard[3]}") // false
// ...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.