解析jetpack合成ジャンプ問題-metrics
32968 ワード
以前、複数のモジュールからCompose Compilerのないモジュールクラスを取得して使用した場合、Skippableは必要に応じていないことを指摘しました.
データを使用してこれらの情報を簡単に表示し、分析する方法について説明します.
合成を適用するモジュールを構築します.ランプに次のコードを追加します.
次に、コンストラクションを回転すると、次のフォルダとファイルが作成されます. SkippableComposables RestartableComposables この2つの組合せをこのブログのcode snippetによって理解する.
再起動可能プロファイルとは、Snapshotオブジェクトの状態が変更されたときに再実行できる構成可能な関数の数です.
SnapshotはJetpack Componentで使用されるState Class Holderです.
Jetpack ComponentはSnapshotシステムを用いて状態変化を検出する.
正しい内容は下記のこのブログをご覧ください.
複合を生成するComponent Compilerによって生成されるコードを以下に示します.
通常,この観測はCorposable関数では単独で記述しない.
Compose CompilerではSnapshotシステムはオートファインダーです.
Snapshot
簡単なMutablesnapshotを使用した例を次に示します.
MutablesnapshotのパラメータはreadObserverとwriteObserverであり,この2つのファイバによって状態の変化を検出する.
さらに理解するために、コードを通じて入ります.以降補充計画
構成可能関数のスキップとは、構成可能関数のパラメータが以前と同じである場合にskipが発生する可能性があることを意味し、これは構成可能関数の数を意味する.
同様に、簡単なコードを見てみましょう.
$changedという静的intデータのビット演算により、パラメータの値が変更されたかどうかを決定し、スキップできるかどうかを決定します.
これらのパラメータの値は、Corpose CompilerによってSlot Table、$Corposerにデータが格納されます.changedからslotテーブルからデータを取り出します.
slotテーブルから抽出したデータを比較して、スキップできるかどうかを確認します.
メトリックをもう一度確認しましょう.
namecomposableskippablerestartableUserProfile101WrappedUserProfile111OtherContent111
生成されたデータのコードを表示するには、次の手順に従います.
app debug-composiblesは、コードのmetricsを分析するために使用されます.txtを表示します.
したがって、正しい動作を確認するには、@Stableまたは@Immutable Annotation(前のシリーズなど)を貼り付ける必要があります.
プロジェクトコードは下にあります.
https://github.com/TaehoonLeee/multi-module-compose-model-test
https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md https://chris.banes.dev/composable-metrics/ https://medium.com/androiddevelopers/under-the-hood-of-jetpack-compose-part-2-of-2-37b2c20c6cdd https://qiita.com/takahirom/items/6907e810d3661e19cfcf https://dev.to/zachklipp/introduction-to-the-compose-snapshot-system-19cn
データを使用してこれらの情報を簡単に表示し、分析する方法について説明します.
Metricsの作成
合成を適用するモジュールを構築します.ランプに次のコードを追加します.
kotlinOptions {
freeCompilerArgs += ["-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${rootProject.file(".").absolutePath}/compose-metrics"]
freeCompilerArgs += ["-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${rootProject.file(".").absolutePath}/compose-reports"]
}
以前に配置されたアイテムでバージョンを変更しました.次に、コンストラクションを回転すると、次のフォルダとファイルが作成されます.
project
│
└───compose-metrics
│ │ app_debug-module.json
└───compose-reports
│ app_debug-classes.txt
│ app_debug-composables.csv
│ app_debug-composables.txt
Files
app_debug-module.json
{
"skippableComposables": 6,
"restartableComposables": 7,
"readonlyComposables": 0,
"totalComposables": 7,
...
}
まず目立つ書類を見てみましょう.これらのファイルを理解するには、次の概念を理解する必要があります.Restartable Composables
再起動可能プロファイルとは、Snapshotオブジェクトの状態が変更されたときに再実行できる構成可能な関数の数です.
SnapshotはJetpack Componentで使用されるState Class Holderです.
Jetpack ComponentはSnapshotシステムを用いて状態変化を検出する.
正しい内容は下記のこのブログをご覧ください.
複合を生成するComponent Compilerによって生成されるコードを以下に示します.
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(
onClick = { count += 1 }
) {
Text(text = "Count : $count")
}
}
上記の簡単なカウンタコードは、次のようにCompose Compilerによって変換されます.@Composable
public static final void Counter(@Nullable Composer $composer, final int $changed) {
$composer = $composer.startRestartGroup(741257999);
...
if ($changed == 0 && $composer.getSkipping()) {
$composer.skipToGroupEnd();
...
} else {
$composer.startReplaceableGroup(-492369756);
...
$composer.endReplaceableGroup();
ButtonKt.Button(
...,
$composer,
...
)
}
ScopeUpdateScope var14 = $composer.endRestartGroup();
if (var14 != null) {
var14.updateScope((Function2)(new Function2() {
public final void invoke(@Nullable Composer $composer, int $force) {
SimpleComposeSampleKt.Counter($composer, $changed | 1);
}
}));
}
}
変換されたコードでComposerのendRestartGroupから返された値が空でない場合は、ステータスが変更されたかどうかを検出してリカバリが実行されます.通常,この観測はCorposable関数では単独で記述しない.
Compose CompilerではSnapshotシステムはオートファインダーです.
Snapshot
簡単なMutablesnapshotを使用した例を次に示します.
MutablesnapshotのパラメータはreadObserverとwriteObserverであり,この2つのファイバによって状態の変化を検出する.
fun main() {
val state = mutableStateOf("first")
val snapShot = Snapshot.takeMutableSnapshot(
readObserver = { println("The State is Read : $it") },
writeObserver = { println("The State is OverWritten : $it") }
)
snapShot.enter {
state.value
state.value = "second"
}
snapShot.apply()
}
以上の関数の出力は次のとおりです.The State is Read : MutableState(value=first)@189568618
The State is OverWritten : MutableState(value=second)@189568618
これにより、Snapshotシステムは、状態の変化を検出し、リカバリ例のコードなどのリカバリを行うことができる.さらに理解するために、コードを通じて入ります.
var14.updateScope((Function2)(new Function2() {
public final void invoke(@Nullable Composer $composer, int $force) {
SimpleComposeSampleKt.Counter($composer, $changed | 1);
}
}));
override fun updateScope(block: (Composer, Int) -> Unit) { this.block = block }
fun compose(composer: Composer) {
block?.invoke(composer, 1) ?: error("Invalid restart scope")
}
Skippable Composables
構成可能関数のスキップとは、構成可能関数のパラメータが以前と同じである場合にskipが発生する可能性があることを意味し、これは構成可能関数の数を意味する.
同様に、簡単なコードを見てみましょう.
@Composable
fun Google(number: Int) {
Address(
number=number,
street="Amphitheatre Pkwy",
city="Mountain View",
state="CA"
zip="94043"
)
}
以上のコードの変換コード.@Composable
public static final void Google(final int number, @Nullable Composer $composer, final int $changed) {
$composer = $composer.startRestartGroup(-1476322213);
...
int $dirty = $changed;
if (($changed & 14) == 0) {
$dirty = $changed | ($composer.changed(number) ? 4 : 2);
}
if (($dirty & 11) == 2 && $composer.getSkipping()) {
$composer.skipToGroupEnd();
} else {
Address(
number,
LiveLiterals$SimpleComposeSampleKt.INSTANCE.String$arg-1$call-Address$fun-Google(),
LiveLiterals$SimpleComposeSampleKt.INSTANCE.String$arg-2$call-Address$fun-Google(),
LiveLiterals$SimpleComposeSampleKt.INSTANCE.String$arg-3$call-Address$fun-Google(),
LiveLiterals$SimpleComposeSampleKt.INSTANCE.String$arg-4$call-Address$fun-Google(),
$composer,
14 & $dirty
);
}
...
}
スキップ可能な部分のコードだけを見せます$changedという静的intデータのビット演算により、パラメータの値が変更されたかどうかを決定し、スキップできるかどうかを決定します.
これらのパラメータの値は、Corpose CompilerによってSlot Table、$Corposerにデータが格納されます.changedからslotテーブルからデータを取り出します.
slotテーブルから抽出したデータを比較して、スキップできるかどうかを確認します.
Metrics File with Project Code
メトリックをもう一度確認しましょう.
app_debug-module.json
{
"skippableComposables": 6,
"restartableComposables": 7,
"readonlyComposables": 0,
"totalComposables": 7,
...
}
app_debug-composables.txt
restartable scheme("[androidx.compose.ui.UiComposable]") fun UserProfile(
unstable user: User
)
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun WrappedUserProfile(
stable userUiState: UserUiState
)
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun OtherContent(
stable otherState: Int
)
app_debug-composables.csv
namecomposableskippablerestartableUserProfile101WrappedUserProfile111OtherContent111
生成されたデータのコードを表示するには、次の手順に従います.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val viewModel: MainViewModel = viewModel()
val otherState by viewModel.otherState.collectAsState()
val userState by viewModel.wrappedUser.collectAsState()
val user by viewModel.user.collectAsState()
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween
) {
UserProfile(user)
WrappedUserProfile(userUiState = userState)
Button(viewModel::onButtonClick) {
Text(text = "Set User")
}
OtherContent(otherState = otherState)
Button(viewModel::onOtherAction) {
Text(text = "Other Action")
}
}
}
}
}
@Composable
fun UserProfile(user: User) {
println("User Profile Composable")
Text(text = user.name)
}
@Composable
fun WrappedUserProfile(userUiState: UserUiState) {
println("Wrapped User Profile Composable")
Text(text = userUiState.user.name)
}
@Composable
fun OtherContent(otherState: Int) {
println("Other Content Composable")
Text(text = otherState.toString())
}
Composeの予想通りにSkipまたはRecompositionが発生したかどうかを確認することを目的としています.そのため、全体的なデータを表示するには、app_debug-module.jsonを表示し、各構成可能な関数の逆コンパイル結果を表示します.app_debug-composables.txtapp_debug-composables.csv.app debug-composiblesは、コードのmetricsを分析するために使用されます.txtを表示します.
restartable scheme("[androidx.compose.ui.UiComposable]") fun UserProfile(
unstable user: User
)
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun WrappedUserProfile(
stable userUiState: UserUiState
)
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun OtherContent(
stable otherState: Int
)
プレゼンテーションレイヤで構成されたWrappedユーザー、OtherStateをパラメータとして渡すWrappedUserProfile、およびOtherContextには通常スキップ機能があり、ドメインレイヤで構成されたユーザーモデルを直接使用するUSerProfileにはスキップ機能がありません.したがって、正しい動作を確認するには、@Stableまたは@Immutable Annotation(前のシリーズなど)を貼り付ける必要があります.
プロジェクトコードは下にあります.
https://github.com/TaehoonLeee/multi-module-compose-model-test
References
Reference
この問題について(解析jetpack合成ジャンプ問題-metrics), 我々は、より多くの情報をここで見つけました https://velog.io/@ams770/jetpack-compose-skippable-issue-2-metricsテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol