डिपेंडेंसी जोड़ना
Media3 लाइब्रेरी में, Jetpack Compose पर आधारित यूज़र इंटरफ़ेस (यूआई) मॉड्यूल शामिल है. इसका इस्तेमाल करने के लिए, यहां दी गई डिपेंडेंसी जोड़ें:
Kotlin
implementation("androidx.media3:media3-ui-compose:1.6.0")
Groovy
implementation "androidx.media3:media3-ui-compose:1.6.0"
हमारा सुझाव है कि आप अपना ऐप्लिकेशन, Compose के साथ डेवलप करें या व्यू का इस्तेमाल करने से माइग्रेट करें.
डेमो ऐप्लिकेशन को पूरी तरह से कंपोज करना
media3-ui-compose
लाइब्रेरी में, पहले से तैयार कॉम्पोज़ेबल (जैसे, बटन, इंडिकेटर, इमेज या डायलॉग) शामिल नहीं होते. हालांकि, आपको ऐसा डेमो ऐप्लिकेशन मिल सकता है जिसे पूरी तरह से Compose में लिखा गया हो. यह ऐप्लिकेशन, AndroidView
में PlayerView
को रैप करने जैसे इंटरऑपरेबिलिटी (अलग-अलग सिस्टम के साथ काम करने की सुविधा) वाले किसी भी समाधान का इस्तेमाल नहीं करता. डेमो ऐप्लिकेशन, media3-ui-compose
मॉड्यूल की यूज़र इंटरफ़ेस (यूआई) स्टेट होल्डर क्लास का इस्तेमाल करता है. साथ ही, Compose Material3 लाइब्रेरी का भी इस्तेमाल करता है.
यूज़र इंटरफ़ेस (यूआई) स्टेट होल्डर
यूज़र इंटरफ़ेस (यूआई) स्टेट होल्डर के मुकाबले, कंपोज़ेबल के फ़्लेक्सिबिलिटी का इस्तेमाल कैसे किया जा सकता है, यह बेहतर तरीके से समझने के लिए, Compose में स्टेट को मैनेज करने का तरीका जानें.
बटन के स्टेट होल्डर
हम कुछ यूज़र इंटरफ़ेस (यूआई) स्टेटस के लिए यह मानते हैं कि उन्हें बटन जैसे Composables का इस्तेमाल करके दिखाया जाएगा.
राज्य | remember*State | टाइप |
---|---|---|
PlayPauseButtonState |
rememberPlayPauseButtonState |
2-टॉगल |
PreviousButtonState |
rememberPreviousButtonState |
कॉन्स्टेंट |
NextButtonState |
rememberNextButtonState |
कॉन्स्टेंट |
RepeatButtonState |
rememberRepeatButtonState |
3-टॉगल |
ShuffleButtonState |
rememberShuffleButtonState |
2-टॉगल |
PlaybackSpeedState |
rememberPlaybackSpeedState |
मेन्यू या N-टॉगल |
PlayPauseButtonState
के इस्तेमाल का उदाहरण:
@Composable
fun PlayPauseButton(player: Player, modifier: Modifier = Modifier) {
val state = rememberPlayPauseButtonState(player)
IconButton(onClick = state::onClick, modifier = modifier, enabled = state.isEnabled) {
Icon(
imageVector = if (state.showPlay) Icons.Default.PlayArrow else Icons.Default.Pause,
contentDescription =
if (state.showPlay) stringResource(R.string.playpause_button_play)
else stringResource(R.string.playpause_button_pause),
)
}
}
ध्यान दें कि state
में थीम से जुड़ी कोई जानकारी नहीं है. जैसे, वीडियो चलाने या रोकने के लिए इस्तेमाल किया जाने वाला आइकॉन. इसकी सिर्फ़ एक ज़िम्मेदारी है, Player
को यूज़र इंटरफ़ेस (यूआई) स्टेटस में बदलना.
इसके बाद, अपनी पसंद के लेआउट में बटनों को जोड़ा जा सकता है:
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
) {
PreviousButton(player)
PlayPauseButton(player)
NextButton(player)
}
विज़ुअल आउटपुट के स्टेट होल्डर
PresentationState
में यह जानकारी होती है कि PlayerSurface
में वीडियो आउटपुट कब दिखाया जा सकता है या उसे प्लेसहोल्डर यूज़र इंटरफ़ेस (यूआई) एलिमेंट से कब कवर किया जाना चाहिए.
val presentationState = rememberPresentationState(player)
val scaledModifier = Modifier.resize(ContentScale.Fit, presentationState.videoSizeDp)
Box(modifier) {
// Always leave PlayerSurface to be part of the Compose tree because it will be initialised in
// the process. If this composable is guarded by some condition, it might never become visible
// because the Player won't emit the relevant event, e.g. the first frame being ready.
PlayerSurface(
player = player,
surfaceType = SURFACE_TYPE_SURFACE_VIEW,
modifier = scaledModifier,
)
if (presentationState.coverSurface) {
// Cover the surface that is being prepared with a shutter
Box(Modifier.background(Color.Black))
}
यहां, presentationState.videoSizeDp
का इस्तेमाल करके, Surface को अपनी पसंद के आसपेक्ट रेशियो में स्केल किया जा सकता है. ज़्यादा जानकारी के लिए, ContentScale के दस्तावेज़ देखें. साथ ही, presentationState.coverSurface
का इस्तेमाल करके यह पता लगाया जा सकता है कि Surface को दिखाने का समय सही है या नहीं. इस मामले में, आपके पास सतह के ऊपर एक अपारदर्शी शटर लगाने का विकल्प होता है. यह शटर, सतह के तैयार होने पर हट जाएगा.
फ़्लो कहां हैं?
कई Android डेवलपर, यूज़र इंटरफ़ेस (यूआई) का डेटा इकट्ठा करने के लिए, Kotlin Flow
ऑब्जेक्ट का इस्तेमाल करते हैं. उदाहरण के लिए, हो सकता है कि आपको ऐसा Player.isPlaying
फ़्लो चाहिए हो जिसे लाइफ़साइकल के हिसाब से collect
किया जा सके. इसके अलावा, Player.eventsFlow
जैसा कुछ भी हो सकता है, ताकि आपको Flow<Player.Events>
मिल सके. इसे अपनी पसंद के मुताबिक filter
किया जा सकता है.
हालांकि, Player
यूज़र इंटरफ़ेस (यूआई) स्टेटस के लिए फ़्लो का इस्तेमाल करने में कुछ समस्याएं आती हैं. डेटा ट्रांसफ़र की असिंक्रोनस (एक साथ नहीं होने वाली) प्रकृति, एक मुख्य समस्या है. हम यह पक्का करना चाहते हैं कि Player.Event
और यूज़र इंटरफ़ेस (यूआई) के बीच, डेटा के इस्तेमाल में कम से कम देरी हो. साथ ही, ऐसे यूआई एलिमेंट न दिखाए जाएं जो Player
के साथ सिंक नहीं हैं.
अन्य बातों में ये शामिल हैं:
- सभी
Player.Events
वाला फ़्लो, एक ही ज़िम्मेदारी के सिद्धांत का पालन नहीं करेगा. हर उपभोक्ता को काम के इवेंट फ़िल्टर करने होंगे. - हर
Player.Event
के लिए फ़्लो बनाने के लिए, आपको हर यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए, उन्हेंcombine
के साथ जोड़ना होगा. Player.Event और यूज़र इंटरफ़ेस (यूआई) एलिमेंट में बदलाव के बीच, कई-से-कई मैपिंग होती है.combine
का इस्तेमाल करने पर, यूज़र इंटरफ़ेस (यूआई) की स्थिति गैर-कानूनी हो सकती है.
कस्टम यूज़र इंटरफ़ेस (यूआई) स्टेटस बनाना
अगर मौजूदा यूज़र इंटरफ़ेस (यूआई) की स्थितियां आपकी ज़रूरतों के मुताबिक नहीं हैं, तो कस्टम यूआई की स्थितियां जोड़ी जा सकती हैं. पैटर्न कॉपी करने के लिए, मौजूदा स्टेटस का सोर्स कोड देखें. यूज़र इंटरफ़ेस (यूआई) की सामान्य स्टेटस होल्डर क्लास ये काम करती है:
Player
को शामिल करता है.- कोरूटीन का इस्तेमाल करके,
Player
की सदस्यता लेता है. ज़्यादा जानकारी के लिए,Player.listen
देखें. - अपनी इंटरनल स्टेटस को अपडेट करके, किसी खास
Player.Events
का जवाब देता है. - कारोबार के लॉजिक से जुड़े ऐसे निर्देश स्वीकार करें जिन्हें सही
Player
अपडेट में बदला जाएगा. - यूज़र इंटरफ़ेस (यूआई) ट्री में कई जगहों पर बनाए जा सकते हैं. साथ ही, ये हमेशा प्लेयर की स्थिति को एक जैसा दिखाते रहेंगे.
- Compose
State
फ़ील्ड को एक्सपोज़ करता है. इन फ़ील्ड का इस्तेमाल, बदलावों के हिसाब से डाइनैमिक तरीके से जवाब देने के लिए, Composable से किया जा सकता है. - इसमें
remember*State
फ़ंक्शन होता है, जो कॉम्पोज़िशन के बीच के इंस्टेंस को याद रखता है.
पर्दे के पीछे क्या होता है:
class SomeButtonState(private val player: Player) {
var isEnabled by mutableStateOf(player.isCommandAvailable(Player.COMMAND_ACTION_A))
private set
var someField by mutableStateOf(someFieldDefault)
private set
fun onClick() {
player.actionA()
}
suspend fun observe() =
player.listen { events ->
if (
events.containsAny(
Player.EVENT_B_CHANGED,
Player.EVENT_C_CHANGED,
Player.EVENT_AVAILABLE_COMMANDS_CHANGED,
)
) {
someField = this.someField
isEnabled = this.isCommandAvailable(Player.COMMAND_ACTION_A)
}
}
}
अपने Player.Events
पर प्रतिक्रिया देने के लिए, Player.listen
का इस्तेमाल किया जा सकता है. यह एक suspend fun
है, जिसकी मदद से कोरयूटीन की दुनिया में जाया जा सकता है और Player.Events
को अनलिमिटेड तौर पर सुना जा सकता है. Media3 में यूज़र इंटरफ़ेस (यूआई) की अलग-अलग स्थितियों को लागू करने से, असली डेवलपर को Player.Events
के बारे में जानने की ज़रूरत नहीं पड़ती.