गतिविधि एम्बेड करना

ऐक्टिविटी एम्बेड करने की सुविधा, बड़ी स्क्रीन वाले डिवाइसों पर ऐप्लिकेशन को ऑप्टिमाइज़ करती है. इसके लिए, यह सुविधा किसी ऐप्लिकेशन की टास्क विंडो को दो ऐक्टिविटी या एक ही ऐक्टिविटी के दो इंस्टेंस के बीच बांट देती है.

पहली इमेज. सेटिंग ऐप्लिकेशन में, एक साथ कई गतिविधियां दिखाई गई हैं.

अगर आपके ऐप्लिकेशन में कई गतिविधियां शामिल हैं, तो गतिविधि एम्बेड करने की सुविधा का इस्तेमाल करके, टैबलेट, फ़ोल्ड किए जा सकने वाले डिवाइसों, और ChromeOS डिवाइसों पर लोगों को बेहतर अनुभव दिया जा सकता है.

गतिविधि को एम्बेड करने के लिए, कोड को फिर से लिखने की ज़रूरत नहीं होती. आपके पास यह तय करने का विकल्प होता है कि आपका ऐप्लिकेशन, अपनी गतिविधियों को कैसे दिखाएगा. जैसे, अगल-बगल या एक के ऊपर एक. इसके लिए, एक्सएमएल कॉन्फ़िगरेशन फ़ाइल बनाएं या Jetpack WindowManager एपीआई कॉल करें.

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

डिवाइस को घुमाने पर भी, गतिविधि एम्बेड करने की सुविधा काम करती है. साथ ही, यह फ़ोल्ड किए जा सकने वाले डिवाइसों पर भी आसानी से काम करती है. डिवाइस को फ़ोल्ड और अनफ़ोल्ड करने पर, गतिविधियों को स्टैक और अनस्टैक किया जा सकता है.

ऐक्टिविटी एम्बेड करने की सुविधा, Android 12L (एपीआई लेवल 32) और इसके बाद के वर्शन पर काम करने वाले ज़्यादातर बड़ी स्क्रीन वाले डिवाइसों पर उपलब्ध है.

टास्क की विंडो को स्प्लिट करना

ऐक्टिविटी एम्बेड करने की सुविधा, ऐप्लिकेशन की टास्क विंडो को दो कंटेनर में बांटती है: प्राइमरी और सेकंडरी. कंटेनर में, मुख्य गतिविधि या कंटेनर में पहले से मौजूद अन्य गतिविधियों से लॉन्च की गई गतिविधियां होती हैं.

ऐक्टिविटी लॉन्च होने पर, उन्हें सेकंडरी कंटेनर में स्टैक किया जाता है. साथ ही, छोटी स्क्रीन पर सेकंडरी कंटेनर को प्राइमरी कंटेनर के ऊपर स्टैक किया जाता है. इसलिए, ऐक्टिविटी स्टैक करने और वापस जाने की सुविधा, आपके ऐप्लिकेशन में पहले से मौजूद ऐक्टिविटी के क्रम के हिसाब से काम करती है.

गतिविधि एम्बेड करने की सुविधा की मदद से, गतिविधियों को अलग-अलग तरीकों से दिखाया जा सकता है. आपका ऐप्लिकेशन, टास्क विंडो को स्प्लिट कर सकता है. इसके लिए, दो गतिविधियों को एक साथ साइड-बाय-साइड या एक के ऊपर एक लॉन्च किया जा सकता है:

दूसरी इमेज. दो ऐक्टिविटी अगल-बगल और एक ऐक्टिविटी ऊपर-नीचे.

टास्क विंडो में पूरी जगह घेरने वाली गतिविधि को स्प्लिट किया जा सकता है. इसके लिए, साथ में एक नई गतिविधि लॉन्च करें:

तीसरी इमेज. ऐक्टिविटी A, ऐक्टिविटी B को साइड में शुरू करती है.

स्प्लिट मोड में पहले से मौजूद और टास्क विंडो शेयर करने वाली गतिविधियां, इन तरीकों से अन्य गतिविधियां लॉन्च कर सकती हैं:

  • किसी अन्य गतिविधि के ऊपर मौजूद साइड में:

    चौथी इमेज. ऐक्टिविटी A, ऐक्टिविटी B के ऊपर साइड में ऐक्टिविटी C शुरू करती है.
  • साइड में ले जाएं और स्प्लिट को साइड में ले जाकर, पिछली मुख्य गतिविधि को छिपाएं:

    पांचवीं इमेज. गतिविधि B, गतिविधि C को साइड में शुरू करती है और स्प्लिट को साइड में ले जाती है.
  • ऐक्टिविटी को सबसे ऊपर लॉन्च करें. इसका मतलब है कि उसे उसी ऐक्टिविटी स्टैक में लॉन्च करें:

    छठी इमेज. गतिविधि B, गतिविधि C को बिना किसी अतिरिक्त इंटेंट फ़्लैग के शुरू करती है.
  • उसी टास्क में, किसी ऐक्टिविटी को फ़ुल विंडो में लॉन्च करने के लिए:

    इमेज 7. गतिविधि A या गतिविधि B, गतिविधि C शुरू करती है. यह गतिविधि, टास्क विंडो को भर देती है.

पिछले पेज पर वापस जाने की सुविधा

स्प्लिट टास्क विंडो की स्थिति में, अलग-अलग तरह के ऐप्लिकेशन के लिए, वापस जाने के अलग-अलग नियम हो सकते हैं. ये नियम, गतिविधियों के बीच की निर्भरता या उपयोगकर्ताओं के वापस जाने के इवेंट को ट्रिगर करने के तरीके पर निर्भर करते हैं. उदाहरण के लिए:

  • एक साथ वापस जाना: अगर गतिविधियां एक-दूसरे से जुड़ी हैं और एक को दूसरी के बिना नहीं दिखाया जाना चाहिए, तो दोनों को पूरा करने के लिए, वापस जाने के नेविगेशन को कॉन्फ़िगर किया जा सकता है.
  • अलग-अलग काम करना: अगर गतिविधियां पूरी तरह से अलग-अलग हैं, तो किसी गतिविधि पर वापस जाने से, टास्क विंडो में मौजूद दूसरी गतिविधि की स्थिति पर कोई असर नहीं पड़ता.

बटन नेविगेशन का इस्तेमाल करते समय, बैक इवेंट को फ़ोकस की गई पिछली ऐक्टिविटी पर भेजा जाता है.

जेस्चर वाले नेविगेशन के लिए:

  • Android 14 (एपीआई लेवल 34) और इससे पहले के वर्शन — बैक इवेंट उस गतिविधि को भेजा जाता है जहां जेस्चर हुआ था. जब उपयोगकर्ता स्क्रीन की बाईं ओर से स्वाइप करते हैं, तो 'वापस जाएं' इवेंट, स्प्लिट विंडो के बाईं ओर मौजूद गतिविधि को भेजा जाता है. जब उपयोगकर्ता स्क्रीन की दाईं ओर से स्वाइप करते हैं, तो 'वापस जाएं' इवेंट, दाईं ओर के पैनल में मौजूद गतिविधि को भेजा जाता है.

  • Android 15 (एपीआई लेवल 35) और उसके बाद के वर्शन

    • एक ही ऐप्लिकेशन में कई गतिविधियां होने पर, यह जेस्चर सबसे ऊपर वाली गतिविधि को बंद कर देता है. इससे कोई फ़र्क़ नहीं पड़ता कि आपने किस दिशा में स्वाइप किया है. इससे आपको एक जैसा अनुभव मिलता है.

    • जब अलग-अलग ऐप्लिकेशन की दो ऐक्टिविटी (ओवरले) शामिल होती हैं, तो वापस जाने का इवेंट, फ़ोकस में मौजूद आखिरी ऐक्टिविटी पर रीडायरेक्ट होता है. यह बटन नेविगेशन के व्यवहार के मुताबिक होता है.

मल्टी-पैन लेआउट

Jetpack WindowManager की मदद से, Android 12L (एपीआई लेवल 32) या इसके बाद के वर्शन वाले बड़े स्क्रीन डिवाइसों पर, मल्टी-पैन लेआउट में ऐक्टिविटी एम्बेड की जा सकती है. साथ ही, इसे प्लैटफ़ॉर्म के पुराने वर्शन वाले कुछ डिवाइसों पर भी इस्तेमाल किया जा सकता है. मौजूदा ऐप्लिकेशन, फ़्रैगमेंट या व्यू-आधारित लेआउट के बजाय कई गतिविधियों पर आधारित होते हैं. जैसे, SlidingPaneLayout. ये ऐप्लिकेशन, सोर्स कोड को बदले बिना बड़ी स्क्रीन पर बेहतर उपयोगकर्ता अनुभव दे सकते हैं.

इसका एक सामान्य उदाहरण, लिस्ट-डिटेल स्प्लिट है. बेहतर क्वालिटी की प्रज़ेंटेशन के लिए, सिस्टम सूची वाली गतिविधि शुरू करता है. इसके बाद, ऐप्लिकेशन तुरंत जानकारी वाली गतिविधि शुरू करता है. ट्रांज़िशन सिस्टम, दोनों गतिविधियों के ड्रॉ होने तक इंतज़ार करता है. इसके बाद, उन्हें एक साथ दिखाता है. उपयोगकर्ता को, दोनों गतिविधियां एक साथ लॉन्च होती हुई दिखती हैं.

आठवीं इमेज. मल्टी-पैन लेआउट में, एक साथ दो गतिविधियां शुरू की गई हैं.

स्प्लिट किए गए एट्रिब्यूट

यह तय किया जा सकता है कि स्प्लिट कंटेनर के बीच टास्क विंडो को किस अनुपात में बांटा जाए. साथ ही, यह भी तय किया जा सकता है कि कंटेनर एक-दूसरे के हिसाब से कैसे लेआउट किए जाएं.

एक्सएमएल कॉन्फ़िगरेशन फ़ाइल में तय किए गए नियमों के लिए, इन एट्रिब्यूट को सेट करें:

  • splitRatio: कंटेनर के डाइमेंशन सेट करता है. वैल्यू, ओपन इंटरवल (0.0, 1.0) में फ़्लोटिंग पॉइंट नंबर होती है.
  • splitLayoutDirection: इससे पता चलता है कि स्प्लिट कंटेनर एक-दूसरे के हिसाब से कैसे लेआउट किए गए हैं. वैल्यू में ये शामिल हैं:
    • ltr: बाएं से दाएं
    • rtl: दाएं से बाएं
    • locale: ltr या rtl में से किसी एक को, स्थान-भाषा की सेटिंग के हिसाब से तय किया जाता है

उदाहरणों के लिए, एक्सएमएल कॉन्फ़िगरेशन सेक्शन देखें.

WindowManager API का इस्तेमाल करके बनाए गए नियमों के लिए, SplitAttributes.Builder की मदद से SplitAttributes ऑब्जेक्ट बनाएं. इसके बाद, बिल्डर के इन तरीकों को कॉल करें:

  • setSplitType(): स्प्लिट कंटेनर के साइज़ सेट करता है. मान्य आर्ग्युमेंट के लिए, SplitAttributes.SplitType देखें. इसमें SplitAttributes.SplitType.ratio() तरीका भी शामिल है.
  • setLayoutDirection(): इससे कंटेनर का लेआउट सेट किया जाता है. संभावित वैल्यू के लिए, SplitAttributes.LayoutDirection देखें.

उदाहरणों के लिए, WindowManager API सेक्शन देखें.

इमेज 9. बाईं से दाईं ओर दो गतिविधि स्प्लिट दिखाए गए हैं, लेकिन इनके स्प्लिट रेशियो अलग-अलग हैं.

स्प्लिट ओरिएंटेशन

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

SplitController SplitAttributes कैलकुलेटर की मदद से, स्प्लिट ओरिएंटेशन तय किया जा सकता है. कैलकुलेटर, चालू SplitRule के लिए SplitAttributes का हिसाब लगाता है.

डिवाइस की अलग-अलग स्थितियों के लिए, पैरंट कंटेनर को अलग-अलग दिशाओं में बांटने के लिए कैलकुलेटर का इस्तेमाल करें. उदाहरण के लिए:

Kotlin

if (WindowSdkExtensions.getInstance().extensionVersion >= 2) {
    SplitController.getInstance(this).setSplitAttributesCalculator { params ->
        val parentConfiguration = params.parentConfiguration
        val builder = SplitAttributes.Builder()
        return@setSplitAttributesCalculator if (parentConfiguration.screenWidthDp >= 840) {
            // Side-by-side dual-pane layout for wide displays.
            builder
                .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
                .build()
        } else if (parentConfiguration.screenHeightDp >= 600) {
            // Horizontal split for tall displays.
            builder
                .setLayoutDirection(SplitAttributes.LayoutDirection.BOTTOM_TO_TOP)
                .build()
        } else {
            // Fallback to expand the secondary container.
            builder
                .setSplitType(SPLIT_TYPE_EXPAND)
                .build()
        }
    }
}

Java

if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 2) {
    SplitController.getInstance(this).setSplitAttributesCalculator(params -> {
        Configuration parentConfiguration = params.getParentConfiguration();
        SplitAttributes.Builder builder = new SplitAttributes.Builder();
        if (parentConfiguration.screenWidthDp >= 840) {
            // Side-by-side dual-pane layout for wide displays.
            return builder
                .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
                .build();
        } else if (parentConfiguration.screenHeightDp >= 600) {
            // Horizontal split for tall displays.
            return builder
                .setLayoutDirection(SplitAttributes.LayoutDirection.BOTTOM_TO_TOP)
                .build();
        } else {
            // Fallback to expand the secondary container.
            return builder
                .setSplitType(SplitType.SPLIT_TYPE_EXPAND)
                .build();
        }
    });
}

फ़ोल्ड किए जा सकने वाले डिवाइसों पर, स्क्रीन को वर्टिकल तौर पर स्प्लिट किया जा सकता है. इसके लिए, डिवाइस को लैंडस्केप मोड में रखें. डिवाइस को पोर्ट्रेट मोड में रखने पर, एक ही ऐक्टिविटी दिखेगी. डिवाइस को टेबलटॉप मोड में रखने पर, स्क्रीन को हॉरिज़ॉन्टल तौर पर स्प्लिट किया जा सकता है:

Kotlin

if (WindowSdkExtensions.getInstance().extensionVersion >= 2) {
    SplitController.getInstance(this).setSplitAttributesCalculator { params ->
        val tag = params.splitRuleTag
        val parentWindowMetrics = params.parentWindowMetrics
        val parentConfiguration = params.parentConfiguration
        val foldingFeatures =
            params.parentWindowLayoutInfo.displayFeatures.filterIsInstance<FoldingFeature>()
        val feature = if (foldingFeatures.size == 1) foldingFeatures[0] else null
        val builder = SplitAttributes.Builder()
        builder.setSplitType(SPLIT_TYPE_HINGE)
        return@setSplitAttributesCalculator if (feature?.isSeparating == true) {
            // Horizontal split for tabletop posture.
            builder
                .setSplitType(SPLIT_TYPE_HINGE)
                .setLayoutDirection(
                    if (feature.orientation == FoldingFeature.Orientation.HORIZONTAL) {
                        SplitAttributes.LayoutDirection.BOTTOM_TO_TOP
                    } else {
                        SplitAttributes.LayoutDirection.LOCALE
                    }
                )
                .build()
        } else if (parentConfiguration.screenWidthDp >= 840) {
            // Side-by-side dual-pane layout for wide displays.
            builder
                .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
                .build()
        } else {
            // No split for tall displays.
            builder
                .setSplitType(SPLIT_TYPE_EXPAND)
                .build()
        }
    }
}

Java

if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 2) {
    SplitController.getInstance(this).setSplitAttributesCalculator(params -> {
        String tag = params.getSplitRuleTag();
        WindowMetrics parentWindowMetrics = params.getParentWindowMetrics();
        Configuration parentConfiguration = params.getParentConfiguration();
        List<FoldingFeature> foldingFeatures =
            params.getParentWindowLayoutInfo().getDisplayFeatures().stream().filter(
                    item -> item instanceof FoldingFeature)
                .map(item -> (FoldingFeature) item)
                .collect(Collectors.toList());
        FoldingFeature feature = foldingFeatures.size() == 1 ? foldingFeatures.get(0) : null;
        SplitAttributes.Builder builder = new SplitAttributes.Builder();
        builder.setSplitType(SplitType.SPLIT_TYPE_HINGE);
        if (feature != null && feature.isSeparating()) {
            // Horizontal slit for tabletop posture.
            return builder
                .setSplitType(SplitType.SPLIT_TYPE_HINGE)
                .setLayoutDirection(
                    feature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL
                        ? SplitAttributes.LayoutDirection.BOTTOM_TO_TOP
                        : SplitAttributes.LayoutDirection.LOCALE)
                .build();
        }
        else if (parentConfiguration.screenWidthDp >= 840) {
            // Side-by-side dual-pane layout for wide displays.
            return builder
                .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
                .build();
        } else {
            // No split for tall displays.
            return builder
                .setSplitType(SplitType.SPLIT_TYPE_EXPAND)
                .build();
        }
    });
}

प्लेसहोल्डर

प्लेसहोल्डर गतिविधियां, खाली सेकंडरी गतिविधियां होती हैं. ये गतिविधि के स्प्लिट के एक हिस्से पर कब्जा करती हैं. इन्हें आखिर में ऐसी गतिविधि से बदल दिया जाता है जिसमें कॉन्टेंट शामिल होता है. उदाहरण के लिए, सूची-जानकारी वाले लेआउट में, सूची से कोई आइटम चुने जाने तक, प्लेसहोल्डर ऐक्टिविटी, ऐक्टिविटी स्प्लिट के सेकंडरी साइड पर दिख सकती है. इसके बाद, चुनी गई सूची के आइटम की जानकारी वाली ऐक्टिविटी, प्लेसहोल्डर की जगह ले लेती है.

डिफ़ॉल्ट रूप से, सिस्टम प्लेसहोल्डर सिर्फ़ तब दिखाता है, जब गतिविधि को अलग-अलग हिस्सों में बांटने के लिए काफ़ी जगह हो. डिसप्ले का साइज़ बदलने पर, प्लेसहोल्डर अपने-आप बंद हो जाते हैं. ऐसा तब होता है, जब डिसप्ले की चौड़ाई या ऊंचाई इतनी कम हो जाती है कि स्प्लिट डिसप्ले नहीं किया जा सकता. जगह खाली होने पर, सिस्टम, प्लेसहोल्डर को फिर से शुरू की गई स्थिति के साथ फिर से लॉन्च करता है.

इमेज 10. फ़ोल्ड किए जा सकने वाले डिवाइस को फ़ोल्ड और अनफ़ोल्ड किया जा रहा है. डिसप्ले का साइज़ बदलने पर, प्लेसहोल्डर की गतिविधि खत्म हो जाती है और उसे फिर से बनाया जाता है.

हालांकि, SplitPlaceholderRule या SplitPlaceholder.Builder के setSticky() तरीके के stickyPlaceholder एट्रिब्यूट का इस्तेमाल करके, डिफ़ॉल्ट व्यवहार को बदला जा सकता है. जब एट्रिब्यूट या तरीके से true वैल्यू तय की जाती है, तो सिस्टम, टास्क विंडो में सबसे ऊपर मौजूद गतिविधि के तौर पर प्लेसहोल्डर दिखाता है. ऐसा तब होता है, जब डिसप्ले को दो पैन वाले डिसप्ले से बदलकर एक पैन वाला डिसप्ले कर दिया जाता है. उदाहरण के लिए, स्प्लिट कॉन्फ़िगरेशन देखें.

इमेज 11. फ़ोल्ड किए जा सकने वाले डिवाइस को फ़ोल्ड और अनफ़ोल्ड किया जा रहा है. प्लेसहोल्डर गतिविधि स्टिकी है.

विंडो के साइज़ में बदलाव

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

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

ऐक्टिविटी स्टैक करने की सुविधा इसलिए उपलब्ध है, क्योंकि WindowManager, सेकंडरी पैन में मौजूद ऐक्टिविटी को प्राइमरी पैन में मौजूद ऐक्टिविटी के ऊपर z-ऑर्डर करता है.

सेकंडरी पैनल में कई गतिविधियां

गतिविधि B, गतिविधि C को बिना किसी अतिरिक्त इंटेंट फ़्लैग के शुरू करती है:

गतिविधि को तीन हिस्सों में बांटा गया है. इनमें A, B, और C शामिल हैं. C को B के ऊपर रखा गया है.

इस वजह से, एक ही टास्क में गतिविधियों का z-ऑर्डर इस तरह से होता है:

सेकंडरी ऐक्टिविटी स्टैक में, ऐक्टिविटी C को B के ऊपर स्टैक किया गया है.
          सेकंडरी स्टैक को प्राइमरी ऐक्टिविटी स्टैक के ऊपर स्टैक किया जाता है. इसमें ऐक्टिविटी A शामिल होती है.

इसलिए, छोटी टास्क विंडो में ऐप्लिकेशन, स्टैक में सबसे ऊपर C के साथ एक गतिविधि में छोटा हो जाता है:

छोटी विंडो में सिर्फ़ गतिविधि C दिख रही है.

छोटी विंडो में वापस जाने पर, एक के ऊपर एक स्टैक की गई गतिविधियों के बीच नेविगेट किया जाता है.

अगर टास्क विंडो के कॉन्फ़िगरेशन को बड़े साइज़ में वापस लाया जाता है, तो एक साथ कई पैन को जगह दी जा सकती है. ऐसे में, गतिविधियां फिर से अगल-बगल दिखती हैं.

एक के ऊपर एक स्प्लिट

ऐक्टिविटी B, ऐक्टिविटी C को साइड में शुरू करती है और स्प्लिट को साइड में ले जाती है:

टास्क विंडो में, पहले गतिविधि A और B दिखाई गई हैं. इसके बाद, गतिविधि B और C दिखाई गई हैं.

नतीजा, एक ही टास्क में गतिविधियों का यह z-ऑर्डर है:

एक ही स्टैक में मौजूद गतिविधियाँ A, B, और C. गतिविधियों को ऊपर से नीचे की ओर इस क्रम में स्टैक किया जाता है: C, B, A.

टास्क की छोटी विंडो में, ऐप्लिकेशन को एक ही गतिविधि में छोटा कर दिया जाता है. इसमें C सबसे ऊपर होता है:

छोटी विंडो में सिर्फ़ गतिविधि C दिख रही है.

फ़िक्स्ड-पोर्ट्रेट ओरिएंटेशन

android:screenOrientation मेनिफ़ेस्ट सेटिंग की मदद से, ऐप्लिकेशन को पोर्ट्रेट या लैंडस्केप ओरिएंटेशन में ऐक्टिविटी को सीमित करने की सुविधा मिलती है. टैबलेट और फ़ोल्ड किए जा सकने वाले डिवाइसों जैसी बड़ी स्क्रीन वाले डिवाइसों पर, उपयोगकर्ता अनुभव को बेहतर बनाने के लिए, डिवाइस बनाने वाली कंपनियां (ओईएम) स्क्रीन ओरिएंटेशन के अनुरोधों को अनदेखा कर सकती हैं. साथ ही, लैंडस्केप डिसप्ले पर पोर्ट्रेट ओरिएंटेशन में या पोर्ट्रेट डिसप्ले पर लैंडस्केप ओरिएंटेशन में ऐप्लिकेशन को लेटरबॉक्स कर सकती हैं.

इमेज 12. लेटरबॉक्स वाली गतिविधियां: लैंडस्केप डिवाइस पर फ़िक्स्ड-पोर्ट्रेट (बाईं ओर), पोर्ट्रेट डिवाइस पर फ़िक्स्ड-लैंडस्केप (दाईं ओर).

इसी तरह, गतिविधि एम्बेड करने की सुविधा चालू होने पर, ओईएम डिवाइसों को इस तरह से पसंद के मुताबिक बना सकते हैं कि बड़ी स्क्रीन (चौड़ाई ≥ 600 डीपी) पर लैंडस्केप ओरिएंटेशन में, फ़िक्स्ड-पोर्ट्रेट गतिविधियों को लेटरबॉक्स किया जा सके. जब फ़िक्स्ड-पोर्ट्रेट मोड में चल रही कोई ऐक्टिविटी, दूसरी ऐक्टिविटी लॉन्च करती है, तो डिवाइस दोनों ऐक्टिविटी को दो-पैन वाले डिसप्ले में अगल-बगल दिखा सकता है.

इमेज 13. फ़िक्स्ड-पोर्ट्रेट मोड में चल रही ऐक्टिविटी A, साइड में ऐक्टिविटी B शुरू करती है.

अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में हमेशा android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED प्रॉपर्टी जोड़ें, ताकि डिवाइसों को यह पता चल सके कि आपका ऐप्लिकेशन, गतिविधि एम्बेड करने की सुविधा के साथ काम करता है. इसके लिए, स्प्लिट कॉन्फ़िगरेशन सेक्शन देखें. इसके बाद, ओईएम के हिसाब से बनाए गए डिवाइस यह तय कर सकते हैं कि फ़िक्स्ड पोर्ट्रेट मोड में की जाने वाली गतिविधियों को लेटरबॉक्स करना है या नहीं.

स्प्लिट कॉन्फ़िगरेशन

स्प्लिट के नियमों से, गतिविधि के स्प्लिट कॉन्फ़िगर किए जाते हैं. स्प्लिट करने के नियम, एक्सएमएल कॉन्फ़िगरेशन फ़ाइल में तय किए जाते हैं. इसके अलावा, Jetpack WindowManager API कॉल करके भी ऐसा किया जा सकता है.

दोनों ही मामलों में, आपके ऐप्लिकेशन को WindowManager लाइब्रेरी को ऐक्सेस करना होगा. साथ ही, सिस्टम को यह बताना होगा कि ऐप्लिकेशन ने गतिविधि एम्बेड करने की सुविधा लागू की है.

यह तरीका अपनाएं:

  1. अपने ऐप्लिकेशन के मॉड्यूल-लेवल की build.gradle फ़ाइल में, WindowManager लाइब्रेरी की नई डिपेंडेंसी जोड़ें. उदाहरण के लिए:

    implementation 'androidx.window:window:1.1.0-beta02'

    WindowManager लाइब्रेरी, ऐक्टिविटी एम्बेड करने के लिए ज़रूरी सभी कॉम्पोनेंट उपलब्ध कराती है.

  2. सिस्टम को बताएं कि आपके ऐप्लिकेशन में गतिविधि एम्बेड करने की सुविधा लागू की गई है.

    ऐप्लिकेशन मेनिफ़ेस्ट फ़ाइल के <application> एलिमेंट में android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED प्रॉपर्टी जोड़ें और इसकी वैल्यू को 'सही' पर सेट करें. उदाहरण के लिए:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <application>
            <property
                android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
                android:value="true" />
        </application>
    </manifest>
    

    WindowManager के 1.1.0-alpha06 और इसके बाद के वर्शन में, ऐक्टिविटी एम्बेड करने की सुविधा बंद कर दी गई है. हालांकि, अगर प्रॉपर्टी को मेनिफ़ेस्ट में जोड़ा जाता है और उसे true पर सेट किया जाता है, तो इस सुविधा को चालू किया जा सकता है.

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

एक्सएमएल कॉन्फ़िगरेशन

गतिविधि एम्बेड करने की सुविधा को एक्सएमएल के आधार पर लागू करने के लिए, यह तरीका अपनाएं:

  1. ऐसी एक्सएमएल रिसॉर्स फ़ाइल बनाएं जो ये काम करती हो:

    • यह कुकी, उन गतिविधियों के बारे में बताती है जिनमें स्प्लिट शेयर किया जाता है
    • स्प्लिट करने के विकल्पों को कॉन्फ़िगर करता है
    • कॉन्टेंट उपलब्ध न होने पर, यह कुकी स्प्लिट किए गए कंटेनर के सेकंडरी कंटेनर के लिए प्लेसहोल्डर बनाती है
    • यह उन गतिविधियों के बारे में बताता है जिन्हें कभी भी स्प्लिट नहीं किया जाना चाहिए

    उदाहरण के लिए:

    <!-- main_split_config.xml -->
    
    <resources
        xmlns:window="http://schemas.android.com/apk/res-auto">
    
        <!-- Define a split for the named activities. -->
        <SplitPairRule
            window:splitRatio="0.33"
            window:splitLayoutDirection="locale"
            window:splitMinWidthDp="840"
            window:splitMaxAspectRatioInPortrait="alwaysAllow"
            window:finishPrimaryWithSecondary="never"
            window:finishSecondaryWithPrimary="always"
            window:clearTop="false">
            <SplitPairFilter
                window:primaryActivityName=".ListActivity"
                window:secondaryActivityName=".DetailActivity"/>
        </SplitPairRule>
    
        <!-- Specify a placeholder for the secondary container when content is
             not available. -->
        <SplitPlaceholderRule
            window:placeholderActivityName=".PlaceholderActivity"
            window:splitRatio="0.33"
            window:splitLayoutDirection="locale"
            window:splitMinWidthDp="840"
            window:splitMaxAspectRatioInPortrait="alwaysAllow"
            window:stickyPlaceholder="false">
            <ActivityFilter
                window:activityName=".ListActivity"/>
        </SplitPlaceholderRule>
    
        <!-- Define activities that should never be part of a split. Note: Takes
             precedence over other split rules for the activity named in the
             rule. -->
        <ActivityRule
            window:alwaysExpand="true">
            <ActivityFilter
                window:activityName=".ExpandedActivity"/>
        </ActivityRule>
    
    </resources>
    
  2. कोई इनिशियलाइज़र बनाएं.

    WindowManager RuleController कॉम्पोनेंट, एक्सएमएल कॉन्फ़िगरेशन फ़ाइल को पार्स करता है और नियमों को सिस्टम के लिए उपलब्ध कराता है. Jetpack Startup लाइब्रेरी Initializer, ऐप्लिकेशन के चालू होने पर RuleController को एक्सएमएल फ़ाइल उपलब्ध कराती है, ताकि कोई भी गतिविधि शुरू होने पर नियम लागू हों.

    इनिशियलाइज़र बनाने के लिए, यह तरीका अपनाएं:

    1. अपने मॉड्यूल-लेवल की build.gradle फ़ाइल में, Jetpack Startup लाइब्रेरी की नई डिपेंडेंसी जोड़ें. उदाहरण के लिए:

      implementation 'androidx.startup:startup-runtime:1.1.1'

    2. Initializer इंटरफ़ेस को लागू करने वाली क्लास बनाएं.

      इनिशियलाइज़र, RuleController को स्प्लिट करने के नियम उपलब्ध कराता है. इसके लिए, वह RuleController.parseRules() तरीके को एक्सएमएल कॉन्फ़िगरेशन फ़ाइल (main_split_config.xml) का आईडी पास करता है.

      Kotlin

      class SplitInitializer : Initializer<RuleController> {
      
          override fun create(context: Context): RuleController {
              return RuleController.getInstance(context).apply {
                  setRules(RuleController.parseRules(context, R.xml.main_split_config))
              }
          }
      
          override fun dependencies(): List<Class<out Initializer<*>>> {
              return emptyList()
          }
      }

      Java

      public class SplitInitializer implements Initializer<RuleController> {
      
          @NonNull
          @Override
          public RuleController create(@NonNull Context context) {
              RuleController ruleController = RuleController.getInstance(context);
              ruleController.setRules(
                  RuleController.parseRules(context, R.xml.main_split_config)
              );
               return ruleController;
           }
      
           @NonNull
           @Override
           public List<Class<? extends Initializer<?>>> dependencies() {
               return Collections.emptyList();
           }
      }

  3. नियमों की परिभाषाओं के लिए, कॉन्टेंट देने वाला कोई व्यक्ति या कंपनी बनाएं.

    अपनी ऐप्लिकेशन मेनिफ़ेस्ट फ़ाइल में androidx.startup.InitializationProvider को <provider> के तौर पर जोड़ें. अपने RuleController इनिशियलाइज़र SplitInitializer को लागू करने का रेफ़रंस शामिल करें:

    <!-- AndroidManifest.xml -->
    
    <provider android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <!-- Make SplitInitializer discoverable by InitializationProvider. -->
        <meta-data android:name="${applicationId}.SplitInitializer"
            android:value="androidx.startup" />
    </provider>
    

    InitializationProvider, ऐप्लिकेशन के onCreate() तरीके को कॉल करने से पहले SplitInitializer को ढूंढता है और उसे शुरू करता है. इस वजह से, ऐप्लिकेशन की मुख्य गतिविधि शुरू होने पर, स्प्लिट करने के नियम लागू होते हैं.

WindowManager API

एपीआई कॉल की मदद से, गतिविधि को प्रोग्राम के हिसाब से एम्बेड किया जा सकता है. Application की सबक्लास के onCreate() तरीके में कॉल करें, ताकि यह पक्का किया जा सके कि कोई भी गतिविधि शुरू होने से पहले नियम लागू हो जाएं.

Application

प्रोग्राम के हिसाब से गतिविधि को बांटने के लिए, यह तरीका अपनाएं:

  1. स्प्लिट नियम बनाएं:

    1. एक SplitPairFilter बनाएं. इससे उन गतिविधियों की पहचान की जा सकेगी जिनमें स्प्लिट शेयर किया गया है:

      Kotlin

      val splitPairFilter = SplitPairFilter(
          ComponentName(this, ListActivity::class.java),
          ComponentName(this, DetailActivity::class.java),
          null
      )

      Java

      SplitPairFilter splitPairFilter = new SplitPairFilter(
         new ComponentName(this, ListActivity.class),
         new ComponentName(this, DetailActivity.class),
         null
      );

    2. फ़िल्टर को फ़िल्टर सेट में जोड़ें:

      Kotlin

      val filterSet = setOf(splitPairFilter)

      Java

      Set<SplitPairFilter> filterSet = new HashSet<>();
      filterSet.add(splitPairFilter);
      ```

    3. स्प्लिट के लिए लेआउट एट्रिब्यूट बनाएं:

      Kotlin

      val splitAttributes: SplitAttributes = SplitAttributes.Builder()
          .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
          .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
          .build()

      Java

      SplitAttributes splitAttributes = new SplitAttributes.Builder()
            .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
            .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
            .build();

      SplitAttributes.Builder, लेआउट एट्रिब्यूट वाला ऑब्जेक्ट बनाता है:

      • setSplitType(): इससे यह तय होता है कि उपलब्ध डिसप्ले एरिया को हर गतिविधि कंटेनर के लिए कैसे बांटा जाता है. रेश्यो स्प्लिट टाइप से यह तय होता है कि डिसप्ले के लिए उपलब्ध जगह का कितना हिस्सा प्राइमरी कंटेनर को दिया जाएगा. बाकी हिस्सा सेकंडरी कंटेनर को दिया जाता है.
      • setLayoutDirection(): इससे पता चलता है कि गतिविधि कंटेनर, एक-दूसरे के हिसाब से कैसे व्यवस्थित किए जाते हैं. इसमें प्राइमरी कंटेनर को सबसे पहले रखा जाता है.
    4. SplitPairRule बनाएं:

      Kotlin

      val splitPairRule = SplitPairRule.Builder(filterSet)
          .setDefaultSplitAttributes(splitAttributes)
          .setMinWidthDp(840)
          .setMinSmallestWidthDp(600)
          .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
          .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER)
          .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS)
          .setClearTop(false)
          .build()

      Java

      SplitPairRule splitPairRule = new SplitPairRule.Builder(filterSet)
          .setDefaultSplitAttributes(splitAttributes)
          .setMinWidthDp(840)
          .setMinSmallestWidthDp(600)
          .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
          .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER)
          .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS)
          .setClearTop(false)
          .build();

      SplitPairRule.Builder नियम बनाता है और उसे कॉन्फ़िगर करता है:

      • filterSet: इसमें स्प्लिट पेयर फ़िल्टर होते हैं. ये फ़िल्टर, स्प्लिट शेयर करने वाली गतिविधियों की पहचान करके यह तय करते हैं कि नियम कब लागू करना है.
      • setDefaultSplitAttributes(): इससे लेआउट एट्रिब्यूट, नियम पर लागू होते हैं.
      • setMinWidthDp(): यह डिसप्ले की कम से कम चौड़ाई (डेंसिटी‑इंडिपेंडेंट पिक्सल, डीपी में) सेट करता है, जिससे स्प्लिट की सुविधा चालू हो जाती है.
      • setMinSmallestWidthDp(): यह कम से कम वैल्यू (डीपी में) सेट करता है. डिसप्ले के दो डाइमेंशन में से छोटे डाइमेंशन में यह वैल्यू होनी चाहिए, ताकि डिवाइस के ओरिएंटेशन से कोई फ़र्क़ न पड़े और स्प्लिट मोड चालू हो सके.
      • setMaxAspectRatioInPortrait(): पोर्ट्रेट ओरिएंटेशन में, डिसप्ले के ऐसेट रेशियो (ऊंचाई:चौड़ाई) की ज़्यादा से ज़्यादा वैल्यू सेट करता है जिसके लिए गतिविधि के स्प्लिट दिखाए जाते हैं. अगर पोर्ट्रेट डिसप्ले का आसपेक्ट रेशियो, ज़्यादा से ज़्यादा आसपेक्ट रेशियो से ज़्यादा है, तो डिसप्ले की चौड़ाई कुछ भी हो, स्प्लिट डिसप्ले की सुविधा काम नहीं करेगी. ध्यान दें: डिफ़ॉल्ट वैल्यू 1.4 होती है. इससे ज़्यादातर टैबलेट पर, पोर्ट्रेट मोड में टास्क विंडो पूरी तरह से भर जाती है. SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT और setMaxAspectRatioInLandscape() भी देखें. लैंडस्केप के लिए डिफ़ॉल्ट वैल्यू ALWAYS_ALLOW है.
      • setFinishPrimaryWithSecondary(): इससे यह तय होता है कि सेकंडरी कंटेनर में मौजूद सभी गतिविधियों को पूरा करने से, प्राइमरी कंटेनर में मौजूद गतिविधियों पर क्या असर पड़ता है. NEVER से पता चलता है कि सेकंडरी कंटेनर में मौजूद सभी गतिविधियां पूरी होने पर, सिस्टम को मुख्य गतिविधियां पूरी नहीं करनी चाहिए (गतिविधियां पूरी करना देखें).
      • setFinishSecondaryWithPrimary(): इससे यह तय होता है कि प्राइमरी कंटेनर में मौजूद सभी गतिविधियों को पूरा करने से, सेकंडरी कंटेनर में मौजूद गतिविधियों पर क्या असर पड़ता है. ALWAYS से पता चलता है कि जब प्राइमरी कंटेनर में मौजूद सभी गतिविधियां पूरी हो जाती हैं, तब सिस्टम को हमेशा सेकंडरी कंटेनर में मौजूद गतिविधियों को पूरा करना चाहिए. इसके बारे में जानने के लिए, गतिविधियां पूरी करना लेख पढ़ें.
      • setClearTop(): इससे यह तय होता है कि कंटेनर में नई गतिविधि शुरू होने पर, सेकंडरी कंटेनर में मौजूद सभी गतिविधियां पूरी हो गई हैं या नहीं. false वैल्यू से पता चलता है कि नई गतिविधियां, पहले से ही सेकंडरी कंटेनर में मौजूद गतिविधियों के ऊपर स्टैक की जाती हैं.
    5. WindowManager RuleController का सिंगलटन इंस्टेंस पाएं और यह नियम जोड़ें:

      Kotlin

      val ruleController = RuleController.getInstance(this)
      ruleController.addRule(splitPairRule)

      Java

      RuleController ruleController = RuleController.getInstance(this);
      ruleController.addRule(splitPairRule);

    6. कॉन्टेंट उपलब्ध न होने पर, सेकंडरी कंटेनर के लिए प्लेसहोल्डर बनाएं:

    7. एक ऐसा ActivityFilter बनाएं जो उस गतिविधि की पहचान करे जिसके साथ प्लेसहोल्डर, टास्क विंडो को बांटता है:

      Kotlin

      val placeholderActivityFilter = ActivityFilter(
          ComponentName(this, ListActivity::class.java),
          null
      )

      Java

      ActivityFilter placeholderActivityFilter = new ActivityFilter(
          new ComponentName(this, ListActivity.class),
          null
      );

    8. फ़िल्टर को फ़िल्टर सेट में जोड़ें:

      Kotlin

      val placeholderActivityFilterSet = setOf(placeholderActivityFilter)

      Java

      Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>();
      placeholderActivityFilterSet.add(placeholderActivityFilter);

    9. SplitPlaceholderRule बनाएं:

      Kotlin

      val splitPlaceholderRule = SplitPlaceholderRule.Builder(
          placeholderActivityFilterSet,
          Intent(context, PlaceholderActivity::class.java)
      ).setDefaultSplitAttributes(splitAttributes)
          .setMinWidthDp(840)
          .setMinSmallestWidthDp(600)
          .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
          .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS)
          .setSticky(false)
          .build()

      Java

      SplitPlaceholderRule splitPlaceholderRule = new SplitPlaceholderRule.Builder(
            placeholderActivityFilterSet,
            new Intent(this, PlaceholderActivity.class)
          ).setDefaultSplitAttributes(splitAttributes)
           .setMinWidthDp(840)
           .setMinSmallestWidthDp(600)
           .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
           .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS)
           .setSticky(false)
           .build();

      SplitPlaceholderRule.Builder नियम बनाता है और उसे कॉन्फ़िगर करता है:

      • placeholderActivityFilterSet: इसमें गतिविधि के फ़िल्टर होते हैं. इनसे यह तय होता है कि नियम कब लागू करना है. इसके लिए, उन गतिविधियों की पहचान की जाती है जिनसे प्लेसहोल्डर गतिविधि जुड़ी होती है.
      • Intent: इससे प्लेसहोल्डर गतिविधि के लॉन्च होने के बारे में पता चलता है.
      • setDefaultSplitAttributes(): इससे लेआउट एट्रिब्यूट, नियम पर लागू होते हैं.
      • setMinWidthDp(): यह डिसप्ले की कम से कम चौड़ाई (डेंसिटी-इंडिपेंडेंट पिक्सल, डीपी में) सेट करता है जिससे स्प्लिट करने की अनुमति मिलती है.
      • setMinSmallestWidthDp(): यह डिसप्ले के दोनों डाइमेंशन में से छोटे डाइमेंशन के लिए, कम से कम वैल्यू (डीपी में) सेट करता है. इससे डिवाइस के ओरिएंटेशन से कोई फ़र्क़ नहीं पड़ता.
      • setMaxAspectRatioInPortrait(): इससे पोर्ट्रेट ओरिएंटेशन में, डिसप्ले के ज़्यादा से ज़्यादा आसपेक्ट रेशियो (ऊंचाई:चौड़ाई) को सेट किया जाता है. इस आसपेक्ट रेशियो में, गतिविधि के स्प्लिट दिखाए जाते हैं. ध्यान दें: डिफ़ॉल्ट वैल्यू 1.4 होती है. इससे ज़्यादातर टैबलेट पर, टास्क विंडो में पोर्ट्रेट ओरिएंटेशन में गतिविधियां दिखती हैं. SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT और setMaxAspectRatioInLandscape() भी देखें. लैंडस्केप के लिए डिफ़ॉल्ट वैल्यू ALWAYS_ALLOW है.
      • setFinishPrimaryWithPlaceholder(): इससे यह तय होता है कि प्लेसहोल्डर गतिविधि पूरी होने पर, प्राइमरी कंटेनर में मौजूद गतिविधियों पर क्या असर पड़ेगा. ALWAYS से पता चलता है कि जब प्लेसहोल्डर खत्म हो जाए, तो सिस्टम को प्राइमरी कंटेनर में मौजूद गतिविधियों को हमेशा पूरा करना चाहिए (गतिविधियां पूरी करना देखें).
      • setSticky(): इससे यह तय होता है कि जब स्प्लिट स्क्रीन में प्लेसहोल्डर पहली बार दिखेगा, तब छोटी स्क्रीन पर प्लेसहोल्डर ऐक्टिविटी, ऐक्टिविटी स्टैक में सबसे ऊपर दिखेगी या नहीं. इसके लिए, स्प्लिट स्क्रीन की चौड़ाई कम से कम ज़रूरी चौड़ाई के बराबर होनी चाहिए.
    10. नियम को WindowManager RuleController में जोड़ें:

      Kotlin

      ruleController.addRule(splitPlaceholderRule)

      Java

      ruleController.addRule(splitPlaceholderRule);

  2. उन गतिविधियों के बारे में बताएं जिन्हें कभी भी स्प्लिट नहीं किया जाना चाहिए:

    1. ऐसी ActivityFilter बनाएं जो ऐसी ऐक्टिविटी की पहचान करे जिसे हमेशा टास्क डिसप्ले एरिया के पूरे हिस्से पर दिखाना चाहिए:

      Kotlin

      val expandedActivityFilter = ActivityFilter(
          ComponentName(this, ExpandedActivity::class.java),
          null
      )

      Java

      ActivityFilter expandedActivityFilter = new ActivityFilter(
          new ComponentName(this, ExpandedActivity.class),
          null
      );

    2. फ़िल्टर को फ़िल्टर सेट में जोड़ें:

      Kotlin

      val expandedActivityFilterSet = setOf(expandedActivityFilter)

      Java

      Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>();
      expandedActivityFilterSet.add(expandedActivityFilter);

    3. ActivityRule बनाएं:

      Kotlin

      val activityRule = ActivityRule.Builder(expandedActivityFilterSet)
          .setAlwaysExpand(true)
          .build()

      Java

      ActivityRule activityRule = new ActivityRule.Builder(
          expandedActivityFilterSet
      ).setAlwaysExpand(true)
       .build();

      ActivityRule.Builder नियम बनाता है और उसे कॉन्फ़िगर करता है:

      • expandedActivityFilterSet: इसमें गतिविधि के फ़िल्टर होते हैं. इनकी मदद से यह तय किया जाता है कि नियम कब लागू करना है. इसके लिए, उन गतिविधियों की पहचान की जाती है जिन्हें आपको स्प्लिट से हटाना है.
      • setAlwaysExpand(): इससे यह तय होता है कि गतिविधि को पूरे टास्क विंडो में दिखाना है या नहीं.
    4. नियम को WindowManager RuleController में जोड़ें:

      Kotlin

      ruleController.addRule(activityRule)

      Java

      ruleController.addRule(activityRule);

अलग-अलग ऐप्लिकेशन में एम्बेड करना

Android 13 (एपीआई लेवल 33) और उसके बाद के वर्शन पर, ऐप्लिकेशन अन्य ऐप्लिकेशन से ऐक्टिविटी एम्बेड कर सकते हैं. क्रॉस‑ऐप्लिकेशन या क्रॉस‑यूआईडी ऐक्टिविटी एम्बेड करने की सुविधा की मदद से, एक से ज़्यादा Android ऐप्लिकेशन की ऐक्टिविटी को विज़ुअल तौर पर इंटिग्रेट किया जा सकता है. सिस्टम, होस्ट ऐप्लिकेशन की ऐक्टिविटी और किसी दूसरे ऐप्लिकेशन से एम्बेड की गई ऐक्टिविटी को स्क्रीन पर अगल-बगल या ऊपर और नीचे दिखाता है. यह ठीक उसी तरह होता है जैसे किसी एक ऐप्लिकेशन की ऐक्टिविटी को एम्बेड किया जाता है.

उदाहरण के लिए, Settings ऐप्लिकेशन, WallpaperPicker ऐप्लिकेशन से वॉलपेपर चुनने की सुविधा को एम्बेड कर सकता है:

इमेज 14. सेटिंग ऐप्लिकेशन (बाईं ओर मौजूद मेन्यू) में, वॉलपेपर चुनने की सुविधा को एम्बेड की गई गतिविधि (दाईं ओर) के तौर पर दिखाया गया है.

ट्रस्ट मॉडल

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

क्रॉस-ऐप्लिकेशन गतिविधि एम्बेड करने की सुविधा का गलत इस्तेमाल रोकने के लिए, Android को यह ज़रूरी है कि ऐप्लिकेशन, अपनी गतिविधियों को एम्बेड करने की अनुमति देने के लिए ऑप्ट-इन करें. ऐप्लिकेशन, होस्ट को भरोसेमंद या गैर-भरोसेमंद के तौर पर मार्क कर सकते हैं.

भरोसेमंद होस्ट

अगर आपको अन्य ऐप्लिकेशन को अपने ऐप्लिकेशन की गतिविधियों को एम्बेड करने और उनके प्रज़ेंटेशन को पूरी तरह से कंट्रोल करने की अनुमति देनी है, तो अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल के <activity> या <application> एलिमेंट के android:knownActivityEmbeddingCerts एट्रिब्यूट में, होस्ट ऐप्लिकेशन का SHA-256 सर्टिफ़िकेट डालें.

android:knownActivityEmbeddingCerts की वैल्यू को स्ट्रिंग के तौर पर सेट करें:

<activity
    android:name=".MyEmbeddableActivity"
    android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
    ... />

या, एक से ज़्यादा सर्टिफ़िकेट तय करने के लिए, स्ट्रिंग की एक कैटगरी:

<activity
    android:name=".MyEmbeddableActivity"
    android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
    ... />

जो इस तरह के किसी संसाधन को रेफ़रंस करता है:

<resources>
    <string-array name="known_host_certificate_digests">
      <item>cert1</item>
      <item>cert2</item>
      ...
    </string-array>
</resources>

ऐप्लिकेशन के मालिक, Gradle signingReport टास्क चलाकर SHA सर्टिफ़िकेट डाइजेस्ट पा सकते हैं. सर्टिफ़िकेट डाइजेस्ट, SHA-256 फ़िंगरप्रिंट होता है. इसमें कोलन नहीं होते. ज़्यादा जानकारी के लिए, हस्ताक्षर की रिपोर्ट जनरेट करना और अपने क्लाइंट की पुष्टि करना लेख पढ़ें.

ऐसे होस्ट जिन पर भरोसा नहीं किया जा सकता

किसी भी ऐप्लिकेशन को अपने ऐप्लिकेशन की गतिविधियों को एम्बेड करने और उनके प्रज़ेंटेशन को कंट्रोल करने की अनुमति देने के लिए, ऐप्लिकेशन मेनिफ़ेस्ट में <activity> या <application> एलिमेंट में android:allowUntrustedActivityEmbedding एट्रिब्यूट तय करें. उदाहरण के लिए:

<activity
    android:name=".MyEmbeddableActivity"
    android:allowUntrustedActivityEmbedding="true"
    ... />

इस एट्रिब्यूट की डिफ़ॉल्ट वैल्यू false होती है. इससे, क्रॉस-ऐप्लिकेशन गतिविधि को एम्बेड करने से रोका जाता है.

पुष्टि करने का कस्टम तरीका

भरोसेमंद न होने वाली गतिविधि को एम्बेड करने से जुड़े जोखिमों को कम करने के लिए, पुष्टि करने का कस्टम तरीका बनाएं. इससे होस्ट की पहचान की पुष्टि की जा सकेगी. अगर आपको होस्ट के सर्टिफ़िकेट के बारे में पता है, तो पुष्टि करने के लिए androidx.security.app.authenticator लाइब्रेरी का इस्तेमाल करें. अगर होस्ट आपकी गतिविधि को एम्बेड करने के बाद पुष्टि करता है, तो आपके पास असली कॉन्टेंट दिखाने का विकल्प होता है. अगर ऐसा नहीं है, तो उपयोगकर्ता को बताएं कि कार्रवाई की अनुमति नहीं दी गई है और कॉन्टेंट को ब्लॉक करें.

Jetpack WindowManager लाइब्रेरी से ActivityEmbeddingController#isActivityEmbedded() तरीके का इस्तेमाल करके यह पता लगाएं कि कोई होस्ट आपकी गतिविधि को एम्बेड कर रहा है या नहीं. उदाहरण के लिए:

Kotlin

fun isActivityEmbedded(activity: Activity): Boolean {
    return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity)
}

Java

boolean isActivityEmbedded(Activity activity) {
    return ActivityEmbeddingController.getInstance(context).isActivityEmbedded(activity);
}

कम से कम साइज़ से जुड़ी पाबंदी

Android सिस्टम, ऐप्लिकेशन मेनिफ़ेस्ट <layout> एलिमेंट में बताई गई कम से कम ऊंचाई और चौड़ाई को एम्बेड की गई गतिविधियों पर लागू करता है. अगर कोई ऐप्लिकेशन कम से कम ऊंचाई और चौड़ाई तय नहीं करता है, तो सिस्टम की डिफ़ॉल्ट वैल्यू लागू होती हैं (sw220dp).

अगर होस्ट, एम्बेड किए गए कंटेनर का साइज़ कम से कम साइज़ से छोटा करने की कोशिश करता है, तो एम्बेड किया गया कंटेनर, टास्क की पूरी जगह पर फैल जाता है.

<activity-alias>

भरोसेमंद या गैर-भरोसेमंद गतिविधि एम्बेड करने के लिए, <activity-alias> एलिमेंट के साथ काम करने के लिए, android:knownActivityEmbeddingCerts या android:allowUntrustedActivityEmbedding को टारगेट गतिविधि पर लागू किया जाना चाहिए, न कि एलियास पर. सिस्टम सर्वर पर सुरक्षा की पुष्टि करने वाली नीति, टारगेट पर सेट किए गए फ़्लैग पर आधारित होती है, न कि एलियास पर.

होस्ट ऐप्लिकेशन

होस्ट ऐप्लिकेशन, क्रॉस-ऐप्लिकेशन गतिविधि को उसी तरह एम्बेड करते हैं जिस तरह वे सिंगल-ऐप्लिकेशन गतिविधि को एम्बेड करते हैं. SplitPairRule और SplitPairFilter या ActivityRule और ActivityFilter ऑब्जेक्ट, एम्बेड की गई गतिविधियों और टास्क विंडो के स्प्लिट के बारे में बताते हैं. स्प्लिट के नियमों को एक्सएमएल में स्टैटिक तौर पर या Jetpack WindowManager API कॉल का इस्तेमाल करके रनटाइम में तय किया जाता है.

अगर कोई होस्ट ऐप्लिकेशन, ऐसी गतिविधि को एम्बेड करने की कोशिश करता है जिसने क्रॉस-ऐप्लिकेशन एम्बेडिंग के लिए ऑप्ट-इन नहीं किया है, तो गतिविधि पूरे टास्क बाउंड को कवर कर लेती है. इसलिए, होस्ट ऐप्लिकेशन को यह पता होना चाहिए कि टारगेट की गई गतिविधियों में, क्रॉस-ऐप्लिकेशन एम्बेडिंग की अनुमति है या नहीं.

अगर एम्बेड की गई कोई गतिविधि, उसी टास्क में नई गतिविधि शुरू करती है और नई गतिविधि ने क्रॉस-ऐप्लिकेशन एम्बेडिंग के लिए ऑप्ट-इन नहीं किया है, तो गतिविधि, एम्बेड किए गए कंटेनर में ओवरले करने के बजाय, पूरे टास्क बाउंड को कवर करती है.

होस्ट ऐप्लिकेशन, बिना किसी पाबंदी के अपनी गतिविधियां एम्बेड कर सकता है. हालांकि, ऐसा तब तक किया जा सकता है, जब तक गतिविधियां एक ही टास्क में लॉन्च होती हैं.

स्प्लिट के उदाहरण

फ़ुल विंडो से स्प्लिट स्क्रीन मोड चालू करना

इमेज 15. ऐक्टिविटी A, ऐक्टिविटी B को साइड में शुरू करती है.

रीफ़ैक्टरिंग की ज़रूरत नहीं है. स्प्लिट के लिए कॉन्फ़िगरेशन को स्टैटिक तौर पर या रनटाइम पर तय किया जा सकता है. इसके बाद, बिना किसी अतिरिक्त पैरामीटर के Context#startActivity() को कॉल किया जा सकता है.

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

डिफ़ॉल्ट रूप से स्प्लिट किया गया

जब किसी ऐप्लिकेशन के लैंडिंग पेज को बड़ी स्क्रीन पर दो कंटेनर में बांटने के लिए डिज़ाइन किया जाता है, तो उपयोगकर्ता अनुभव सबसे अच्छा तब होता है, जब दोनों गतिविधियां एक साथ बनाई और दिखाई जाती हैं. हालांकि, जब तक उपयोगकर्ता प्राइमरी कंटेनर में मौजूद ऐक्टिविटी से इंटरैक्ट नहीं करता, तब तक स्प्लिट किए गए कॉन्टेंट का सेकंडरी कंटेनर उपलब्ध नहीं हो सकता. उदाहरण के लिए, उपयोगकर्ता ने नेविगेशन मेन्यू से कोई आइटम चुना. स्प्लिट किए गए लेआउट के सेकंडरी कंटेनर में कॉन्टेंट दिखने तक, प्लेसहोल्डर गतिविधि से खाली जगह को भरा जा सकता है. इसके बारे में जानने के लिए, प्लेसहोल्डर सेक्शन देखें.

इमेज 16. दो गतिविधियों को एक साथ खोलने पर बनाया गया स्प्लिट. एक गतिविधि, प्लेसहोल्डर है.

प्लेसहोल्डर के साथ स्प्लिट बनाने के लिए, एक प्लेसहोल्डर बनाएं और उसे मुख्य गतिविधि से असोसिएट करें:

<SplitPlaceholderRule
    window:placeholderActivityName=".PlaceholderActivity">
    <ActivityFilter
        window:activityName=".MainActivity"/>
</SplitPlaceholderRule>

जब किसी ऐप्लिकेशन को इंटेंट मिलता है, तो टारगेट ऐक्टिविटी को ऐक्टिविटी स्प्लिट के दूसरे हिस्से के तौर पर दिखाया जा सकता है. उदाहरण के लिए, सूची में मौजूद किसी आइटम के बारे में जानकारी वाली स्क्रीन दिखाने का अनुरोध. छोटी स्क्रीन पर, टास्क की पूरी विंडो में जानकारी दिखती है. वहीं, बड़े डिवाइसों पर यह जानकारी सूची के बगल में दिखती है.

इमेज 17. छोटी स्क्रीन पर, डीप लिंक की जानकारी वाली ऐक्टिविटी को अलग से दिखाया गया है. हालांकि, बड़ी स्क्रीन पर इसे सूची वाली ऐक्टिविटी के साथ दिखाया गया है.

लॉन्च करने का अनुरोध मुख्य गतिविधि पर भेजा जाना चाहिए. साथ ही, टारगेट की जानकारी वाली गतिविधि को स्प्लिट स्क्रीन में लॉन्च किया जाना चाहिए. सिस्टम, डिसप्ले की चौड़ाई के हिसाब से, सही प्रज़ेंटेशन अपने-आप चुनता है. जैसे, स्टैक किया गया या अगल-बगल.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    RuleController.getInstance(this)
        .addRule(SplitPairRule.Builder(filterSet).build())
    startActivity(Intent(this, DetailActivity::class.java))
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    RuleController.getInstance(this)
        .addRule(new SplitPairRule.Builder(filterSet).build());
    startActivity(new Intent(this, DetailActivity.class));
}

बैक नेविगेशन स्टैक में, डीप लिंक डेस्टिनेशन ही ऐसी गतिविधि हो सकती है जो उपयोगकर्ता के लिए उपलब्ध होनी चाहिए. साथ ही, आपको जानकारी वाली गतिविधि को खारिज करने और सिर्फ़ मुख्य गतिविधि को छोड़ने से बचना चाहिए:

बड़ी स्क्रीन पर, सूची वाली गतिविधि और जानकारी वाली गतिविधि को अगल-बगल दिखाया गया है.
          बैक नेविगेशन से, जानकारी वाली गतिविधि को खारिज नहीं किया जा सकता. साथ ही, सूची वाली गतिविधि को स्क्रीन पर नहीं छोड़ा जा सकता.

छोटी डिसप्ले, जिसमें सिर्फ़ गतिविधि की जानकारी होती है. बैक नेविगेशन की सुविधा, जानकारी वाली गतिविधि को खारिज नहीं कर सकती और सूची वाली गतिविधि को दिखा नहीं सकती.

इसके बजाय, finishPrimaryWithSecondary एट्रिब्यूट का इस्तेमाल करके, दोनों गतिविधियों को एक साथ पूरा किया जा सकता है:

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".ListActivity"
        window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>

कॉन्फ़िगरेशन एट्रिब्यूट सेक्शन देखें.

स्प्लिट कंटेनर में कई गतिविधियां

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

इमेज 18. टास्क विंडो के सेकंडरी पैन में, गतिविधि को उसी जगह पर खोला गया.

Kotlin

class DetailActivity : AppCompatActivity() {
    fun onOpenSubdetail() {
        startActivity(Intent(this, SubdetailActivity::class.java))
    }
}

Java

public class DetailActivity  extends AppCompatActivity {
    void onOpenSubdetail() {
        startActivity(new Intent(this, SubdetailActivity.class));
    }
}

ज़्यादा जानकारी वाली गतिविधि के ऊपर, कम जानकारी वाली गतिविधि दिखती है. इससे ज़्यादा जानकारी वाली गतिविधि छिप जाती है:

इसके बाद, उपयोगकर्ता स्टैक में वापस जाकर, जानकारी के पिछले लेवल पर वापस जा सकता है:

इमेज 19. ऐक्टिविटी को स्टैक में सबसे ऊपर से हटा दिया गया है.

जब एक ही सेकंडरी कंटेनर में मौजूद किसी गतिविधि से अन्य गतिविधियां लॉन्च की जाती हैं, तो वे एक-दूसरे के ऊपर स्टैक हो जाती हैं. यह डिफ़ॉल्ट व्यवहार है. स्प्लिट स्क्रीन मोड में चालू प्राइमरी कंटेनर से लॉन्च की गई गतिविधियां भी, गतिविधि स्टैक में सबसे ऊपर मौजूद सेकंडरी कंटेनर में दिखती हैं.

नए टास्क में की गई गतिविधियां

जब स्प्लिट टास्क विंडो में मौजूद गतिविधियां, किसी नए टास्क में गतिविधियां शुरू करती हैं, तो नया टास्क, स्प्लिट किए गए टास्क से अलग होता है. साथ ही, यह फ़ुल विंडो में दिखता है. 'हाल ही के' स्क्रीन पर दो टास्क दिख रहे हैं: स्प्लिट स्क्रीन में मौजूद टास्क और नया टास्क.

इमेज 20. गतिविधि B से, गतिविधि C को नए टास्क में शुरू करें.

गतिविधि बदलना

सेकंडरी कंटेनर स्टैक में ऐक्टिविटी बदली जा सकती हैं. उदाहरण के लिए, जब टॉप-लेवल नेविगेशन के लिए प्राइमरी ऐक्टिविटी का इस्तेमाल किया जाता है और सेकंडरी ऐक्टिविटी, चुना गया डेस्टिनेशन होती है. टॉप-लेवल नेविगेशन से हर आइटम चुनने पर, सेकंडरी कंटेनर में नई गतिविधि शुरू होनी चाहिए. साथ ही, पहले से मौजूद गतिविधि या गतिविधियों को हटा देना चाहिए.

इमेज 21. प्राइमरी पैन में टॉप-लेवल नेविगेशन की गतिविधि, सेकंडरी पैन में डेस्टिनेशन की गतिविधियों की जगह ले लेती है.

अगर नेविगेशन का विकल्प बदलने पर, ऐप्लिकेशन सेकंडरी कंटेनर में गतिविधि पूरी नहीं करता है, तो स्प्लिट स्क्रीन बंद होने पर (जब डिवाइस को फ़ोल्ड किया जाता है), वापस जाने का नेविगेशन भ्रमित करने वाला हो सकता है. उदाहरण के लिए, अगर आपके पास प्राइमरी पैन में कोई मेन्यू है और सेकंडरी पैन में स्क्रीन A और B स्टैक की गई हैं, तो जब उपयोगकर्ता फ़ोन को फ़ोल्ड करता है, तो B, A के ऊपर होता है और A, मेन्यू के ऊपर होता है. जब उपयोगकर्ता B से वापस जाता है, तो मेन्यू की जगह A दिखता है.

ऐसे मामलों में, स्क्रीन A को बैक स्टैक से हटाना ज़रूरी है.

स्प्लिट स्क्रीन पर पहले से मौजूद किसी कंटेनर के बगल में नया कंटेनर लॉन्च करने पर, डिफ़ॉल्ट रूप से नए सेकंडरी कंटेनर सबसे ऊपर दिखते हैं. साथ ही, पुराने कंटेनर बैक स्टैक में बने रहते हैं. clearTop का इस्तेमाल करके, स्प्लिट को कॉन्फ़िगर किया जा सकता है, ताकि पिछले सेकंडरी कंटेनर को मिटाया जा सके. साथ ही, नई गतिविधियों को सामान्य तरीके से लॉन्च किया जा सके.

<SplitPairRule
    window:clearTop="true">
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenA"/>
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>

Kotlin

inner class MenuActivity : AppCompatActivity() {
    fun onMenuItemSelected(selectedMenuItem: Int) {
        startActivity(Intent(this, classForItem(selectedMenuItem)))
    }
}

Java

public class MenuActivity extends AppCompatActivity{
    void onMenuItemSelected(int selectedMenuItem) {
        startActivity(new Intent(this, classForItem(selectedMenuItem)));
    }
}

इसके अलावा, एक ही सेकंडरी गतिविधि का इस्तेमाल करें. साथ ही, प्राइमरी (मेन्यू) गतिविधि से ऐसे नए इंटेंट भेजें जो एक ही इंस्टेंस में हल हो जाएं. हालांकि, इससे सेकंडरी कंटेनर में कोई स्थिति ट्रिगर हो या यूज़र इंटरफ़ेस (यूआई) अपडेट हो.

एक से ज़्यादा स्प्लिट

ऐप्लिकेशन, साइड में अतिरिक्त गतिविधियां लॉन्च करके, कई लेवल वाला डीप नेविगेशन उपलब्ध करा सकते हैं.

जब किसी सेकंडरी कंटेनर में मौजूद कोई ऐक्टिविटी, साइड में नई ऐक्टिविटी लॉन्च करती है, तो मौजूदा स्प्लिट के ऊपर एक नया स्प्लिट बन जाता है.

इमेज 22. गतिविधि B, गतिविधि C को साइड में शुरू करती है.

बैक स्टैक में वे सभी गतिविधियां शामिल होती हैं जिन्हें पहले खोला गया था. इसलिए, उपयोगकर्ता C को पूरा करने के बाद A/B स्प्लिट पर जा सकते हैं.

स्टैक में मौजूद गतिविधियां A, B, और C. गतिविधियों को ऊपर से नीचे की ओर इस क्रम में रखा जाता है: C, B, A.

नया स्प्लिट बनाने के लिए, मौजूदा सेकंडरी कंटेनर से नई गतिविधि को साइड में लॉन्च करें. A/B और B/C, दोनों स्प्लिट के लिए कॉन्फ़िगरेशन का एलान करें. साथ ही, B से C गतिविधि को सामान्य तौर पर लॉन्च करें:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
    <SplitPairFilter
        window:primaryActivityName=".B"
        window:secondaryActivityName=".C"/>
</SplitPairRule>

Kotlin

class B : AppCompatActivity() {
    fun onOpenC() {
        startActivity(Intent(this, C::class.java))
    }
}

Java

public class B extends AppCompatActivity{
    void onOpenC() {
        startActivity(new Intent(this, C.class));
    }
}

स्प्लिट की स्थिति में होने वाले बदलावों पर प्रतिक्रिया करना

किसी ऐप्लिकेशन में अलग-अलग ऐक्टिविटी के लिए, ऐसे यूज़र इंटरफ़ेस (यूआई) एलिमेंट हो सकते हैं जो एक ही फ़ंक्शन को पूरा करते हैं. उदाहरण के लिए, एक ऐसा कंट्रोल जो खाता सेटिंग वाली विंडो खोलता है.

इमेज 23. एक जैसी सुविधाओं वाले यूज़र इंटरफ़ेस (यूआई) एलिमेंट के साथ अलग-अलग गतिविधियां.

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

इमेज 24. ऐक्टिविटी स्प्लिट में यूज़र इंटरफ़ेस (यूआई) के डुप्लीकेट एलिमेंट.

यह जानने के लिए कि गतिविधियां कब स्प्लिट होती हैं, SplitController.splitInfoList फ़्लो देखें या स्प्लिट की स्थिति में बदलावों के लिए, SplitControllerCallbackAdapter के साथ लिसनर रजिस्टर करें. इसके बाद, यूज़र इंटरफ़ेस (यूआई) में इसके मुताबिक बदलाव करें:

Kotlin

val layout = layoutInflater.inflate(R.layout.activity_main, null)
val view = layout.findViewById<View>(R.id.infoButton)
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        splitController.splitInfoList(this@SplitDeviceActivity) // The activity instance.
            .collect { list ->
                view.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE
            }
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    new SplitControllerCallbackAdapter(SplitController.getInstance(this))
        .addSplitListener(
            this,
            Runnable::run,
            splitInfoList -> {
                View layout = getLayoutInflater().inflate(R.layout.activity_main, null);
                layout.findViewById(R.id.infoButton).setVisibility(
                    splitInfoList.isEmpty() ? View.VISIBLE : View.GONE);
            });
}

कोरूटीन को लाइफ़साइकल की किसी भी स्थिति में लॉन्च किया जा सकता है. हालांकि, आम तौर पर इन्हें STARTED स्थिति में लॉन्च किया जाता है, ताकि संसाधनों को बचाया जा सके. ज़्यादा जानकारी के लिए, लाइफ़साइकल के बारे में जानकारी रखने वाले कॉम्पोनेंट के साथ Kotlin कोरूटीन का इस्तेमाल करना लेख पढ़ें.

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

फ़ुल-विंडो मोडल

कुछ गतिविधियां, उपयोगकर्ताओं को ऐप्लिकेशन से इंटरैक्ट करने से तब तक रोकती हैं, जब तक कोई तय कार्रवाई नहीं की जाती. उदाहरण के लिए, लॉगिन स्क्रीन गतिविधि, नीति की पुष्टि करने वाली स्क्रीन या गड़बड़ी का मैसेज. स्प्लिट स्क्रीन में, मोडल गतिविधियों को दिखने से रोकना चाहिए.

एक्सपैंड कॉन्फ़िगरेशन का इस्तेमाल करके, किसी गतिविधि को हमेशा टास्क विंडो भरने के लिए मजबूर किया जा सकता है:

<ActivityRule
    window:alwaysExpand="true">
    <ActivityFilter
        window:activityName=".FullWidthActivity"/>
</ActivityRule>

गतिविधियां पूरी करना

उपयोगकर्ता, डिसप्ले के किनारे से स्वाइप करके, स्प्लिट स्क्रीन के दोनों हिस्सों में मौजूद गतिविधियों को पूरा कर सकते हैं:

इमेज 25. गतिविधि B को खत्म करने के लिए स्वाइप करने का जेस्चर.
इमेज 26. स्वाइप जेस्चर से गतिविधि A को खत्म किया जा रहा है.

अगर डिवाइस को जेस्चर नेविगेशन के बजाय, 'वापस जाएं' बटन का इस्तेमाल करने के लिए सेट अप किया गया है, तो इनपुट को फ़ोकस की गई गतिविधि पर भेजा जाता है. यह वह गतिविधि होती है जिसे आखिरी बार छुआ गया था या लॉन्च किया गया था.

किसी कंटेनर में सभी गतिविधियां पूरी करने का असर, दूसरे कंटेनर पर पड़ता है. यह स्प्लिट कॉन्फ़िगरेशन पर निर्भर करता है.

कॉन्फ़िगरेशन एट्रिब्यूट

स्प्लिट पेयर के नियम वाले एट्रिब्यूट तय किए जा सकते हैं. इससे यह कॉन्फ़िगर किया जा सकता है कि स्प्लिट के एक हिस्से में सभी गतिविधियां पूरी होने पर, स्प्लिट के दूसरे हिस्से की गतिविधियों पर क्या असर पड़ेगा. ये एट्रिब्यूट हैं:

  • window:finishPrimaryWithSecondary — सेकंडरी कंटेनर में सभी गतिविधियां पूरी करने से, प्राइमरी कंटेनर में मौजूद गतिविधियों पर क्या असर पड़ता है
  • window:finishSecondaryWithPrimary — प्राइमरी कंटेनर में सभी गतिविधियां पूरी करने से, सेकंडरी कंटेनर में मौजूद गतिविधियों पर क्या असर पड़ता है

इन एट्रिब्यूट की संभावित वैल्यू ये हैं:

  • always — इससे जुड़ी गतिविधियों को हमेशा कंटेनर में पूरा करें
  • never — इससे जुड़ी गतिविधियों को कभी भी बंद नहीं किया जाता
  • adjacent — जब दो कंटेनर एक-दूसरे के बगल में दिख रहे हों, तब उनसे जुड़ी गतिविधियों को पूरा करें. हालांकि, जब दो कंटेनर एक के ऊपर एक रखे गए हों, तब ऐसा न करें

उदाहरण के लिए:

<SplitPairRule
    <!-- Do not finish primary container activities when all secondary container activities finish. -->
    window:finishPrimaryWithSecondary="never"
    <!-- Finish secondary container activities when all primary container activities finish. -->
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

डिफ़ॉल्ट कॉन्फ़िगरेशन

स्प्लिट किए गए किसी कंटेनर में मौजूद सभी गतिविधियां पूरी होने पर, बाकी कंटेनर पूरी विंडो पर दिखता है:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

स्प्लिट में गतिविधियां A और B शामिल हैं. A बंद हो जाता है और B पूरी विंडो पर दिखता है.

स्प्लिट में गतिविधियां A और B शामिल हैं. B बंद हो जाता है और A पूरी विंडो पर दिखता है.

साथ मिलकर गतिविधियां पूरी करना

सेकंडरी कंटेनर में मौजूद सभी गतिविधियां पूरी होने पर, प्राइमरी कंटेनर में मौजूद गतिविधियां अपने-आप पूरी हो जाएं:

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

स्प्लिट में गतिविधियां A और B शामिल हैं. B पूरा हो गया है. इससे A भी पूरा हो जाता है और टास्क विंडो खाली हो जाती है.

स्प्लिट में गतिविधियां A और B शामिल हैं. A पूरा हो गया है और B को टास्क विंडो में अकेला छोड़ दिया गया है.

प्राइमरी कंटेनर में मौजूद सभी गतिविधियां पूरी होने पर, सेकंडरी कंटेनर में मौजूद गतिविधियां अपने-आप पूरी हो जाएं:

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

स्प्लिट में गतिविधियां A और B शामिल हैं. A पूरा हो गया है. इससे B भी पूरा हो जाता है और टास्क विंडो खाली हो जाती है.

स्प्लिट में गतिविधियां A और B शामिल हैं. B का काम पूरा हो गया है. इसलिए, टास्क विंडो में सिर्फ़ A बचा है.

जब प्राइमरी या सेकंडरी कंटेनर में मौजूद सभी गतिविधियां पूरी हो जाती हैं, तब एक साथ गतिविधियां पूरी करें:

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

स्प्लिट में गतिविधियां A और B शामिल हैं. A पूरा हो गया है. इससे B भी पूरा हो जाता है और टास्क विंडो खाली हो जाती है.

स्प्लिट में गतिविधियां A और B शामिल हैं. B पूरा हो गया है. इससे A भी पूरा हो जाता है और टास्क विंडो खाली हो जाती है.

कंटेनर में एक साथ कई गतिविधियां पूरी करना

अगर स्प्लिट कंटेनर में कई गतिविधियां स्टैक की गई हैं, तो स्टैक में सबसे नीचे मौजूद गतिविधि को पूरा करने से, सबसे ऊपर मौजूद गतिविधियां अपने-आप पूरी नहीं हो जाती हैं.

उदाहरण के लिए, अगर दो गतिविधियां सेकंडरी कंटेनर में हैं, तो B के ऊपर C:

सेकंडरी ऐक्टिविटी स्टैक में, ऐक्टिविटी C को ऐक्टिविटी B के ऊपर रखा गया है. इसे प्राइमरी ऐक्टिविटी स्टैक में, ऐक्टिविटी A के ऊपर रखा गया है.

स्प्लिट का कॉन्फ़िगरेशन, गतिविधियों A और B के कॉन्फ़िगरेशन से तय होता है:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

सबसे ऊपर मौजूद ऐप्लिकेशन को बंद करने पर, स्प्लिट स्क्रीन बंद नहीं होती.

प्राइमरी कंटेनर में गतिविधि A और सेकंडरी कंटेनर में गतिविधियां B और C को स्प्लिट किया गया है. C को B के ऊपर स्टैक किया गया है. C के खत्म होने के बाद, गतिविधि को A और B के बीच बांट दिया जाता है.

सेकंडरी कंटेनर की सबसे नीचे वाली (रूट) गतिविधि को पूरा करने से, उसके ऊपर की गतिविधियां नहीं हटती हैं. इसलिए, स्प्लिट स्क्रीन मोड भी बना रहता है.

प्राइमरी कंटेनर में गतिविधि A और सेकंडरी कंटेनर में गतिविधियां B और C को स्प्लिट किया गया है. C को B के ऊपर स्टैक किया गया है. B के खत्म होने पर, A और C के बीच गतिविधि बंट जाती है.

साथ मिलकर गतिविधियां पूरी करने से जुड़े अन्य नियमों को भी लागू किया जाता है. जैसे, मुख्य गतिविधि के साथ-साथ दूसरी गतिविधि को भी पूरा करना:

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

प्राइमरी कंटेनर में गतिविधि A और सेकंडरी कंटेनर में गतिविधियां B और C को स्प्लिट किया गया है. C को B के ऊपर स्टैक किया गया है. A पूरा हो जाता है. साथ ही, B और C भी पूरे हो जाते हैं.

अगर स्प्लिट को इस तरह कॉन्फ़िगर किया गया है कि प्राइमरी और सेकंडरी, दोनों एक साथ खत्म हों, तो:

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

प्राइमरी कंटेनर में गतिविधि A और सेकंडरी कंटेनर में गतिविधियां B और C को स्प्लिट किया गया है. C को B के ऊपर स्टैक किया गया है. C के खत्म होने के बाद, गतिविधि को A और B के बीच बांट दिया जाता है.

प्राइमरी कंटेनर में गतिविधि A और सेकंडरी कंटेनर में गतिविधियां B और C को स्प्लिट किया गया है. C को B के ऊपर स्टैक किया गया है. B के खत्म होने पर, A और C के बीच गतिविधि बंट जाती है.

प्राइमरी कंटेनर में गतिविधि A और सेकंडरी कंटेनर में गतिविधियां B और C को स्प्लिट किया गया है. C को B के ऊपर स्टैक किया गया है. A पूरा हो जाता है. साथ ही, B और C भी पूरे हो जाते हैं.

रनटाइम के दौरान स्प्लिट प्रॉपर्टी बदलना

चालू और दिखने वाले स्प्लिट की प्रॉपर्टी नहीं बदली जा सकतीं. स्प्लिट के नियमों में बदलाव करने से, अतिरिक्त गतिविधि लॉन्च और नए कंटेनर पर असर पड़ता है. हालांकि, इससे मौजूदा और चालू स्प्लिट पर कोई असर नहीं पड़ता.

चालू स्प्लिट की प्रॉपर्टी बदलने के लिए, स्प्लिट में की जा रही साइड ऐक्टिविटी या ऐक्टिविटी पूरी करें. इसके बाद, नए कॉन्फ़िगरेशन के साथ फिर से साइड ऐक्टिविटी लॉन्च करें.

डाइनैमिक स्प्लिट प्रॉपर्टी

Android 15 (एपीआई लेवल 35) और इसके बाद के वर्शन पर, Jetpack WindowManager 1.4 और इसके बाद के वर्शन काम करते हैं. इनमें डाइनैमिक सुविधाएं मिलती हैं. इनकी मदद से, ऐक्टिविटी एम्बेड करने की सुविधा के स्प्लिट को कॉन्फ़िगर किया जा सकता है. जैसे:

  • पैन का बड़ा होना: इंटरैक्टिव और ड्रैग किए जा सकने वाले डिवाइडर की मदद से, उपयोगकर्ता स्प्लिट प्रज़ेंटेशन में पैन का साइज़ बदल सकते हैं.
  • ऐक्टिविटी स्टैक पिन करना: उपयोगकर्ता किसी एक कंटेनर में कॉन्टेंट पिन कर सकते हैं. साथ ही, एक कंटेनर में नेविगेशन को दूसरे कंटेनर में नेविगेशन से अलग कर सकते हैं.
  • डायलॉग फ़ुल-स्क्रीन डिम: डायलॉग दिखाते समय, ऐप्लिकेशन यह तय कर सकते हैं कि पूरी टास्क विंडो को डिम करना है या सिर्फ़ उस कंटेनर को जिसने डायलॉग खोला है.

पैनल को बड़ा करना

पैन को बड़ा करने की सुविधा की मदद से, उपयोगकर्ता दो पैन वाले लेआउट में, दोनों गतिविधियों के लिए स्क्रीन स्पेस को अडजस्ट कर सकते हैं.

विंडो डिवाइडर के दिखने के तरीके को पसंद के मुताबिक बनाने और डिवाइडर की ड्रैग की जा सकने वाली रेंज सेट करने के लिए, यह तरीका अपनाएं:

  1. DividerAttributes का इंस्टेंस बनाना

  2. डिवाइडर एट्रिब्यूट को पसंद के मुताबिक बनाएं:

    • color: यह ड्रैग किए जा सकने वाले पैनल सेपरेटर का रंग होता है.

    • widthDp: यह ड्रैग किए जा सकने वाले पैन सेपरेटर की चौड़ाई होती है. सिस्टम को डिवाइडर की चौड़ाई तय करने की अनुमति देने के लिए, इसे WIDTH_SYSTEM_DEFAULT पर सेट करें.

    • ड्रैग रेंज: यह स्क्रीन के उस कम से कम प्रतिशत को दिखाता है जिस पर दोनों में से कोई भी पैन दिख सकता है. इसकी वैल्यू 0.33 से 0.66 के बीच हो सकती है. सिस्टम को ड्रैग रेंज तय करने की अनुमति देने के लिए, इसे DRAG_RANGE_SYSTEM_DEFAULT पर सेट करें.

    Kotlin

    val splitAttributesBuilder: SplitAttributes.Builder = SplitAttributes.Builder()
        .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
        .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
    
    if (WindowSdkExtensions.getInstance().extensionVersion >= 6) {
        splitAttributesBuilder.setDividerAttributes(
            DividerAttributes.DraggableDividerAttributes.Builder()
                .setColor(getColor(R.color.divider_color))
                .setWidthDp(4)
                .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT)
                .build()
        )
    }
    val splitAttributes: SplitAttributes = splitAttributesBuilder.build()

    Java

    SplitAttributes.Builder splitAttributesBuilder = new SplitAttributes.Builder()
        .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
        .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT);
    
    if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) {
        splitAttributesBuilder.setDividerAttributes(
          new DividerAttributes.DraggableDividerAttributes.Builder()
            .setColor(ContextCompat.getColor(this, R.color.divider_color))
            .setWidthDp(4)
            .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT)
            .build()
        );
    }
    SplitAttributes _splitAttributes = splitAttributesBuilder.build();

ऐक्टिविटी स्टैक को पिन करना

ऐक्टिविटी स्टैक पिन करने की सुविधा की मदद से, उपयोगकर्ता स्प्लिट की गई किसी एक विंडो को पिन कर सकते हैं. इससे, ऐक्टिविटी उसी तरह बनी रहती है जिस तरह वह पहले थी. साथ ही, उपयोगकर्ता दूसरी विंडो में नेविगेट कर पाते हैं. ऐक्टिविटी स्टैक पिन करने की सुविधा से, एक साथ कई काम करने का बेहतर अनुभव मिलता है.

अपने ऐप्लिकेशन में ऐक्टिविटी स्टैक पिन करने की सुविधा चालू करने के लिए, यह तरीका अपनाएं:

  1. आपको जिस गतिविधि को पिन करना है उसकी लेआउट फ़ाइल में एक बटन जोड़ें. उदाहरण के लिए, सूची-जानकारी वाले लेआउट की जानकारी वाली गतिविधि:

    <androidx.constraintlayout.widget.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/detailActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/white"
     tools:context=".DetailActivity">
    
    <TextView
       android:id="@+id/textViewItemDetail"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textSize="36sp"
       android:textColor="@color/obsidian"
       app:layout_constraintBottom_toTopOf="@id/pinButton"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />
    
    <androidx.appcompat.widget.AppCompatButton
       android:id="@+id/pinButton"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/pin_this_activity"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@id/textViewItemDetail"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
  2. ऐक्टिविटी के onCreate() तरीके में, बटन पर onclick लिसनर सेट करें:

    Kotlin

    val pinButton: Button = findViewById(R.id.pinButton)
    pinButton.setOnClickListener {
        val splitAttributes: SplitAttributes = SplitAttributes.Builder()
            .setSplitType(SplitAttributes.SplitType.ratio(0.66f))
            .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
            .build()
    
        val pinSplitRule = SplitPinRule.Builder()
            .setSticky(true)
            .setDefaultSplitAttributes(splitAttributes)
            .build()
    
        SplitController.getInstance(applicationContext)
            .pinTopActivityStack(taskId, pinSplitRule)
    }

    Java

    Button pinButton = findViewById(R.id.pinButton);
    pinButton.setOnClickListener( (view) -> {
        SplitAttributes splitAttributes = new SplitAttributes.Builder()
            .setSplitType(SplitAttributes.SplitType.ratio(0.66f))
            .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
            .build();
    
        SplitPinRule pinSplitRule = new SplitPinRule.Builder()
            .setSticky(true)
            .setDefaultSplitAttributes(splitAttributes)
            .build();
    
        SplitController.getInstance(getApplicationContext())
            .pinTopActivityStack(getTaskId(), pinSplitRule);
    });

डायलॉग फ़ुल-स्क्रीन डिम

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

WindowManager 1.4 और इसके बाद के वर्शन में, डायलॉग बॉक्स खुलने पर पूरी ऐप्लिकेशन विंडो डिफ़ॉल्ट रूप से धुंधली हो जाती है (EmbeddingConfiguration.DimAreaBehavior.ON_TASK देखें).

डायलॉग बॉक्स खोलने वाली गतिविधि के सिर्फ़ कंटेनर को धुंधला करने के लिए, EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK का इस्तेमाल करें.

स्प्लिट की गई विंडो से किसी गतिविधि को फ़ुल विंडो में ले जाना

एक नया कॉन्फ़िगरेशन बनाएं, जो साइड ऐक्टिविटी को पूरी विंडो में दिखाता हो. इसके बाद, ऐक्टिविटी को ऐसे इंटेंट के साथ फिर से लॉन्च करें जो उसी इंस्टेंस पर ले जाता हो.

देखें कि स्प्लिटिंग की सुविधा रनटाइम के दौरान काम करती है या नहीं

ऐक्टिविटी एम्बेड करने की सुविधा, Android 12L (एपीआई लेवल 32) और इसके बाद के वर्शन पर काम करती है. हालांकि, यह सुविधा प्लैटफ़ॉर्म के पुराने वर्शन वाले कुछ डिवाइसों पर भी उपलब्ध है. रनटाइम पर सुविधा की उपलब्धता की जांच करने के लिए, SplitController.splitSupportStatus प्रॉपर्टी या SplitController.getSplitSupportStatus() तरीके का इस्तेमाल करें:

Kotlin

if (SplitController.getInstance(this).splitSupportStatus ==
    SplitController.SplitSupportStatus.SPLIT_AVAILABLE
) {
    // Device supports split activity features.
}

Java

if (SplitController.getInstance(this).getSplitSupportStatus() ==
    SplitController.SplitSupportStatus.SPLIT_AVAILABLE) {
    // Device supports split activity features.
}

अगर स्प्लिट स्क्रीन की सुविधा काम नहीं करती है, तो गतिविधियां, गतिविधि स्टैक के सबसे ऊपर लॉन्च की जाती हैं. ऐसा गतिविधि एम्बेड करने के मॉडल के हिसाब से किया जाता है.

सिस्टम ओवरराइड को रोकना

Android डिवाइस बनाने वाली कंपनियां (ओरिजनल इक्विपमेंट मैन्युफ़ैक्चरर या ओईएम), डिवाइस सिस्टम के फ़ंक्शन के तौर पर गतिविधि एम्बेड करने की सुविधा लागू कर सकती हैं. सिस्टम, एक साथ कई गतिविधियां करने वाले ऐप्लिकेशन के लिए स्प्लिट करने के नियम तय करता है. इससे, ऐप्लिकेशन के विंडो में दिखने के तरीके को बदला जा सकता है. सिस्टम ओवरराइड की वजह से, एक साथ कई गतिविधियां करने वाले ऐप्लिकेशन, सिस्टम के तय किए गए गतिविधि एम्बेडिंग मोड में चले जाते हैं.

सिस्टम ऐक्टिविटी एम्बेड करने की सुविधा से, ऐप्लिकेशन के प्रज़ेंटेशन को बेहतर बनाया जा सकता है. इसके लिए, मल्टी-पैन लेआउट का इस्तेमाल किया जा सकता है. जैसे, सूची-जानकारी. इसके लिए, ऐप्लिकेशन में कोई बदलाव करने की ज़रूरत नहीं होती. हालांकि, सिस्टम की ऐक्टिविटी एम्बेड करने की सुविधा से, ऐप्लिकेशन के लेआउट गलत हो सकते हैं, बग आ सकते हैं या ऐप्लिकेशन की ओर से लागू की गई ऐक्टिविटी एम्बेड करने की सुविधा के साथ टकराव हो सकता है.

आपका ऐप्लिकेशन, सिस्टम गतिविधि को एम्बेड करने से रोक सकता है या इसकी अनुमति दे सकता है. इसके लिए, ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE सेट करें. उदाहरण के लिए:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <property
            android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
            android:value="true|false" />
    </application>
</manifest>

प्रॉपर्टी का नाम, Jetpack WindowManager WindowProperties ऑब्जेक्ट में तय किया जाता है. अगर आपका ऐप्लिकेशन, गतिविधि एम्बेड करने की सुविधा लागू करता है या आपको सिस्टम को अपने ऐप्लिकेशन पर गतिविधि एम्बेड करने के नियमों को लागू करने से रोकना है, तो वैल्यू को false पर सेट करें. सिस्टम को अपने ऐप्लिकेशन पर सिस्टम के तय किए गए गतिविधि एम्बेड करने के नियमों को लागू करने की अनुमति देने के लिए, वैल्यू को true पर सेट करें.

सीमाएं, पाबंदियां, और चेतावनियां

  • सिर्फ़ टास्क का होस्ट ऐप्लिकेशन, टास्क में अन्य गतिविधियों को व्यवस्थित और एम्बेड कर सकता है. टास्क में रूट गतिविधि के मालिक के तौर पर इसकी पहचान की जाती है. अगर एम्बेड करने और स्प्लिट करने की सुविधा के साथ काम करने वाली गतिविधियाँ, किसी ऐसे टास्क में चलती हैं जो किसी दूसरे ऐप्लिकेशन से जुड़ा है, तो उन गतिविधियों के लिए एम्बेड करने और स्प्लिट करने की सुविधा काम नहीं करेगी.
  • गतिविधियों को सिर्फ़ एक टास्क में व्यवस्थित किया जा सकता है. किसी गतिविधि को नए टास्क में लॉन्च करने पर, वह हमेशा किसी भी मौजूदा स्प्लिट के बाहर, बड़ी की गई नई विंडो में खुलती है.
  • एक ही प्रोसेस में मौजूद गतिविधियों को व्यवस्थित किया जा सकता है और उन्हें स्प्लिट किया जा सकता है. SplitInfo कॉलबैक सिर्फ़ एक ही प्रोसेस से जुड़ी गतिविधियों की जानकारी देता है, क्योंकि अलग-अलग प्रोसेस में होने वाली गतिविधियों के बारे में जानने का कोई तरीका नहीं है.
  • हर जोड़ी या एक गतिविधि से जुड़ा नियम, सिर्फ़ उन गतिविधियों पर लागू होता है जिन्हें नियम रजिस्टर होने के बाद लॉन्च किया जाता है. फ़िलहाल, मौजूदा स्प्लिट या उनकी विज़ुअल प्रॉपर्टी को अपडेट करने का कोई तरीका नहीं है.
  • स्प्लिट पेयर फ़िल्टर का कॉन्फ़िगरेशन, गतिविधियों को पूरी तरह से लॉन्च करते समय इस्तेमाल किए गए इंटेंट से मेल खाना चाहिए. मैचिंग तब होती है, जब ऐप्लिकेशन प्रोसेस से कोई नई गतिविधि शुरू की जाती है. इसलिए, हो सकता है कि इसे उन कॉम्पोनेंट के नामों के बारे में पता न हो जिन्हें सिस्टम प्रोसेस में बाद में हल किया जाता है. ऐसा इंप्लिसिट इंटेंट का इस्तेमाल करते समय होता है. अगर लॉन्च के समय किसी कॉम्पोनेंट का नाम नहीं पता है, तो वाइल्डकार्ड ("*/*") का इस्तेमाल किया जा सकता है. साथ ही, इंटेंट ऐक्शन के आधार पर फ़िल्टर किया जा सकता है.
  • फ़िलहाल, कंटेनर के बीच गतिविधियों को ट्रांसफ़र करने का कोई तरीका उपलब्ध नहीं है. साथ ही, स्प्लिट बनाने के बाद, उन्हें स्प्लिट में शामिल या उससे हटाने का भी कोई तरीका उपलब्ध नहीं है. स्प्लिट सिर्फ़ तब बनाए जाते हैं, जब WindowManager लाइब्रेरी में मैचिंग नियमों वाली नई गतिविधियां लॉन्च की जाती हैं. साथ ही, स्प्लिट तब बंद हो जाते हैं, जब स्प्लिट कंटेनर में आखिरी गतिविधि खत्म हो जाती है.
  • कॉन्फ़िगरेशन में बदलाव होने पर, गतिविधियों को फिर से लॉन्च किया जा सकता है. इसलिए, जब स्प्लिट बनाया जाता है या हटाया जाता है और गतिविधि की सीमाएं बदलती हैं, तो गतिविधि के पिछले इंस्टेंस को पूरी तरह से खत्म किया जा सकता है और नया इंस्टेंस बनाया जा सकता है. इसलिए, ऐप्लिकेशन डेवलपर को लाइफ़साइकल कॉलबैक से नई गतिविधियां लॉन्च करते समय सावधानी बरतनी चाहिए.
  • डिवाइसों में विंडो एक्सटेंशन इंटरफ़ेस होना चाहिए, ताकि गतिविधि एम्बेड करने की सुविधा काम कर सके. Android 12L (एपीआई लेवल 32) या इसके बाद के वर्शन पर काम करने वाले लगभग सभी बड़ी स्क्रीन वाले डिवाइसों में यह इंटरफ़ेस शामिल होता है. हालांकि, कुछ बड़ी स्क्रीन वाले डिवाइसों में विंडो एक्सटेंशन इंटरफ़ेस शामिल नहीं होता है. ऐसा इसलिए, क्योंकि इन डिवाइसों पर एक साथ कई ऐक्टिविटी नहीं की जा सकतीं. अगर बड़ी स्क्रीन वाले डिवाइस पर मल्टी-विंडो मोड काम नहीं करता है, तो हो सकता है कि उस पर गतिविधि एम्बेड करने की सुविधा भी काम न करे.

अन्य संसाधन