از کوروتین های کاتلین با اجزای آگاه از چرخه حیات استفاده کنید

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

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

وابستگی‌ها را اضافه کنید

محدوده‌های کوروتین داخلی که در این مبحث توضیح داده شده‌اند، در Lifecycle API موجود هستند. هنگام استفاده از این محدوده‌ها، حتماً وابستگی‌های مناسب را اضافه کنید.

  • برای ابزارهای ViewModel در Compose، از implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version") استفاده کنید.
  • برای ابزارهای Lifecycle در Compose، از implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version") استفاده کنید.

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

کتابخانه‌های Compose و Lifecycle، scopeهای داخلی زیر را ارائه می‌دهند که می‌توانید در برنامه خود از آنها استفاده کنید.

محدوده مدل نمایش

برای هر ViewModel در برنامه شما، یک ViewModelScope تعریف می‌شود. هر کوروتینی که در این scope راه‌اندازی شود، در صورت پاک شدن 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 تزریق کنید، که کنترل زمان و تأیید رفتار کوروتین را در تست‌های واحد آسان‌تر می‌کند.

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

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

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

Compose رابط برنامه‌نویسی کاربردی LaunchedEffect را برای مدیریت محدوده‌بندی Composition به صورت اعلانی ارائه می‌دهد.

LaunchedEffect یک CoroutineScope ایجاد می‌کند که به شما امکان می‌دهد توابع suspend را اجرا کنید. این scope به چرخه حیات Composition مربوط به composable گره خورده است، نه چرخه حیات Activity میزبان.

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

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

// 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 ، به بخش عوارض جانبی در Compose مراجعه کنید.

جمع‌آوری جریان آگاه از چرخه حیات

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

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

@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)
    /* ... */
}

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

در Compose، می‌توانید با تعریف چندین متغیر state، چندین جریان را به صورت موازی جمع‌آوری کنید. از آنجا که 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()

    // ...
}

محاسبه مقادیر به صورت غیرهمزمان با استفاده از Flowها

وقتی نیاز دارید مقادیر را به صورت غیرهمزمان محاسبه کنید، 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 برای تبدیل مقادیر جمع‌آوری‌شده به Compose State استفاده کنید، به طوری که رابط کاربری شما بتواند هر زمان که داده‌ها تغییر می‌کنند، به صورت واکنشی به‌روزرسانی شود.

برای اطلاعات بیشتر در مورد وضعیت، به وضعیت و Jetpack Compose مراجعه کنید.

منابع اضافی

محتوا را مشاهده می‌کند

نمونه‌ها

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}