पिक्चर में पिक्चर (पीआईपी) Jetpack लाइब्रेरी, Android ऐप्लिकेशन डेवलपर के लिए पीआईपी की सुविधा लागू करने का आसान और मज़बूत तरीका है. खास तौर पर, मीडिया प्लेबैक, वीडियो कॉल, और नेविगेशन ऐप्लिकेशन के लिए. यह लाइब्रेरी, एक ही एपीआई उपलब्ध कराती है. इससे बॉयलरप्लेट कोड और ऐप्लिकेशन में होने वाली आम गड़बड़ियां कम होती हैं. साथ ही, पीआईपी के उपयोगकर्ता अनुभव की क्वालिटी बेहतर होती है.
पीआईपी Jetpack लाइब्रेरी, मौजूदा पीआईपी एपीआई को बेहतर बनाती है. इसके लिए, यह Android इकोसिस्टम में आने वाली कई अहम चुनौतियों और गड़बड़ियों को ठीक करती है:
- ओएस फ़्रैगमेंटेशन: यह लाइब्रेरी, अलग-अलग Android वर्शन में पीआईपी एपीआई
कॉल के अंतर को अपने-आप मैनेज करती है. जैसे, Android 12 से पहले
enterPictureInPictureModeऔर इसके बादisAutoEnterEnabledका इस्तेमाल करना. इसलिए, डेवलपर को वर्शन के अंतर को मैनेज करने की ज़रूरत नहीं होती. - पीआईपी के गलत पैरामीटर: यह लाइब्रेरी, पीआईपी के पैरामीटर को सही तरीके से सेट करने के लिए एक ही तरीका उपलब्ध कराती है. जैसे, मीडिया प्लेबैक के दौरान, बेहतर क्वालिटी वाले ऐनिमेशन बनाने के लिए
setSourceRectHintका इस्तेमाल करना. - पीआईपी की स्थिति के लिए एक ही कॉलबैक: यह लाइब्रेरी, स्थिति और यूज़र इंटरफ़ेस (यूआई) को आसानी से मैनेज करने के लिए,
onPictureInPictureModeChangedऔरonPictureInPictureUiStateChangedको एक ही कॉलबैक इंटरफ़ेस (PictureInPictureDelegate.OnPictureInPictureEventListener) में जोड़ती है. - बॉयलरप्लेट कोड कम करना: यह लाइब्रेरी, आम तौर पर इस्तेमाल होने वाले मामलों के लिए,
RemoteActionsके पहले से तय सेट उपलब्ध कराती है. जैसे, प्लेबैक कंट्रोल और वीडियो कॉल की कार्रवाइयां. इससे, बार-बार इस्तेमाल होने वाले बॉयलरप्लेट कोड की मात्रा कम होती है. - आने वाले समय के लिए तैयारी: पीआईपी की अन्य सुविधाएं, Jetpack लाइब्रेरी के ज़रिए उपलब्ध कराई जाती हैं. इससे, इन्हें अपनाने वाले लोग, कम से कम या बिना किसी मेहनत के अतिरिक्त सुविधाओं का ऐक्सेस पा सकते हैं.
माइग्रेशन का वर्कफ़्लो
ऐप्लिकेशन के इस्तेमाल के उदाहरण की कैटगरी और पुराने पीआईपी लॉजिक की पहचान करें:
कैटगरी: वीडियो प्लेबैक, नेविगेशन या वीडियो कॉल.
पुराना पीआईपी लॉजिक जिसकी पहचान करनी है:
onUserLeaveHintsetAutoEnterEnabledonPictureInPictureModeChangedonPictureInPictureUiStateChangedsetPictureInPictureParams.
2. AndroidManifest कॉन्फ़िगरेशन
पक्का करें कि पीआईपी में जाने वाली ऐक्टिविटी, AndroidManifest.xml में ज़रूरी configChanges के साथ, पीआईपी की सुविधा के लिए सहमति का एलान करे. इससे, ऐप्लिकेशन को बार-बार रीस्टार्ट करने की ज़रूरत नहीं पड़ेगी:
<activity
android:name="VideoActivity" android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
</activity>
3. एनवायरमेंट सेट अप करना
build.gradle में ज़रूरी डिपेंडेंसी जोड़ें:
dependencies {
implementation("androidx.core:core:1.18.0")
implementation("androidx.activity:activity:1.13.0")
implementation("androidx.core:core-pip:1.0.0-alpha02") }
डिपेंडेंसी के लिए, AndroidX की नई लाइब्रेरी इस्तेमाल करें. साथ ही, इस बारे में जानकारी पाने के लिए, रिलीज़ पेज देखें.
4. टेंप्लेट चुनना और उसे शुरू करना
ऐप्लिकेशन के इस्तेमाल के उदाहरण के हिसाब से, लागू करने का सबसे सही टेंप्लेट चुनें:
- नेविगेशन और वीडियो कॉल:
BasicPictureInPicture; आम तौर पर, साइज़ बदलने की सुविधा काम नहीं करती . साथ ही, आपको सोर्स रेक्ट हिंट की ज़रूरत नहीं होती. - वीडियो प्लेबैक:
VideoPlaybackPictureInPicture; सोर्स रेक्ट हिंट के लिए, प्लेयर व्यू की सीमाओं को अपने-आप ट्रैक करता है. साथ ही, डिफ़ॉल्ट रूप से, साइज़ बदलने की सुविधा चालू करता है.
Jetpack लाइब्रेरी को अपनाने के लिए, पीआईपी को लागू करने के मौजूदा कस्टम तरीके को Jetpack लाइब्रेरी के एपीआई से बदलें. इसे अपनाने में लगने वाली मुश्किल और लागत, ऐप्लिकेशन के मौजूदा तरीके के हिसाब से अलग-अलग होगी.
यहां पीआईपी के इस्तेमाल के कुछ आम उदाहरण और इसे लागू करने के ज़रूरी चरणों के बारे में बताया गया है:
नेविगेशन
ऐप्लिकेशन, लाइब्रेरी को नेविगेशन की चालू या बंद स्थिति के बारे में बताता है. साथ ही, आसपेक्ट रेशियो सेट करता है. बाकी काम Jetpack लाइब्रेरी करती है.
मुख्य अंतर:
- ऐप्लिकेशन की ओर से, ऑटो-एंटर और लेगसी-एंटर के बीच अंतर करने की ज़रूरत नहीं है.
- कॉलबैक इंटरफ़ेस को एक साथ इस्तेमाल किया जा सकता है.
- पिछले वर्शन के साथ काम करने की सुविधा के लिए, नया
PictureInPictureParamsबिल्डर.
वीडियो कॉल
ऐप्लिकेशन, लाइब्रेरी को कॉल की चालू या बंद स्थिति के बारे में बताता है. साथ ही, आसपेक्ट रेशियो सेट करता है.
मुख्य अंतर:
- ऐप्लिकेशन की ओर से, ऑटो-एंटर और लेगसी-एंटर के बीच अंतर करने की ज़रूरत नहीं है.
- कॉलबैक इंटरफ़ेस को एक साथ इस्तेमाल किया जा सकता है.
- पिछले वर्शन के साथ काम करने की सुविधा के लिए, नया
PictureInPictureParamsबिल्डर. - वीडियो कॉल के लिए, कार्रवाई के आइकॉन को स्टैंडर्ड बनाया गया है.
5. कोड माइग्रेट करना
- एंट्री लॉजिक: एपीआई के हिसाब से तय लॉजिक को बदलें. जैसे,
setAutoEnterEnabledAndroid 12 और इसके बाद के वर्शन के लिए या Android 11 और इससे पहले के वर्शन के लिए कोsetEnabledसे बदलें.onUserLeaveHintपीआईपी की सुविधा के लिए ज़रूरी शर्तें पूरी होने की स्थिति में बदलाव होने पर, इसे ट्रिगर करें. - कॉलबैक:
onPictureInPictureModeChanged(लेआउट टॉगल करना) औरonPictureInPictureUiStateChanged(ऐनिमेशन/स्थितियां) को एक ही इवेंट-आधारित कॉलबैकonPictureInPictureEventमें जोड़ें. - कार्रवाइयां और पैरामीटर: टेंप्लेट इंस्टेंस पर
setActionsऔरsetAspectRatioका इस्तेमाल करके, पैरामीटर में बदलाव होने पर उन्हें अपडेट करें.
रेफ़रंस के तौर पर लागू करने के पैटर्न
लागू करने के उदाहरण.
नेविगेशन और वीडियो कॉल
class NavOrVideoCallJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener { private lateinit var pictureInPictureImpl: BasicPictureInPicture override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) pictureInPictureImpl = BasicPictureInPicture(this) // BasicPictureInPicture is ideal for Navigation and Video call use cases. pictureInPictureImpl.addOnPictureInPictureEventListener( ContextCompat.getMainExecutor(this), this ) setContent { } } override fun onPictureInPictureEvent( event: PictureInPictureDelegate.Event, config: Configuration? ) { when (event) { PictureInPictureDelegate.Event.ENTERED -> { /* Toggle to PiP layout */ } PictureInPictureDelegate.Event.EXITED -> { /* Toggle to Full-screen layout */ } PictureInPictureDelegate.Event.STASHED -> { /* Optional: PiP is stashed */ } PictureInPictureDelegate.Event.UNSTASHED -> { /* Optional: PiP is unstashed */ } } } }
वीडियो प्लेबैक
class VideoPlaybackJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener { private lateinit var pictureInPictureImpl: VideoPlaybackPictureInPicture override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) pictureInPictureImpl = VideoPlaybackPictureInPicture(this) pictureInPictureImpl.addOnPictureInPictureEventListener( ContextCompat.getMainExecutor(this), this ) setContent { ContentScreen(pictureInPictureImpl) } } override fun onPictureInPictureEvent( event: PictureInPictureDelegate.Event, config: Configuration? ) { when (event) { PictureInPictureDelegate.Event.ENTER_ANIMATION_START -> { /* Hide overlays */ } PictureInPictureDelegate.Event.ENTER_ANIMATION_END -> { /* Animation finished */ } PictureInPictureDelegate.Event.ENTERED -> { /* Switch to PiP layout */ } PictureInPictureDelegate.Event.STASHED -> { /* PiP stashed */ } PictureInPictureDelegate.Event.UNSTASHED -> { /* PiP unstashed */ } PictureInPictureDelegate.Event.EXITED -> { /* Return to full-screen */ } } } @Composable fun ContentScreen(pipController: VideoPlaybackPictureInPicture) { DisposableEffect(pipController) { onDispose { pipController.close() } } } }