‫Compose و کتابخانه‌های دیگر

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

فعالیت

برای استفاده از «نگارش» در فعالیت، باید از ComponentActivity، زیرکلاسی از Activity که LifecycleOwner مناسب و عناصر «نگارش» را ارائه می‌دهد استفاده کنید. این کتابخانه همچنین میاناهای برنامه‌سازی کاربردی اضافه‌ای ارائه می‌دهد که کد شما را از جای‌گزین کردن روش‌ها در کلاس فعالیتتان جدا می‌کند. Activity Compose این «میاناهای برنامه‌سازی کاربردی» را در اختیار عناصر ترکیبی قرار می‌دهد تا دیگر نیازی به ملغی کردن روش‌های خارج از عناصر ترکیبی یا بازیابی نمونه Activity صریح نباشد. علاوه‌براین، این «میاناهای برنامه‌سازی کاربردی» تضمین می‌کنند که فقط یک‌بار مقداردهی اولیه شوند، از ترکیب مجدد جان سالم به‌در ببرند، و اگر عنصر ترکیبی از ترکیب برداشته شود، به‌درستی پاک‌سازی شوند.

نتیجه فعالیت

میانای برنامه‌سازی کاربردی rememberLauncherForActivityResult() به شما امکان می‌دهد از یک فعالیت نتیجه بگیرید در عنصر ترکیبی:

@Composable
fun GetContentExample() {
    var imageUri by remember { mutableStateOf<Uri?>(null) }
    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
        imageUri = uri
    }
    Column {
        Button(onClick = { launcher.launch("image/*") }) {
            Text(text = "Load Image")
        }
        Image(
            painter = rememberAsyncImagePainter(imageUri),
            contentDescription = "My Image"
        )
    }
}

این مثال یک GetContent() قرارداد ساده را نشان می‌دهد. با تک‌ضرب زدن روی دکمه، درخواست راه‌اندازی می‌شود. وقتی کاربر تصویری را انتخاب می‌کند و به فعالیت راه‌اندازی برمی‌گردد، لامبدای انتهایی برای rememberLauncherForActivityResult() فراخوانی می‌شود. این کار تصویر انتخاب‌شده را بااستفاده از تابع rememberImagePainter() بار می‌کند.

هر زیرکلاسی از ActivityResultContract می‌تواند به‌عنوان اولین آرگومان برای rememberLauncherForActivityResult() استفاده شود. این یعنی می‌توانید از این تکنیک برای درخواست محتوا از چارچوب و در الگوهای رایج دیگر استفاده کنید. همچنین می‌توانید قراردادهای سفارشی خودتان را ایجاد کنید و از آن‌ها با این تکنیک استفاده کنید.

درحال درخواست اجازه‌های زمان اجرا

از همان «میانای برنامه‌سازی کاربردی نتیجه فعالیت» و rememberLauncherForActivityResult() توضیح داده‌شده در بالا می‌توان برای درخواست اجازه‌های زمان اجرا بااستفاده از RequestPermission قرارداد برای یک اجازه یا RequestMultiplePermissions قرارداد برای چند اجازه استفاده کرد.

از کتابخانه «اجازه‌های همراه» همچنین می‌توان به‌عنوان لایه‌ای بالای آن میاناهای برنامه‌سازی کاربردی استفاده کرد تا وضعیت اعطاشده فعلی اجازه‌ها را به «وضعیت» نگاشت کند که «میانای کاربر Compose» شما می‌تواند از آن استفاده کند.

مدیریت دکمه برگشتن سیستم

برای ارائه پیمایش به عقب سفارشی و ملغی کردن عملکرد پیش‌فرض دکمه بازگشت سیستم از داخل ترکیب‌شدنی، ترکیب‌شدنی شما می‌تواند از BackHandler برای رهگیری آن رویداد استفاده کند:

var backHandlingEnabled by remember { mutableStateOf(true) }
BackHandler(backHandlingEnabled) {
    // Handle back press
}

اولین آرگومان کنترل می‌کند که آیا BackHandler درحال‌حاضر فعال است یا نه؛ می‌توانید از این آرگومان برای غیرفعال کردن موقت کنترل‌کننده خود براساس وضعیت مؤلفه‌تان استفاده کنید. اگر کاربر رویداد برگشت سیستم را راه‌اندازی کند و BackHandler درحال‌حاضر فعال باشد، لامبدای دنباله‌دار فراخوانی خواهد شد.

ViewModel

اگر از کتابخانه عناصر معماری ViewModel استفاده می‌کنید، می‌توانید با فراخوانی تابع viewModel() از هر عنصر ترکیب‌پذیری به ViewModel دسترسی پیدا کنید. وابستگی زیر را به فایل Gradle خود اضافه کنید:

شیک

dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0'
}

کاتلین

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0")
}

سپس می‌توانید از تابع viewModel() در کدتان استفاده کنید.

class MyViewModel : ViewModel() { /*...*/ }

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    // use viewModel here
}

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

برای مثال، اگر از عنصر ترکیبی در فعالیتی استفاده شود، viewModel() تا زمانی که فعالیت تمام شود یا فرایند متوقف شود، نمونه یکسانی را برمی‌گرداند.

class MyViewModel : ViewModel() { /*...*/ }
// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    // Returns the same instance as long as the activity is alive,
    // just as if you grabbed the instance from an Activity or Fragment
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

@Composable
fun MyScreen2(
    viewModel: MyViewModel = viewModel() // Same instance as in MyScreen
) { /* ... */ }

رهنمودهای استفاده

معمولاً در ViewModel نمونه در سطح صفحه ترکیب‌پذیرها دسترسی دارید، یعنی نزدیک به ترکیب‌پذیر ریشه‌ای که از فعالیت، تکه، یا مقصد «گراف پیمایش» فراخوانی می‌شود. دلیل این است که ViewModels به‌طور پیش‌فرض به آن اشیای سطح صفحه محدود می‌شوند. درباره ViewModel چرخه حیات و محدوده بیشتر بخوانید.

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

می‌توانید از ViewModel نمونه برای مدیریت وضعیت ترکیب‌پذیرهای سطح زیرصفحه استفاده کنید، اما از ViewModel چرخه حیات و محدوده آن آگاه باشید. اگر composable خوداتکا است، می‌توانید از Hilt برای تزریق ViewModel استفاده کنید تا مجبور نباشید وابستگی‌ها را از composable والد منتقل کنید.

اگر ViewModel شما وابستگی داشته باشد، viewModel() یک ViewModelProvider.Factory اختیاری را به‌عنوان پارامتر می‌گیرد.

برای اطلاعات بیشتر درباره ViewModel در «نوشتن» و نحوه استفاده از نمونه‌ها با کتابخانه «نوشتن با پیمایش»، یا فعالیت‌ها و تکه‌ها، به اسناد قابلیت همکاری مراجعه کنید.

جریان‌های داده‌ها

‫Compose با افزونه‌هایی برای پرطرفدارترین راه‌حل‌های مبتنی بر جاری‌سازی Android ارائه می‌شود. هریک از این افزونه‌ها توسط یک آرتیفکت متفاوت ارائه می‌شود:

  • ‫LiveData.observeAsState() در آرتیفکت androidx.compose.runtime:runtime-livedata:$composeVersion گنجانده شده است.
  • ‫Flow.collectAsState() به وابستگی‌های اضافی نیاز ندارد.
  • ‫Observable.subscribeAsState() در androidx.compose.runtime:runtime-rxjava2:$composeVersion یا androidx.compose.runtime:runtime-rxjava3:$composeVersion خروجی ساختاریافته گنجانده شده است.

این آرتیفکت‌ها به‌عنوان شنونده ثبت می‌شوند و مقادیر را به‌صورت State نشان می‌دهند. هرگاه مقدار جدیدی منتشر شود، Compose آن بخش‌هایی از واسط کاربر را که از آن state.value استفاده می‌کنند بازسازی می‌کند. برای مثال، در این کد، هر بار که exampleLiveData مقدار جدیدی منتشر می‌کند، ShowData دوباره ترکیب می‌شود.

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val dataExample = viewModel.exampleLiveData.observeAsState()

    // Because the state is read here,
    // MyScreen recomposes whenever dataExample changes.
    dataExample.value?.let {
        ShowData(dataExample)
    }
}

عملیات غیرهمگام در Compose

‫Jetpack Compose به شما امکان می‌دهد عملیات ناهمزمان را بااستفاده از روتین‌های همکار از درون عناصر ترکیبی‌تان اجرا کنید.

برای کسب اطلاعات بیشتر، میاناهای برنامه‌سازی کاربردی LaunchedEffect،‏ produceState، و rememberCoroutineScope را در مستندات اثرات جانبی ببینید.

عنصر «پیمایش» از برنامه‌های Jetpack Compose پشتیبانی می‌کند. برای اطلاعات بیشتر، پیمایش با Compose و انتقال «پیمایش Jetpack» به «پیمایش Compose» را ببینید.

Hilt

‫Hilt راهکار توصیه‌شده برای تزریق وابستگی در برنامه‌های Android است و به‌صورت یکپارچه با Compose کار می‌کند.

تابع viewModel() که در بخش ViewModel ذکر شده است به‌طور خودکار از ViewModel استفاده می‌کند که Hilt با @HiltViewModel گزارمان می‌سازد. اسنادی با اطلاعاتی درباره ادغام ViewModel در Hilt ارائه کرده‌ایم.

@HiltViewModel
class MyViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: ExampleRepository
) : ViewModel() { /* ... */ }

// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

‫Hilt و پیمایش

‫Hilt با کتابخانه Navigation Compose نیز ادغام می‌شود. وابستگی‌های اضافی زیر را به فایل Gradle خود اضافه کنید:

شیک

dependencies {
    implementation 'androidx.hilt:hilt-navigation-compose:1.4.0'
}

کاتلین

dependencies {
    implementation("androidx.hilt:hilt-navigation-compose:1.4.0")
}

هنگام استفاده از «ترکیب پیمایش»، همیشه از تابع ترکیب‌پذیر hiltViewModel برای دریافت نمونه‌ای از @HiltViewModel حاشیه‌نویسی‌شده ViewModel استفاده کنید. این ویژگی با تکه‌کدها یا فعالیت‌هایی که با @AndroidEntryPoint نشانه‌گذاری شده‌اند کار می‌کند.

برای مثال، اگر ExampleScreen مقصد در گراف پیمایش باشد، برای دریافت نمونه‌ای از ExampleViewModel محدود به مقصد، همان‌طور که در تکه‌کد زیر نشان داده شده است، hiltViewModel() را فراخوانی کنید:

// import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun MyApp() {
    val navController = rememberNavController()
    val startRoute = "example"
    NavHost(navController, startDestination = startRoute) {
        composable("example") { backStackEntry ->
            // Creates a ViewModel from the current BackStackEntry
            // Available in the androidx.hilt:hilt-navigation-compose artifact
            val viewModel = hiltViewModel<MyViewModel>()
            MyScreen(viewModel)
        }
        /* ... */
    }
}

اگر نیاز دارید نمونه‌ای از ViewModel را که در مسیرهای پیمایش یا گراف پیمایش محدوده دارد بازیابی کنید، از تابع ترکیب‌پذیر hiltViewModel استفاده کنید و backStackEntry مربوطه را به‌عنوان پارامتر ارسال کنید:

// import androidx.hilt.navigation.compose.hiltViewModel
// import androidx.navigation.compose.getBackStackEntry

@Composable
fun MyApp() {
    val navController = rememberNavController()
    val startRoute = "example"
    val innerStartRoute = "exampleWithRoute"
    NavHost(navController, startDestination = startRoute) {
        navigation(startDestination = innerStartRoute, route = "Parent") {
            // ...
            composable("exampleWithRoute") { backStackEntry ->
                val parentEntry = remember(backStackEntry) {
                    navController.getBackStackEntry("Parent")
                }
                val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry)
                ExampleWithRouteScreen(parentViewModel)
            }
        }
    }
}

صفحه‌بندی

کتابخانه صفحه‌بندی بار کردن تدریجی داده‌ها را برایتان آسان‌تر می‌کند و در Compose پشتیبانی می‌شود. صفحه انتشار صفحه‌بندی حاوی اطلاعاتی درباره paging-compose وابستگی اضافی است که باید به پروژه و نسخه آن اضافه شود.

در اینجا نمونه‌ای از «میاناهای برنامه‌سازی کاربردی Compose» کتابخانه «صفحه‌بندی» آورده شده است:

@Composable
fun MyScreen(flow: Flow<PagingData<String>>) {
    val lazyPagingItems = flow.collectAsLazyPagingItems()
    LazyColumn {
        items(
            lazyPagingItems.itemCount,
            key = lazyPagingItems.itemKey { it }
        ) { index ->
            val item = lazyPagingItems[index]
            Text("Item is $item")
        }
    }
}

برای اطلاعات بیشتر درباره استفاده از «صفحه‌بندی» در «نوشتن»، مستندات «فهرست‌ها و شبکه‌ها» را بررسی کنید.

Maps

می‌توانید از کتابخانه Maps Compose برای ارائه Google Maps در برنامه‌تان استفاده کنید. در اینجا نمونه‌ای از استفاده آن آمده است:

@Composable
fun MapsExample() {
    val singapore = LatLng(1.35, 103.87)
    val cameraPositionState = rememberCameraPositionState {
        position = CameraPosition.fromLatLngZoom(singapore, 10f)
    }
    GoogleMap(
        modifier = Modifier.fillMaxSize(),
        cameraPositionState = cameraPositionState
    ) {
        Marker(
            state = remember { MarkerState(position = singapore) },
            title = "Singapore",
            snippet = "Marker in Singapore"
        )
    }
}