الإنشاء والمكتبات الأخرى

يمكنك استخدام مكتباتك المفضّلة في ميزة "الإنشاء". يصف هذا القسم كيفية دمج عدد قليل من المكتبات الأكثر فائدة.

النشاط

لاستخدام Compose في نشاط، يجب استخدام ComponentActivity، وهي فئة فرعية من Activity تقدّم مكوّنات LifecycleOwner و المناسبة ل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() عقدًا بسيطًا. يؤدي النقر على الزر إلى بدء الطلب. يتمّ استدعاء دالة lambda اللاحقة لملف rememberLauncherForActivityResult() بعد أن يختار المستخدِم صورة ويعود إلى نشاط الإطلاق. يؤدي ذلك إلى تحميل الصورة المحدّدة باستخدام rememberImagePainter()دالة في Coil.

يمكن استخدام أي فئة فرعية من ActivityResultContract كالوسيطة الأولى لدالة rememberLauncherForActivityResult(). وهذا يعني أنّه يمكنك استخدام هذه الطريقة لطلب المحتوى من إطار العمل وفي أنماط شائعة أخرى. يمكنك أيضًا إنشاء عقود مخصّصة واستخدامها مع هذه التقنية.

جارٍ طلب أذونات التشغيل

يمكن استخدام Activity Result API وrememberLauncherForActivityResult() الموضّحين أعلاه للقيام بما يلي: طلب أذونات وقت التشغيل باستخدام RequestPermission عقد إذن واحد أو RequestMultiplePermissions عقد لأذونات متعددة.

يمكن أيضًا استخدام مكتبة أذونات المصاحب كطبقة فوق واجهات برمجة التطبيقات هذه لربط الحالة الممنوحة الحالية ل الأذونات بالحالة التي يمكن لواجهة مستخدِم "الإنشاء" استخدامها.

التعامل مع زر الرجوع في النظام

لتوفير ميزة التنقل للخلف المخصّصة وتجاوز السلوك التلقائي لزر الرجوع في النظام من داخل العنصر القابل للتجميع، يمكن للعنصر القابل للتجميع استخدام BackHandler لاعتراض هذا الحدث:

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

تتحكّم الوسيطة الأولى في ما إذا كان BackHandler مفعّلاً حاليًا، ويمكنك استخدام هذه الوسيطة لإيقاف معالِجك مؤقتًا استنادًا إلى حالة المكوّن. سيتمّ استدعاء دالة lambda اللاحقة إذا بدأ المستخدم حدثًا للعودة إلى النظام، وكان دالة BackHandler مفعّلة حاليًا.

ViewModel

إذا كنت تستخدم مكتبة Architecture Components ViewModel، يمكنك الوصول إلى ViewModel من أي عنصر قابل للتجميع من خلال استدعاء الدالة viewModel(). أضف التبعية التالية إلى ملف Gradle:

رائع

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

Kotlin

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

يمكنك بعد ذلك استخدام الدالة viewModel() في التعليمة البرمجية.

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

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

تعرِض دالة viewModel() 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 ونطاقها. إذا كان العنصر القابل للتجميع مكتفيًا ذاتيًا، ننصحك باستخدام Hilt لحقن ViewModel لتجنُّب الحاجة إلى تمرير التبعيات من العناصر القابلة للتجميع الرئيسية.

إذا كانت ViewModel تحتوي على تبعيات، تأخذ viewModel() مَعلمة اختيارية ViewModelProvider.Factory.

لمزيد من المعلومات عن ViewModel في Compose وكيفية استخدام النُسخ مع مكتبة Navigation 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. على سبيل المثال، في هذا الرمز البرمجي، تتم إعادة تركيب ShowData كلّما بثّexampleLiveData قيمة جديدة.

// 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)
    }
}

العمليات غير المتزامنة في ميزة "الإنشاء"

يتيح لك Jetpack Compose تنفيذ عمليات غير متزامنة باستخدام سلاسل الاستدعاء المتعدّدة من داخل العناصر القابلة للتجميع.

اطّلِع على واجهات برمجة التطبيقات LaunchedEffect وproduceState وrememberCoroutineScope في مستندات التأثيرات الجانبية للحصول على مزيد من المعلومات.

يقدّم مكوّن التنقّل دعمًا لتطبيقات Jetpack Compose. للحصول على مزيد من المعلومات، يمكنك الاطّلاع على التنقّل باستخدام ميزة Compose ونقل البيانات في Jetpack التنقل إلى ميزة "إنشاء التنقل".

Hilt

Hilt هو الحل المقترَح لإدخال التبعية في تطبيقات Android، وتعمل بسلاسة مع ميزة Compose.

تستخدم دالة viewModel() المذكورة في قسم ViewModel تلقائيًا ViewModel التي تنشئها Hilt باستخدام التعليق التوضيحي @HiltViewModel. وقد قدّمنا مستندات تتضمّن معلومات حول دمج Hilt's ViewModel.

@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 وNavigation

يمكن أيضًا دمج Hilt مع مكتبة Navigation Compose. أضف التبعيات الإضافية التالية إلى ملف Gradle الخاص بك:

رائع

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

Kotlin

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

عند استخدام ميزة "إنشاء مسار التنقّل"، استخدِم دائمًا الدالة القابلة للتجميع hiltViewModel للحصول على مثيل من @HiltViewModel ViewModel المُشارَك عليه تعليقات توضيحية. ويمكن استخدام هذه الطريقة مع الأجزاء أو الأنشطة التي تتم إضافة تعليقات توضيحية إليها باستخدام @AndroidEntryPoint.

على سبيل المثال، إذا كان ExampleScreen وجهة في رسم بياني للتنقّل، اتصل بـ hiltViewModel() للحصول على مثيل من ExampleViewModel على مستوى الوجهة كما هو موضّح في مقتطف الرمز البرمجي أدناه:

// 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)
            }
        }
    }
}

ترقيم الصفحات

تسهِّل عليك مكتبة الفهرسة carregar تحميل البيانات تدريجيًا، وهي متوافقة مع ميزة "الإنشاء". تحتوي صفحة إصدار الصفحات على معلومات حول اعتماد paging-compose الإضافية التي يجب إضافتها إلى المشروع وإصداره.

في ما يلي مثال على واجهات برمجة تطبيقات Compose في مكتبة Paging:

@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

يمكنك استخدام مكتبة إنشاء خرائط لتوفير "خرائط Google" في تطبيقك. في ما يلي مثال على الاستخدام:

@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"
        )
    }
}