নির্ভরতা যোগ করুন
Media3 লাইব্রেরিতে একটি Jetpack Compose-ভিত্তিক UI মডিউল রয়েছে। এটি ব্যবহার করতে, নিম্নলিখিত নির্ভরতা যোগ করুন:
কোটলিন
implementation("androidx.media3:media3-ui-compose:1.8.0")
খাঁজকাটা
implementation "androidx.media3:media3-ui-compose:1.8.0"
আমরা আপনাকে কম্পোজ-ফার্স্ট পদ্ধতিতে আপনার অ্যাপটি তৈরি করতে অথবা ভিউ ব্যবহার থেকে মাইগ্রেট করতে উৎসাহিত করছি।
সম্পূর্ণরূপে রচনা ডেমো অ্যাপ
যদিও media3-ui-compose লাইব্রেরিতে আউট-অফ-দ্য-বক্স কম্পোজেবল (যেমন বোতাম, সূচক, ছবি বা ডায়ালগ) অন্তর্ভুক্ত নেই, আপনি সম্পূর্ণরূপে Compose-এ লেখা একটি ডেমো অ্যাপ খুঁজে পেতে পারেন যা AndroidView এ PlayerView মোড়ানোর মতো কোনও আন্তঃকার্যকারিতা সমাধান এড়ায়। ডেমো অ্যাপটি media3-ui-compose মডিউল থেকে UI state holder ক্লাস ব্যবহার করে এবং Compose Material3 লাইব্রেরি ব্যবহার করে।
UI স্টেট হোল্ডাররা
UI স্টেট হোল্ডার বনাম কম্পোজেবলের নমনীয়তা কীভাবে ব্যবহার করবেন তা আরও ভালোভাবে বুঝতে, Compose কীভাবে State পরিচালনা করে তা পড়ুন।
বোতাম স্টেট হোল্ডার
কিছু UI রাজ্যের জন্য, আমরা ধরে নিই যে সেগুলি সম্ভবত বোতাম-সদৃশ কম্পোজেবল দ্বারা গ্রাস করা হবে।
| রাজ্য | মনে রাখবেন*রাষ্ট্র | আদর্শ |
|---|---|---|
PlayPauseButtonState | rememberPlayPauseButtonState | 2-টগল করুন |
PreviousButtonState | rememberPreviousButtonState | ধ্রুবক |
NextButtonState | rememberNextButtonState | ধ্রুবক |
RepeatButtonState | rememberRepeatButtonState | 3-টগল করুন |
ShuffleButtonState | rememberShuffleButtonState | 2-টগল করুন |
PlaybackSpeedState | rememberPlaybackSpeedState | মেনু অথবা এন-টগল |
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 UI অবস্থায় রূপান্তর করা।
এরপর আপনি আপনার পছন্দের লেআউটের বোতামগুলো মিক্স অ্যান্ড ম্যাচ করতে পারেন:
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
) {
PreviousButton(player)
PlayPauseButton(player)
NextButton(player)
}
ভিজ্যুয়াল আউটপুট স্টেট হোল্ডার
PresentationState কখন PlayerSurface এ ভিডিও আউটপুট দেখানো যেতে পারে অথবা কখন প্লেসহোল্ডার UI উপাদান দ্বারা আচ্ছাদিত করা উচিত তার তথ্য ধারণ করে।
val presentationState = rememberPresentationState(player)
val scaledModifier = Modifier.resizeWithContentScale(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 ব্যবহার করে সারফেসকে কাঙ্ক্ষিত আকৃতির অনুপাতের সাথে স্কেল করতে পারি (আরও ধরণের জন্য ContentScale ডক্স দেখুন) এবং presentationState.coverSurface করে জানতে পারি কখন সারফেস দেখানোর সময় সঠিক নয়। এই ক্ষেত্রে, আপনি সারফেসের উপরে একটি অস্বচ্ছ শাটার স্থাপন করতে পারেন, যা সারফেস প্রস্তুত হয়ে গেলে অদৃশ্য হয়ে যাবে।
ফ্লোস কোথায়?
অনেক অ্যান্ড্রয়েড ডেভেলপারই Kotlin Flow অবজেক্ট ব্যবহার করে ক্রমবর্ধমান UI ডেটা সংগ্রহের সাথে পরিচিত। উদাহরণস্বরূপ, আপনি হয়তো Player.isPlaying ফ্লো খুঁজছেন যা আপনি জীবনচক্র-সচেতন পদ্ধতিতে collect করতে পারেন। অথবা Player.eventsFlow এর মতো কিছু যা আপনাকে Flow<Player.Events> প্রদান করবে যা আপনি আপনার ইচ্ছামত filter করতে পারবেন।
তবে, Player UI অবস্থার জন্য ফ্লো ব্যবহারের কিছু অসুবিধা রয়েছে। প্রধান উদ্বেগের বিষয় হল ডেটা ট্রান্সফারের অ্যাসিঙ্ক্রোনাস প্রকৃতি। আমরা Player.Event এবং UI দিকে এর ব্যবহারের মধ্যে যতটা সম্ভব কম ল্যাটেন্সি নিশ্চিত করতে চাই, Player এর সাথে সিঙ্কের বাইরে থাকা UI উপাদানগুলি দেখানো এড়িয়ে চলুন।
অন্যান্য বিষয়গুলির মধ্যে রয়েছে:
- সমস্ত
Player.Eventsসহ একটি প্রবাহ একটি একক দায়িত্ব নীতি মেনে চলবে না, প্রতিটি ভোক্তাকে প্রাসঙ্গিক ইভেন্টগুলি ফিল্টার করতে হবে। - প্রতিটি
Player.Eventএর জন্য একটি ফ্লো তৈরি করার জন্য আপনাকে প্রতিটি UI এলিমেন্টের জন্য (combineসহ) তাদের একত্রিত করতে হবে। একটি Player.Event এবং একটি UI এলিমেন্টের মধ্যে many-to-many ম্যাপিং পরিবর্তন হয়।combineব্যবহার করার ফলে UI সম্ভাব্য অবৈধ অবস্থায় চলে যেতে পারে।
কাস্টম UI অবস্থা তৈরি করুন
যদি বিদ্যমান UI স্টেটগুলি আপনার চাহিদা পূরণ না করে তবে আপনি কাস্টম UI স্টেটগুলি যোগ করতে পারেন। প্যাটার্নটি অনুলিপি করতে বিদ্যমান স্টেটের সোর্স কোডটি দেখুন। একটি সাধারণ UI স্টেট হোল্ডার ক্লাস নিম্নলিখিত কাজগুলি করে:
- একজন
Playerদলে নেয়। - কোরোটিন ব্যবহার করে
Playerসাবস্ক্রাইব করুন। আরও বিস্তারিত জানার জন্যPlayer.listenদেখুন। - নির্দিষ্ট
Player.Eventsএর অভ্যন্তরীণ অবস্থা আপডেট করে সাড়া দেয়। - ব্যবসায়িক-লজিক কমান্ড গ্রহণ করুন যা একটি উপযুক্ত
Playerআপডেটে রূপান্তরিত হবে। - UI ট্রি জুড়ে একাধিক জায়গায় তৈরি করা যেতে পারে এবং সর্বদা প্লেয়ারের অবস্থার একটি সামঞ্জস্যপূর্ণ দৃষ্টিভঙ্গি বজায় রাখবে।
- কম্পোজ
Stateক্ষেত্রগুলি প্রকাশ করে যা একটি কম্পোজেবল দ্বারা পরিবর্তনগুলিতে গতিশীলভাবে প্রতিক্রিয়া জানাতে ব্যবহার করা যেতে পারে। - কম্পোজিশনের মধ্যে উদাহরণ মনে রাখার জন্য একটি
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 যা আপনাকে coroutine জগতে প্রবেশ করতে এবং অনির্দিষ্টকালের জন্য Player.Events শুনতে দেয়। বিভিন্ন UI অবস্থার Media3 বাস্তবায়ন শেষ ডেভেলপারকে Player.Events সম্পর্কে শেখার বিষয়ে উদ্বিগ্ন না হতে সাহায্য করে।