Snapshot

Jetpack Compose 引入了一种处理可查询状况的新办法 —— Snapsot(快照)。在Compose中咱们经过state的改动来触发重组,那么请考虑以下几个问题:

  • 为什么state改动能触发重组javascript呢?
  • 它是怎样供认重组规划呢?
  • 只需state改动就一定会重组吗?

让咱们带着问题去学习!approve

本文部分比如和内容来自:Introduction to the Compose Snapshot system

Snapshot API

一般状况下我多线程的并发问题们不需求了解快照怎appointment样运用,这些都是结构应该做的作业,咱们手动操作很可能搞出问题。所以这儿只是演示快照的运用(不触及底层完毕),这样有助于了解Compose重组的机制。

Snapshot(快照),简略比如便是给悉数state拍了个照,因而你能获取到拍摄之前的状况。

咱们经过代码演示来看看Snapshot到底是做什么的:
首要界说一个Dog类,包含一个state:

class Djava模拟器og {
var name: MutableStandroid体系ate<String> = mutableSta多线程是什么意思teOf("")
}

创立快照

  val dog = Dog()
dog.naandroid体系me.value = “Spot”
val snaps多线程的并发问题hot = Snapshot.android手机takeSnapshot()
dog.nam线程池的七个参数e.value = “Fido”
println(dog.name.value)
snapshot.enter {
println(dog.name.value)
}
println(dog.name.value)
// Output:
Fido
Spot
Fido

  • tak线程池eSnapshot()"拍摄"程序中悉数State值的快照,无论它们是在何处创立的
  • enter函数会把快照状况康复并运用到函数体中

因而咱们看到仅在enter多线程中能够经过调用相应的中是旧值。

可变快照

咱们测验在enter块中更改狗狗的名字:

fun main() {
v线程池al dog = Dog()
dog.name.value = "Spot"
val snapshot = Snapshot.takeSnapshot()
println(dog.name.value)
snapshot.enter {
pri多线程ntln(dog.name.value)
dog.name.value = "Fido"
println(d多线程的并发问题og.name.value)
}
println(dog.name.value)
}
// Output:
Spot
Spot
java.lang.IllegapplealStateException: Cannot modify a statappstoree object in a read-only snjava开发apshot

会发现当咱们测验修改值时报错了,因为takeSnapshot()是只android是什么手机牌子读的,因而在enter内部咱们能够读但不能写,假定想要创立一个可变快照应运用takeMutableSnapshot()办法。

fun main() {
val djava开发og = Dog()
dog.name.value = "Spot"
val snapshot = Snapshot.takeMutableSnapshot()
println(dog.naandroid开发me.value)
snapshot.enter {
dog.name.value = "Fido"
println(dog.name.value)
}
println(dog.name线程池面试题.value)
}
// Output:
Sappearancepot
Fido
Spot

能够看到程序没有溃散了,但是在enter里的操作并没有在其规划之外收效!这是一个很重要的隔绝机制,javaee假定咱们想要运用enter 内部的改动需求多线程中能够经过调用相应的调用apply()办法:

 fun main() {
val dog =android的drawable类 Dog()
dog.name.value = "Spot"
val snapshot =APP Snapshot.takeMutableSnapshot()
println(dog.name.value)
snapshot.enter {
dog.name.value = "Fido"
println(dog.name.valueappetite)
}
println(dog.name.valueandroid什么意思)
snapshot.apply()
println(dog.name.value)
}
// Output:
Spot多线程cpu有什么优点
Fido
Spot
Fido

能够看到调用apply之后,新值android下载enter之外也收效了。咱们还能够使Snapshot.withMutableSnapshot()来简化调用:

fun main(多线程的实现办法) {
val dog = Dog()
dog.java作业培训班name.value = "Spot"
Snapshot.withMutableSnapshot {
println(dog.name.value)
dog.name.value = "Fido"
println(dog.name.value)
}
println(dog.name.value)
}

到目前为止咱们知道了:

  • 拍摄咱们悉数状况的快照
  • “康复”情多线程中能够经过调用相应的况到特定的代码块
  • 改动状况值

但咱们还不知道怎样感知读写,接下来让咱们搞清楚这个。

查询读取和写入

无论是LiveData,Flow 仍是St线程池的七个参数ate都是查询者形式,那么就要有查询者和被查询者。关于快照体系,被查询者便是咱们的state,而查询者有两个,一个是读取查询者,一个是写入查询者。

实践上 takeMutableSnapshot有两个可选参数的,别离在读和写时多线程面试题回调:

 fun takeMutableSnapshotAndroid(
readObserver: ((Any) -> Unit)? = null,
writeObserver: ((Any) ->java作业培训班 Unit)? = null
): MutableSna线程池的七个参数pshot =
(currentSnapshot() as? MutableSnapshot)?.takeNestedMutableSnapshot(
readObserver,
writeObserver
) ?: error("Cannot create a mutable snapshot of anappstore read-only snapshot")

因而咱们能够在回线程调中实施一些操作,在Compose中便是值读取时记java怎样读ComposeScope,写APP入时假定有改动则将对应的Scope标记为invalid

大局快照

大局快照是位于快照树根部的可变快照。与有必要apply才华收效的惯例可变快照比较,大局快照没有apply操作。比如咱们会在ViewModel里界说state,并且在repository请求数据并给state赋值。此刻就Android会由GlobalSnapshot去发送奉告:

它经过调用:

  • Snapshot.notifyObjandroidstudio装置教程ectsInitialized。这会为自前次调用以来更改的androidstudio装置教程任何状况发送奉告。
  • Snapshot.sendApplyNotifications()。这类似于notifyObjectsInitialized,但只需在实践产生更改时才会推动javaee快照。在第一种状况下,只需将任何可变快照运用于大局多线程的实现办法快照,就会隐式调用此函数。

Jetpack Compose   快照体系

能够看到在android平台上注册了writeObserver,它还有ApplyObs多线程形式有什么作用erv多线程cpu有什么优点er咱们后边再线程池创立的四种说。

线程

在给定线多线程和多进程的差异程的快照中,在运用该快照之前,不会看到其他线程对状况值所做的更改。快照与其他快照“隔绝”。在运用快照并主动推动大局快照之前,对快照内的状况所做的任何更改对其他线程都将不行见。
看这个类名咱们就懂了 Sna线程pshotThread线程和进程的差异是什么Local:

Jetpack Compose   快照体系

抵触

假定咱们”拍摄”了多个快照并且均运用修改会怎android体系样呢?

fun main() {
val dog = Dog()
dog.name.value = "Spot"
val snajavascriptpshot1 = S线程撕裂者napshot.takeMutableSnapshot(appear)
val snapshot2 = Snapshot.takeMutandroid体系ableSnapshot()
println(dog.name.value)
snapsho多线程中能够经过调用相应的t1.enter {
dog.name.value = "Fido"
prinjava难学吗tln("in snapshot1: " + dog.namapplee.value)
}
// Don’t apply it yet, let’s try setting a third value first.
println(dog.name.android手机value)
snapshot2.enter {
dog.name.value = "Fluffy"
println(java言语"in snapshot2: " + dog.name.value)
}
// Ok now we can app多线程ly bot线程h.
println("before applying: " + dog.name多线程形式有什么作用.value)
snaps多线程和多进程的差异hot1.apply()
println多线程面试题("after applying 1android平板电脑价格: " + dog线程池的七个参数.name.value)
snapshot2.apply()
println("after applying 2: " + dog.name.value)
}
// Output:
Spot
in snapshot线程池原理1: Fido
Spot
in snapshot2: Fluffy
before applying: Spot
after applying 1: Fido
after applying 2: Fido

会发现第二个快照的更改无法运用,因为它们都视图以相同的初始值进行修改,因而第二个快照要么再实施一次enter,要么奉告怎样解抵触。多线程面试题

Compose 实践上有一个用于appstore处理兼并抵触的 API多线程面试题mutableStateOf()需求一个可选的SnapshotMutationPolicy. 该战略界说了怎样比较特定类型的值 (equivalent) 以及怎样处理抵触 (merge)。并且供给了一些开箱即用的战略:

  • structuralEqualityPolicy– 运用政策的equals办法 ( ==)比较方android体系针,全多线程形式有什么作用部写入都被以为对错冲线程池的七个参数突的。
  • referentialEqualityPolicy– 经过引用 ( ===)比较政策,悉数写入都被以为对错抵触的。
  • neverEqualPolicy– 将悉数政策视为不相等,悉数写入都被以为对错抵触的。

线程池创立的四种们也能够构建自己的规则:

claappointmentss Dog {
var naAPPme: MutableState<String> =
mutableStateOf("", policy = object : SnapshotMutationPolicy<String> {
override fun equivalent(a: String, b: String): Boolean = a == b
overriandroid的drawable类de fun merge(previous: String, current: String, applied: Strin线程安全g): String =
"$applied, briefapplicationly kno线程池面试题wn as $current, originally known as $previous"
})
}
fun main() {
// Same as before.
}
// Output:
Spot
in snapshot1: Fido
Spot
in snapshot2: Flappointmentuffy
before applying: Spot
after app线程和进程的差异是什么lying 1: Fido
after applying 2: Fluffy, briefljava初学y known as Fido, originally known as Sp多线程是什么意思ot

总结

以上便是Snapshot(快照)的根柢运用,它就相当于高级的DiffUtil。它的特征总结起来便是:

  • 呼应式多线程的实现办法:有状况的代码一直主动坚持java言语最新。咱们无需忧虑订阅和反订阅。
  • 隔绝性:有状况代码能够对状况进行操作,而不用忧虑在不同线程上作业的代线程是什么意思码会改动该状况。Compose 能够使用这一点来完毕旧的 View 体系无法完毕多线程面试题的作用,例如将重构放到多个后台线程上去实施。

解惑

  • 为什么stat多线程中能够经过调用相应的e改动能触发重多线程中能够经过调用相应的组呢?

Jetpack Compose在实施时注册了readObserverOfwriteObserverOf:

Jetpack Compose   快照体系

其间在读取状况android下载的当地会实施:

  • readObserverOf来记载哪些线程scope运用了此state

Jetpack Compose   快照体系

  • writeObserveapplicationrOf

而写入时会找出对应运用此statescope使其invalidate
Jetpack Compose   快照体系

在下次帧信号抵达时关于这些scope实施重组。

  • 它是怎样供认重组规划呢?

具体参见:Compose 怎样供认重组规划

Jetpack Compose   快照体系

咱们方才看了readObse多线程是什么意思rver,就多线程编程是在读取value的可重组的@composable函数。

  • 只需standroid是什么手机牌子ate改动就一定会重组吗?

不一定,具体事例请看以下比如:

比如①

    val darkMode = mutableStateOf("helloandroid开发")多线程的并发问题
override fun onCrandroidstudio装置教程eate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
lifecycleScope.launch {
delay(100)
val text= darkMode.value
darkMode.value = "Compose"
}
}
}

不会重组,因为delay导致状况的读取是在apply办法之外实施的:

Jetpack Compose   快照体系

Android此也就不会注册readObserverOf,天然也就不会与composeScope挂钩,也就不会触发重组,假定是在delay之前读取则会重组哦。

比如②

   val多线程中能够经过调用相应的 darkMo线程是什么意思de = mutableStateOf("h多线程和多进程的差异ello")
override fun onCreate(savedInsappeartanceState: Bundle?) {
super.onCrappointmenteate(savedInstanceState)
setContent {
thread {
darkMode.value = "Compose"
}
}
}

这个就比较简略了,在不同线程调用,想想SnapshotThreadLocal,互不烦扰(直到appjava言语ly),因而也不会触发重组。

比如③

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val darkMode = mutableStateOf("hello")
Text(多线程面试题darkMode.value)
dajavaeerkMode.value = "Compose"
}
}

这个也没触发重组,可能咱们会疑问,这个没异步,断点也有readObserverwriteObserver为啥不会触发重组线程撕裂者呢? 不是说状况改动会将运用它的scope记为invalid吗?

approach而实践作业中,InvalidationResultIGNORE
Jetpack Compose   快照体系

首要咱们确实记载下了运用state线程安全scope,否则也不会在修改时触发invalidate行为。但此刻slotTable里并还没有可重组的区域锚点信息,只需在组合完毕之后才华拿到每个区域的锚点anchors
简略描绘便是Compose运用SlotTable来记载数据信息,此刻第一次无缺的组合都没完毕,不知道该从哪下手。

有关SlotTable的更多信息请参阅:深入详解JetpackCompose|完毕原理

但是假定你把state的创立放到setContent线程之外呢线程池面试题

比如④

  val darkMode = mutableStateOf("hello")application
override fuapplicationn oandroid什么意思nCreate(sa多线程编程vedInstanceState: Bundle?) {
supeandroid下载装置r.onCreate(savedInstanceState)
setContentandroid体系 {
Text(darkMode.value)
darkappstoreMode.value = "Compose"
}
}

答案是会重组

因为这个状况是在拍摄之前创立的,此刻state.snapshotId!=Snapshot.id,此期间对state的修改虽然不会当即标appearance记为invalid,但是会计入modified,apply之后,由大局快照进行奉告:

Jetpack Compose   快照体系

会在apply时奉告到查询者ApplyObserv线程池创立的四种er(方才还说到writerObserver),记载下changed:

Jetpack Compose   快照体系

composation则会找出查询了对应改动状况多线程和多进程的差异scope进行重组。

Jetpack Compose   快照体系

以上便是快照体系的运用和Jetpack Com多线程cpu有什么优点pose重组的机制,有任何不正确的当地欢迎指正。