Compose में व्यू का इस्तेमाल करना

Compose यूज़र इंटरफ़ेस (यूआई) में, Android व्यू हैरारकी (व्यू और व्यू ग्रुप के लेआउट का क्रम) को शामिल किया जा सकता है. यह तरीका खास तौर पर तब काम आता है, जब आपको ऐसे यूज़र इंटरफ़ेस (यूआई) एलिमेंट इस्तेमाल करने हों जो Compose में अब तक उपलब्ध नहीं हैं. जैसे, AdView. इस तरीके से, आपके बनाए गए कस्टम व्यू को फिर से इस्तेमाल किया जा सकता है.

किसी व्यू एलिमेंट या हैरारकी को शामिल करने के लिए, AndroidView कंपोज़ेबल का इस्तेमाल करें. AndroidView को एक lambda फ़ंक्शन पास किया गया है, जो View दिखाता है. AndroidView, update कॉलबैक भी उपलब्ध कराता है. इसे तब कॉल किया जाता है, जब व्यू को बड़ा किया जाता है. जब भी कॉलबैक में पढ़ा गया State बदलता है, तब AndroidView फिर से कंपोज़ होता है. AndroidView, पहले से मौजूद अन्य कंपोज़ेबल की तरह, Modifier पैरामीटर लेता है. इसका इस्तेमाल, पैरंट कंपोज़ेबल में इसकी पोज़िशन सेट करने के लिए किया जा सकता है.

@Composable
fun CustomView() {
    var selectedItem by remember { mutableIntStateOf(0) }

    // Adds view to Compose
    AndroidView(
        modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree
        factory = { context ->
            // Creates view
            MyView(context).apply {
                // Sets up listeners for View -> Compose communication
                setOnClickListener {
                    selectedItem = 1
                }
            }
        },
        update = { view ->
            // View's been inflated or state read in this block has been updated
            // Add logic here if necessary

            // As selectedItem is read here, AndroidView will recompose
            // whenever the state changes
            // Example of Compose -> View communication
            view.selectedItem = selectedItem
        }
    )
}

@Composable
fun ContentExample() {
    Column(Modifier.fillMaxSize()) {
        Text("Look at this CustomView!")
        CustomView()
    }
}

AndroidView के साथ व्यू बाइंडिंग

एक्सएमएल लेआउट को एम्बेड करने के लिए, AndroidViewBinding एपीआई का इस्तेमाल करें. यह एपीआई, androidx.compose.ui:ui-viewbinding लाइब्रेरी से मिलता है. ऐसा करने के लिए, आपके प्रोजेक्ट में व्यू बाइंडिंग की सुविधा चालू होनी चाहिए.

@Composable
fun AndroidViewBindingExample() {
    AndroidViewBinding(ExampleLayoutBinding::inflate) {
        exampleView.setBackgroundColor(Color.GRAY)
    }
}

AndroidView, लेज़ी लिस्ट में

अगर लेज़ी लिस्ट (LazyColumn, LazyRow, Pager वगैरह) में AndroidView का इस्तेमाल किया जा रहा है, तो 1.4.0-rc01 वर्शन में पेश किए गए AndroidView ओवरलोड का इस्तेमाल करें. इस ओवरलोड की मदद से, Compose, View के मौजूदा इंस्टेंस को फिर से इस्तेमाल कर सकता है. ऐसा तब होता है, जब कंपोज़िशन को फिर से इस्तेमाल किया जाता है, जैसा कि लेज़ी लिस्ट के मामले में होता है.

AndroidView के इस ओवरलोड में दो अतिरिक्त पैरामीटर जोड़े जाते हैं:

  • onReset - यह बताने के लिए कि View का फिर से इस्तेमाल किया जाने वाला है, एक कॉलबैक को शुरू किया गया. व्यू को फिर से इस्तेमाल करने की सुविधा चालू करने के लिए, यह वैल्यू शून्य नहीं होनी चाहिए.
  • onRelease (ज़रूरी नहीं) - यह बताने के लिए एक कॉलबैक शुरू किया गया है कि View ने कंपोज़िशन से बाहर निकल गया है और इसका फिर से इस्तेमाल नहीं किया जाएगा.

@Composable
fun AndroidViewInLazyList() {
    LazyColumn {
        items(100) { index ->
            AndroidView(
                modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree
                factory = { context ->
                    MyView(context)
                },
                update = { view ->
                    view.selectedItem = index
                },
                onReset = { view ->
                    view.clear()
                }
            )
        }
    }
}

Compose में फ़्रैगमेंट (ट्रांज़िशनरी स्टेप)

Compose में Fragment जोड़ने के लिए, AndroidFragment कंपोज़ेबल का इस्तेमाल करें. AndroidFragment में फ़्रैगमेंट के हिसाब से हैंडलिंग की सुविधा होती है. जैसे, कंपोज़ेबल के कंपोज़िशन से बाहर निकलने पर फ़्रैगमेंट को हटाना.

किसी फ़्रैगमेंट को शामिल करने के लिए, AndroidFragment कंपोज़ेबल का इस्तेमाल करें. Fragment क्लास को AndroidFragment में पास किया जाता है. इसके बाद, यह उस क्लास के इंस्टेंस को सीधे कंपोज़िशन में जोड़ देता है. AndroidFragment, fragmentState ऑब्जेक्ट भी उपलब्ध कराता है, ताकि दी गई स्थिति के साथ AndroidFragment बनाया जा सके. साथ ही, नए फ़्रैगमेंट में पास करने के लिए arguments और कंपोज़िशन से फ़्रैगमेंट उपलब्ध कराने वाला onUpdate कॉलबैक भी उपलब्ध कराता है. पहले से मौजूद कई अन्य कंपोज़ेबल की तरह, AndroidFragment में Modifier पैरामीटर का इस्तेमाल किया जा सकता है. उदाहरण के लिए, पैरंट कंपोज़ेबल में इसकी पोज़िशन सेट करने के लिए, इसका इस्तेमाल किया जा सकता है.

Compose में AndroidFragment को इस तरह कॉल करें:

@Composable
fun FragmentInComposeExample() {
    AndroidFragment<MyFragment>()
}

Cap Fragment लाइफ़साइकल स्टेट

Fragment 1.9.0 और इसके बाद के वर्शन में, maxLifecycle पैरामीटर का इस्तेमाल करके, एम्बेड किए गए Fragment की लाइफ़साइकल की स्थिति को सीमित किया जा सकता है.

उदाहरण के लिए, HorizontalPager में, maxLifecycle को डाइनैमिक तौर पर RESUMED पर सेट किया जा सकता है. ऐसा सिर्फ़ तब किया जा सकता है, जब उससे जुड़ा पेज चालू हो. साथ ही, ऑफ़स्क्रीन पेजों को STARTED पर सेट किया जा सकता है. जब उपयोगकर्ता किसी दूसरे पेज पर जाता है, तो पिछले पेज के फ़्रैगमेंट की सीमा STARTED हो जाती है. इससे RESUMED के दायरे में आने वाले वर्कलोड को रोका या रद्द किया जाता है. जैसे, repeatOnLifecycle(RESUMED) में चल रहे कोरूटीन. इससे ऑफ़स्क्रीन पेज, सिर्फ़ फ़ोरग्राउंड में होने वाले काम नहीं कर पाते. हालांकि, उनका यूज़र इंटरफ़ेस (यूआई) STARTED पर शुरू किया जाता है:

HorizontalPager(state = pagerState) { page ->
    // Dynamically cap the lifecycle state based on whether the page is selected
    val maxLifecycle = if (pagerState.settledPage == page) {
        Lifecycle.State.RESUMED
    } else {
        Lifecycle.State.STARTED
    }

    when (page) {
        0 -> AndroidFragment<HomeFragment>(maxLifecycle = maxLifecycle)
        1 -> AndroidFragment<LibraryFragment>(maxLifecycle = maxLifecycle)
        /* Other pages and corresponding fragments */
    }
}

Compose से Android फ़्रेमवर्क को कॉल करना

Compose, Android फ़्रेमवर्क क्लास के अंदर काम करता है. उदाहरण के लिए, इसे Android व्यू क्लास पर होस्ट किया जाता है, जैसे कि Activity या Fragment. साथ ही, यह Android फ़्रेमवर्क क्लास का इस्तेमाल कर सकता है, जैसे कि Context, सिस्टम रिसॉर्स, Service या BroadcastReceiver.

सिस्टम के संसाधनों के बारे में ज़्यादा जानने के लिए, Compose में संसाधन देखें.

कंपोज़िशन लोकल

CompositionLocal क्लास, कंपोज़ेबल फ़ंक्शन के ज़रिए डेटा को इंप्लिसिट तरीके से पास करने की अनुमति देती हैं. आम तौर पर, यूज़र इंटरफ़ेस (यूआई) ट्री के किसी नोड में वैल्यू के साथ ये उपलब्ध होते हैं. इस वैल्यू का इस्तेमाल, इसके कंपोज़ेबल डिसेंडेंट कर सकते हैं. इसके लिए, कंपोज़ेबल फ़ंक्शन में CompositionLocal को पैरामीटर के तौर पर एलान करने की ज़रूरत नहीं होती.

CompositionLocal का इस्तेमाल, Compose में Android फ़्रेमवर्क टाइप की वैल्यू को लागू करने के लिए किया जाता है. जैसे, Context, Configuration या View, जिसमें Compose कोड को उससे जुड़े LocalContext, LocalConfiguration या LocalView के साथ होस्ट किया जाता है. ध्यान दें कि CompositionLocal क्लास के नाम से पहले Local लगाया जाता है, ताकि आईडीई में ऑटो-कंप्लीट की सुविधा की मदद से, उन्हें आसानी से खोजा जा सके.

current प्रॉपर्टी का इस्तेमाल करके, CompositionLocal की मौजूदा वैल्यू को ऐक्सेस करें. उदाहरण के लिए, नीचे दिया गया कोड Toast.makeToast तरीके में LocalContext.current देकर, टोस्ट मैसेज दिखाता है.

@Composable
fun ToastGreetingButton(greeting: String) {
    val context = LocalContext.current
    Button(onClick = {
        Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show()
    }) {
        Text("Greet")
    }
}

ब्रॉडकास्ट रिसीवर

CompositionLocal और खराब असर दिखाने के लिए, अगर किसी BroadcastReceiver को ऐप्लिकेशन बनाने की सुविधा से रजिस्टर करना है, तो मौजूदा कॉन्टेक्स्ट का इस्तेमाल करने के लिए LocalContext का इस्तेमाल करें. साथ ही, rememberUpdatedState और DisposableEffect खराब असर का इस्तेमाल करें.

@Composable
fun SystemBroadcastReceiver(
    systemAction: String,
    onSystemEvent: (intent: Intent?) -> Unit
) {
    // Grab the current context in this part of the UI tree
    val context = LocalContext.current

    // Safely use the latest onSystemEvent lambda passed to the function
    val currentOnSystemEvent by rememberUpdatedState(onSystemEvent)

    // If either context or systemAction changes, unregister and register again
    DisposableEffect(context, systemAction) {
        val intentFilter = IntentFilter(systemAction)
        val broadcast = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                currentOnSystemEvent(intent)
            }
        }

        context.registerReceiver(broadcast, intentFilter)

        // When the effect leaves the Composition, remove the callback
        onDispose {
            context.unregisterReceiver(broadcast)
        }
    }
}

@Composable
fun HomeScreen() {

    SystemBroadcastReceiver(Intent.ACTION_BATTERY_CHANGED) { batteryStatus ->
        val isCharging = /* Get from batteryStatus ... */ true
        /* Do something if the device is charging */
    }

    /* Rest of the HomeScreen */
}

अन्य इंटरैक्शन

अगर आपको जिस इंटरैक्शन की ज़रूरत है उसके लिए कोई यूटिलिटी तय नहीं की गई है, तो सबसे सही तरीका यह है कि Compose के सामान्य दिशा-निर्देश का पालन करें. इसके तहत, डेटा नीचे की ओर फ़्लो करता है और इवेंट ऊपर की ओर फ़्लो करते हैं. इस बारे में ज़्यादा जानकारी के लिए, Compose के बारे में सोचें लेख पढ़ें. उदाहरण के लिए, यह कंपोज़ेबल एक अलग गतिविधि लॉन्च करता है:

class OtherInteractionsActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // get data from savedInstanceState
        setContent {
            MaterialTheme {
                ExampleComposable(data, onButtonClick = {
                    startActivity(Intent(this, MyActivity::class.java))
                })
            }
        }
    }
}

@Composable
fun ExampleComposable(data: DataExample, onButtonClick: () -> Unit) {
    Button(onClick = onButtonClick) {
        Text(data.title)
    }
}