लिखें और अन्य लाइब्रेरी

Compose में, अपनी पसंदीदा लाइब्रेरी का इस्तेमाल किया जा सकता है. इस सेक्शन में, कुछ सबसे काम की लाइब्रेरी को शामिल करने का तरीका बताया गया है.

ऐक्टिविटी

किसी ऐक्टिविटी में Compose का इस्तेमाल करने के लिए, ComponentActivity का इस्तेमाल करना ज़रूरी है. यह Activity की सबक्लास है. यह Compose को सही 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() तब लागू होता है, जब उपयोगकर्ता कोई इमेज चुनता है और लॉन्च करने वाली ऐक्टिविटी पर वापस आता है. इससे, चुनी गई इमेज को Coil के rememberImagePainter() फ़ंक्शन का इस्तेमाल करके लोड किया जाता है.

ActivityResultContract की किसी भी सबक्लास का इस्तेमाल, rememberLauncherForActivityResult() के पहले आर्ग्युमेंट के तौर पर किया जा सकता है. इसका मतलब है कि इस तकनीक का इस्तेमाल करके, फ़्रेमवर्क और अन्य सामान्य पैटर्न से कॉन्टेंट का अनुरोध किया जा सकता है. आपके पास अपने कस्टम कॉन्ट्रैक्ट बनाने और इस तकनीक के साथ उनका इस्तेमाल करने का विकल्प भी है.

रनटाइम अनुमतियों का अनुरोध करना

ऊपर बताए गए, ऐक्टिविटी के नतीजे के एपीआई और rememberLauncherForActivityResult() का इस्तेमाल, रनटाइम अनुमतियों का अनुरोध करने के लिए किया जा सकता है. इसके लिए, RequestPermission कॉन्ट्रैक्ट का इस्तेमाल एक अनुमति के लिए या RequestMultiplePermissions कॉन्ट्रैक्ट का इस्तेमाल एक से ज़्यादा अनुमतियों के लिए करें.

अनुमतियों के लिए, Accompanist Permissions लाइब्रेरी का इस्तेमाल भी किया जा सकता है. यह लाइब्रेरी, इन एपीआई के ऊपर एक लेयर के तौर पर काम करती है. इसकी मदद से, अनुमतियों के लिए मौजूदा दी गई स्थिति को स्टेट में मैप किया जा सकता है. इस स्टेट का इस्तेमाल, Compose यूज़र इंटरफ़ेस (यूआई) कर सकता है.

सिस्टम के 'वापस जाएं' बटन को हैंडल करना

अपने कंपोज़ेबल में, वापस जाएं' के लिए कस्टम नेविगेशन उपलब्ध कराने और सिस्टम के 'वापस जाएं' बटन के डिफ़ॉल्ट व्यवहार को ओवरराइड करने के लिए, कंपोज़ेबल, उस इवेंट को इंटरसेप्ट करने के लिए BackHandler का इस्तेमाल कर सकता है:

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

पहले आर्ग्युमेंट से यह कंट्रोल किया जाता है कि फ़िलहाल the BackHandler चालू है या नहीं. इस आर्ग्युमेंट का इस्तेमाल करके, अपने कॉम्पोनेंट की स्थिति के आधार पर, हैंडलर को कुछ समय के लिए बंद किया जा सकता है. अगर उपयोगकर्ता, सिस्टम के 'वापस जाएं' बटन को ट्रिगर करता है और फ़िलहाल BackHandler चालू है, तो ट्रेलिंग लैम्डा लागू होगा.

ViewModel

अगर Architecture Components ViewModel लाइब्रेरी का इस्तेमाल किया जाता है, तो viewModel() फ़ंक्शन को कॉल करके, किसी भी कंपोज़ेबल से ViewModel को ऐक्सेस किया जा सकता है. अपनी Gradle फ़ाइल में, यह डिपेंडेंसी जोड़ें:

शानदार

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

Kotlin

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

इसके बाद, अपने कोड में 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 इंस्टेंस को स्क्रीन-लेवल कंपोज़ेबल पर ऐक्सेस किया जाता है. इसका मतलब है कि इसे, रूट कंपोज़ेबल के पास ऐक्सेस किया जाता है. रूट कंपोज़ेबल को, नेविगेशन ग्राफ़ की किसी ऐक्टिविटी, फ़्रैगमेंट या डेस्टिनेशन से कॉल किया जाता है. ऐसा इसलिए है, क्योंकि ViewModel डिफ़ॉल्ट रूप से, स्क्रीन लेवल ऑब्जेक्ट के दायरे में होते हैं. ViewModel के लाइफ़साइकल और दायरे के बारे में ज़्यादा जानने के लिए, यहां जाएं.

अन्य कंपोज़ेबल में ViewModel इंस्टेंस पास करने से बचें. ऐसा करने से, उन कंपोज़ेबल की टेस्टिंग करना मुश्किल हो सकता है और प्रीव्यू टूट सकते हैं. इसके बजाय, सिर्फ़ वह डेटा और फ़ंक्शन पास करें जिनकी उन्हें पैरामीटर के तौर पर ज़रूरत होती है.

_सब स्क्रीन-लेवल_ कंपोज़ेबल के लिए, स्टेट को मैनेज करने के लिए ViewModel इंस्टेंस का इस्तेमाल किया जा सकता है. हालांकि, ViewModel's लाइफ़साइकल और दायरे के बारे में जानकारी रखें. अगर कंपोज़ेबल, अपने-आप में पूरा है, तो Hilt का इस्तेमाल करके ViewModel को इंजेक्ट किया जा सकता है. इससे, पैरंट कंपोज़ेबल से डिपेंडेंसी पास करने की ज़रूरत नहीं पड़ती.

अगर आपके ViewModel में डिपेंडेंसी हैं, तो viewModel(), पैरामीटर के तौर पर, वैकल्पिक तौर पर ViewModelProvider.Factory लेता है.

Compose में ViewModel के बारे में ज़्यादा जानने के लिए, इंटरऑपरेबिलिटी से जुड़े दस्तावेज़ देखें. साथ ही, यह भी जानें कि Navigation Compose लाइब्रेरी, या ऐक्टिविटी और फ़्रैगमेंट के साथ इंस्टेंस का इस्तेमाल कैसे किया जाता है.

डेटा स्ट्रीम

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

Compose में एसिंक्रोनस कार्रवाइयां

Jetpack Compose की मदद से, कंपोज़ेबल में को-रूटीन का इस्तेमाल करके, एसिंक्रोनस कार्रवाइयां की जा सकती हैं.

ज़्यादा जानकारी के लिए, साइड इफ़ेक्ट के दस्तावेज़ में LaunchedEffect, produceState, और rememberCoroutineScope एपीआई देखें.

नेविगेशन कॉम्पोनेंट, Jetpack Compose ऐप्लिकेशन के लिए सहायता उपलब्ध कराता है. ज़्यादा जानकारी के लिए, Compose की मदद से नेविगेट करना और Jetpack Navigation को Navigation Compose पर माइग्रेट करना देखें.

Hilt

Android ऐप्लिकेशन में, डिपेंडेंसी इंजेक्शन के लिए Hilt को इस्तेमाल करने का सुझाव दिया जाता है. यह Compose के साथ आसानी से काम करता है.

viewModel() फ़ंक्शन, ViewModel सेक्शन में बताया गया है, जो @HiltViewModel एनोटेशन के साथ Hilt से बनाए गए ViewModel का इस्तेमाल अपने-आप करता है. हमने Hilt के 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 और नेविगेशन

Hilt को Navigation Compose लाइब्रेरी के साथ भी इंटिग्रेट किया जा सकता है. अपनी Gradle फ़ाइल में, ये अतिरिक्त डिपेंडेंसी जोड़ें:

शानदार

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

Kotlin

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

Navigation Compose का इस्तेमाल करते समय, 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")
        }
    }
}

Compose में पेज़िंग का इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, सूचियां और ग्रिड से जुड़ा दस्तावेज़ देखें.

Maps

अपने ऐप्लिकेशन में Google Maps उपलब्ध कराने के लिए, Maps Compose लाइब्रेरी का इस्तेमाल किया जा सकता है. यहां इस्तेमाल का एक उदाहरण दिया गया है:

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