Jetpack Component(5)-負効果


この文章はJetpackCompose公式ドキュメント-サブタイトル効果を読んで整理したものです.
複合体はシード効果(Side-effect)を持つことはできません.ただし、Componentの動作が外部状態を変更する必要がある場合は、管理環境で副作用を呼び出してコンポーネントのライフサイクルを識別する必要があります.
「アクセシビリティ」とは、構成可能な関数の範囲外でアプリケーションのステータスを変更することです.Componentosableは負の値の効果を持つべきではありませんが、場合によってはステータスの変更が必要になります.この記事では,CorposableにおけるAPIの付随効果についてまとめる.😌.

ステータスと効果の使用例


補助効果を使用する場合は、EffectAPIを使用して補助効果を予測可能に実行する必要があります.
Effect:UIをエクスポートせず、コンパイル完了時に効果付きの構成可能な関数を実行

LaunchedEffect:グループ内でcoutinを実行する


Corposableから「停止関数」(Suspend)を安全に呼び出すには、LauncedEffect Component Componentを使用する必要があります.
@Composable
fun MyScreen(
    state: UiState<List<Movie>>,
    scaffoldState: ScaffoldState = rememberScaffoldState()
) {

    if (state.hasError) {

        LaunchedEffect(scaffoldState.snackbarHostState) {
            scaffoldState.snackbarHostState.showSnackbar(
                message = "Error message",
                actionLabel = "Retry message"
            )
        }
    }

    Scaffold(scaffoldState = scaffoldState) {
        /* ... */
    }
}
上の関数ではstate.hasErrorがtrueの場合、「coutin」(showSnakbar)がトリガーされます.そうしないと、coutinはキャンセルされます.
LaunchedEffectはComposableのライフサイクルに従います.
実行ポイント終了ポイント再実行の条件設定Enter構成Leaveparamの変更
LaunchedEffectのパラメータの値が変更された場合、既存のcoutineを終了し、新しいcoutineでsuspend関数を実行します.

rememberCoroutineScope-プログラム可能なコンポーネントの外でcoutineを実行


LaunchedEffectは結合可能な関数であるため、結合可能な関数内でのみ呼び出されます.したがって、構成可能な部分の外でcoroutine scopeを取得するには、rememberCoroutineScopeを使用する必要があります.
rememberCoroutineScopeは、呼び出された複合ライフサイクルに基づいて起動/終了します.
運転点終了点再運転の条件設定Enter構成LeaveX
@Composable
fun Screen(scaffoldState: ScaffoldState = rememberScaffoldState()) {

    val scope = rememberCoroutineScope()

    Scaffold(scaffoldState = scaffoldState) {
        Column {
            Button(
                onClick = {
                    scope.launch { // snackBar를 표시하기 위해 새로운 coroutine을 생성합니다.
                        scaffoldState.snackbarHostState.showSnackbar("Something happened!")
                    }
                }
            ) {
                Text("Press me")
            }
        }
    }
}
Screenの組合せが終了すると、scopeのcoroutineもキャンセルされます.そのため、Screenを離れるとSnakbarもキャンセルされます.

rememberUpdateState:値が変更された場合は、再起動すべきでない効果の値を参照してください。


LaunchedEffectは、内部ブロックの値が変更されたときに既存のcoroutineをキャンセルし、新しいcoroutineを実行します.
LaunchedEffect内部の値を変更する必要があるが、新しいCoroutineを実行する必要がない場合、または効果が長く続く場合に操作を維持する必要がある場合は、rememberUpdateStateを使用します.
@Composable
fun ShowSnackBar(scaffoldState: ScaffoldState = rememberScaffoldState(), timeoutText: String) {
    val currentTimeoutText by rememberUpdatedState(timeoutText)

    LaunchedEffect(true) {
        try {
            delay(3000L)
            scaffoldState.snackbarHostState.showSnackbar(currentTimeoutText)
        } catch (ce: CancellationException) {

        }
    }

}
時間テキストが変化してもLaunchedEffectは再起動せず(パラメータがtrueをロックしているため)、3秒後にSnakbarを解放します.
rememberUpdatedStateを使用しないと、timeoutTextが変化しても同じSnakbarが表示されます.(lambda captureはfinal形式で値を入力するため)

DisposableEffect:クリーンアップが必要な効果


DisposableEffectの動作はLaunchedEffectと同じです.ただし、DinsposableEffectsms ComponentLiftで終わると、いつもonDispose{.}が呼び出されます.
@Composable
fun HomeScreen(
    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
    onStart: () -> Unit,
    onStop: () -> Unit
) {
    // 새로운 람다식이 들어왔을 때 안전하게 실행할 수 있도록 rememberUpdatedState를 사용합니다.
    val currentOnStart by rememberUpdatedState(onStart)
    val currentOnStop by rememberUpdatedState(onStop)

    // lifecycleOwner가 변경되면 DisposableEffect내에 있는 코루틴이 다시 시작됩니다.
    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_START) {
                currentOnStart()
            } else if (event == Lifecycle.Event.ON_STOP) {
                currentOnStop()
            }
        }

        lifecycleOwner.lifecycle.addObserver(observer)

        // Effect가 Composition을 떠날 때 observer를 삭제합니다.
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }

    /* Home screen content */
}
DisposableEffectは、onDispose部分をコードブロックの最後の一言として記録する.そうでない場合、IDEにエラーが表示されます.

productState:非Component状態をComponent状態に変換


Corposeは、State<T>によって状態を観察し、Corposeを更新する.したがって、CommoseでFlowLiveDataRxJavaなどの観察可能なタイプを使用するには、それらをStateに変換する必要がありますが、ProductStateはその一部です.
観察中の値が変更された場合、productStateはState<T>を返します.
Componentは、Flow、LiveDataをStateに変換する関数をサポートします.
  • LiveData<T> : observeAsState(initial: R)
    observerAsStateを使用するには、implementation "androidx.compose.runtime:runtime-livedata:$compose_version"を追加する必要があります.
  • Flow<T> : collectAsState(initial: R, context: CoroutineContext)
  • DerivedStateOf:1つ以上のステータスオブジェクトを別のステータスに変換


    この関数は、他のステータスから派生するステータスが必要な場合に使用されます.
    @Composable
    fun TodoList(highPriorityKeywords: List<String> = listOf("Review", "Unblock", "Compose")) {
    
        val todoTasks = remember { mutableStateListOf<String>() }
    
        val highPriorityTasks by remember(highPriorityKeywords) {
            derivedStateOf { todoTasks.filter { it.containsWord(highPriorityKeywords) } }
        }
    
        Box(Modifier.fillMaxSize()) {
            LazyColumn {
                items(highPriorityTasks) { /* ... */ }
                items(todoTasks) { /* ... */ }
            }
        }
    }
    上記のコードでは、derivedStateOf {}は、todoTasksの変更時に優先度の高いTask計算を実行し、UIを更新することを保証する.
    高優先度Tasksの計算にはコストがかかるため、高優先度Keywordsが変更された場合にのみ計算が必要になります.このため、HighPriorityTaskはDerivedStateOfに分類される.

    snapshotFlow:Componentの状態をFlowに変換する


    snapshotFlowを使用して、State<T>オブジェクトをコールドFlowに変換します.
    snapshotFlowブロックで読み込まれたStateオブジェクトが変更され、新しい値が以前にエクスポートされた値と異なる場合、Flowは新しい値をコレクタにエクスポートします.
    val listState = rememberLazyListState()
    
    LaunchedEffect(listState) {
        snapshotFlow { listState.firstVisibleItemIndex } // Flow<T>를 반환합니다.
            .map { index -> index > 0 }
            .distinctUntilChanged()
            .filter { it == true }
            .collect {
                MyAnalyticsService.sendScrolledPastFirstItemEvent()
            }
    }

    再起動効果


    いくつかの複合効果(例えば、LaunchedEffectproduceState、およびDisposableEffect)は、実行中の効果をキャンセルし、新しい効果を実行するために複数のパラメータを受け入れる.パラメータを変更すると、新しい効果が得られます.
    効果を再実行するには、次の2つの要因を考慮します.
  • は、必要以上に再起動すると、アプリケーションにエラーが発生する可能性があります.
  • 必要以上に機能を再起動すると、効率が低下する可能性があります.
  • 変数を変更するときに効果を再開する必要がない場合は、その変数をrememberUpdateStateにパッケージする必要があります.
    効果に使用する変数は、効果の組み合わせのパラメータとして追加するか、rememberUpdateStateを使用する必要があります.

    鍵の定数として使用


    キーには定数(trueなど)を含めることができます.これにより、LaunchedEffectはcoroutineを1回のみ実行します.したがって、定数を使用する場合は慎重にしなければならない.
    これでComponentの効果がわかりました.次の記事では、Componentの手順について説明します.最後まで読んでくれてありがとう.楽しく開発してください.🤗.

    リファレンス


    Componentの付加効果
    愚痴のリアルブログ
    Jetpack Componentの高度な状態と副作用