استفاده از روال‌های مشترک Kotlin با عناصر آگاه از چرخه حیات

روال‌های مشترک Kotlin یک API ارائه می‌دهد که به شما امکان می‌دهد کد ناهمگام بنویسید. با روتین‌های همکار Kotlin، می‌توانید CoroutineScope تعریف کنید که به شما کمک می‌کند زمان اجرای روتین‌های همکار را مدیریت کنید. هر عملیات ناهم‌زمان در یک محدوده خاص اجرا می‌شود.

عناصر آگاه از چرخه زندگی پشتیبانی درجه یک از روتین‌های همکار برای حوزه‌های منطقی در برنامه شما ارائه می‌دهند. این سند توضیح می‌دهد چگونه از روتین‌های همکار به‌طور مؤثر با عناصر آگاه از چرخه زندگی استفاده کنید.

افزودن وابستگی‌ها

محدوده‌های داخلی روتین همکار که در این موضوع شرح داده شده است در میانای برنامه‌سازی کاربردی چرخه حیات قرار دارند. هنگام استفاده از این دامنه‌ها، حتماً وابستگی‌های مناسب را اضافه کنید.

  • برای ابزارهای کمکی ViewModel در Compose، از implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version") استفاده کنید.
  • برای برنامه‌های کمکی «چرخه حیات» در «نوشتن»، از implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version") استفاده کنید.

محدوده‌های روتین همکار آگاه از چرخه حیات

کتابخانه‌های Compose و «چرخه حیات» دامنه‌های داخلی زیر را ارائه می‌دهند که می‌توانید در برنامه‌تان استفاده کنید.

ViewModelScope

یک ViewModelScope برای هر ViewModel در برنامه‌تان تعریف شده است. هر روال هم‌زمان که در این محدوده راه‌اندازی شود، اگر ViewModel پاک شود به‌طور خودکار لغو می‌شود. در اینجا، روتین‌های همکار برای زمانی که کاری دارید که باید فقط درصورت فعال بودن ViewModel انجام شود مفید هستند. برای مثال، اگر درحال محاسبه برخی‌از داده‌ها برای چیدمان هستید، باید کار را به ViewModel محدود کنید تا اگر ViewModel پاک شد، کار به‌طور خودکار لغو شود و از مصرف منابع جلوگیری شود.

می‌توانید ازطریق دارایی viewModelScope ViewModel به CoroutineScope ViewModel دسترسی پیدا کنید، همان‌طور که در مثال زیر نشان داده شده است:

class MyViewModel: ViewModel() {
    init {
        viewModelScope.launch {
            // Coroutine that will be canceled when the ViewModel is cleared.
        }
    }
}

برای موارد استفاده پیشرفته‌تر، می‌توانید CoroutineScope سفارشی را مستقیماً به سازنده ViewModel ارسال کنید تا جایگزین viewModelScope پیش‌فرض شود. این رویکرد کنترل و انعطاف‌پذیری بیشتری ارائه می‌دهد، به‌ویژه برای:

  • آزمایش: به شما امکان می‌دهد TestScope تزریق کنید و کنترل زمان و درستی‌سنجی رفتار روتین‌های همکار در آزمون‌های واحد را آسان‌تر می‌کند.

  • پیکربندی سفارشی: می‌توانید محدوده را با CoroutineDispatcher خاصی (مثل Dispatchers.Default برای محاسبات سنگین) یا CoroutineExceptionHandler سفارشی قبل‌از اینکه ViewModel کارش را شروع کند پیکربندی کنید.

حوزه‌های محدود به ترکیب

عوارض جانبی مانند پویانمایی‌ها، تماس‌های شبکه، یا زمان‌سنج‌ها باید در محدوده چرخه حیات عنصر ترکیبی باشند. به این ترتیب، وقتی یک عنصر ترکیبی از صفحه خارج می‌شود (از ترکیب خارج می‌شود)، هرگونه روتین هم‌زمان درحال اجرا به‌طور خودکار لغو می‌شود تا از نشت حافظه جلوگیری شود.

‫Compose میانای برنامه‌سازی کاربردی LaunchedEffect را برای مدیریت محدوده «ترکیب» به‌صورت اعلامی ارائه می‌دهد.

‫LaunchedEffect CoroutineScope ایجاد می‌کند که به شما امکان می‌دهد توابع تعلیق را اجرا کنید. دامنه به چرخه حیات «ترکیب» عنصر ترکیبی مرتبط است، نه به «چرخه حیات» «فعالیت» میزبان.

  • ورود: روتین همکار زمانی شروع می‌شود که عنصر ترکیبی وارد ترکیب می‌شود.
  • خروج: وقتی عنصر ترکیب‌پذیر از ترکیب خارج می‌شود، روتین هم‌زمان لغو می‌شود.
  • راه‌اندازی مجدد: اگر هریک از کلیدهای ارسال‌شده به LaunchedEffect تغییر کند، روال هم‌زمان موجود لغو می‌شود و روال هم‌زمان جدیدی راه‌اندازی می‌شود.

مثال زیر نحوه استفاده از LaunchedEffect برای ایجاد پویانمایی تپش‌دار را نشان می‌دهد. روال همکار به حضور عنصر ترکیبی در ترکیب گره خورده است و به تغییرات پیکربندی واکنش نشان می‌دهد:

// Allow the pulse rate to be configured, so it can be sped up if the user is running
// out of time
var pulseRateMs by remember { mutableLongStateOf(3000L) }
val alpha = remember { Animatable(1f) }
LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes
    while (isActive) {
        delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user
        alpha.animateTo(0f)
        alpha.animateTo(1f)
    }
}

برای اطلاعات بیشتر درباره LaunchedEffect، عوارض جانبی در «نوشتن» را ببینید.

مجموعه جریان آگاه از چرخه زندگی

برای جمع‌آوری ایمن جاری‌سازی‌ها در Jetpack Compose، از collectAsStateWithLifecycle API استفاده کنید. این تابع واحد Flow را به شیء «نوشتن» State تبدیل می‌کند و به‌طور خودکار اشتراک چرخه حیات را برای شما مدیریت می‌کند. به‌طور پیش‌فرض، جمع‌آوری وقتی چرخه حیات STARTED است شروع می‌شود و وقتی چرخه حیات STOPPED است متوقف می‌شود. برای ملغی کردن این رفتار پیش‌فرض، پارامتر minActiveState را با روش چرخه حیات موردنظرتان مثل Lifecycle.State.RESUMED ارسال کنید.

مثال زیر نحوه جمع‌آوری StateFlow یک ViewModel را در ترکیب‌پذیر نشان می‌دهد:

@Composable
private fun ConversationScreen(
    conversationViewModel: ConversationViewModel = viewModel()
) {

    val messages by conversationViewModel.messages.collectAsStateWithLifecycle()

    ConversationScreen(
        messages = messages,
        onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) }
    )
}

@Composable
private fun ConversationScreen(
    messages: List<Message>,
    onSendMessage: (Message) -> Unit
) {

    MessagesList(messages, onSendMessage)
    /* ... */
}

جمع‌آوری موازی چندین جریان

در «نوشتن»، می‌توانید با تعریف چندین متغیر حالت، چندین جاری‌سازی را به‌صورت موازی جمع‌آوری کنید. ازآنجایی‌که collectAsStateWithLifecycle حوزه زیربنایی خود را مدیریت می‌کند، جمع‌آوری موازی به‌طور خودکار انجام می‌شود:

@Composable
fun DashboardScreen(viewModel: DashboardViewModel = viewModel()) {
    // Both flows are collected safely in parallel and will emit updates when either changes, the composables will recompose
    val userData by viewModel.userFlow.collectAsStateWithLifecycle()
    val feedData by viewModel.feedFlow.collectAsStateWithLifecycle()

    // ...
}

محاسبه ناهمزمان مقادیر بااستفاده از «جریان‌ها»

وقتی نیاز دارید مقادیر را به‌صورت ناهمگام محاسبه کنید، از StateFlow با عامل stateIn استفاده کنید.

تکه زیر از Flow استاندارد استفاده می‌کند که به StateFlow تبدیل شده است. پارامتر WhileSubscribed(5000) اشتراک را برای پنج ثانیه پس‌از ناپدید شدن واسط کاربر فعال نگه می‌دارد تا تغییرات پیکربندی را مدیریت کند.

val uiState: StateFlow<Result> = flow {
    emit(repository.fetchData())
}
.stateIn(
    scope = viewModelScope,
    started = SharingStarted.WhileSubscribed(5_000),
    initialValue = Result.Loading
)

از collectAsStateWithLifecycle برای تبدیل مقادیر جمع‌آوری‌شده به «نوشتن» State استفاده کنید تا رابط کاربری شما بتواند هر زمان که داده‌ها تغییر می‌کند به‌صورت واکنشی به‌روز شود.

برای اطلاعات بیشتر درباره حالت، حالت و Jetpack Compose را ببینید.

منابع بیشتر

محتوا را می‌بیند

نمونه‌ها