ऐप्लिकेशन स्क्रीन पर न होने पर भी, बैकग्राउंड में मीडिया चलाया जा सकता है. उदाहरण के लिए, जब उपयोगकर्ता दूसरे ऐप्लिकेशन इस्तेमाल कर रहा हो.
इसके लिए, MediaPlayer को MediaBrowserServiceCompat सेवा में एम्बेड किया जाता है. साथ ही, इसे दूसरी गतिविधि में मौजूद MediaBrowserCompat के साथ इंटरैक्ट करने के लिए सेट किया जाता है.
क्लाइंट और सर्वर के इस सेटअप को लागू करते समय सावधानी बरतें. बैकग्राउंड सेवा में चल रहे प्लेयर के, सिस्टम के बाकी हिस्सों के साथ इंटरैक्ट करने के तरीके के बारे में कुछ उम्मीदें हैं. अगर आपका ऐप्लिकेशन इन उम्मीदों को पूरा नहीं करता है, तो उपयोगकर्ता को खराब अनुभव मिल सकता है. ज़्यादा जानकारी के लिए, ऑडियो ऐप्लिकेशन बनाना लेख पढ़ें.
इस पेज पर, MediaPlayer को मैनेज करने के लिए खास निर्देश दिए गए हैं. ये निर्देश तब लागू होते हैं, जब MediaPlayer को किसी सेवा में लागू किया जाता है.
एसिंक्रोनस तरीके से चलाना
Activity की तरह, Service में सारा काम डिफ़ॉल्ट रूप से एक ही थ्रेड में किया जाता है. दरअसल, जब किसी ऐप्लिकेशन से कोई गतिविधि और सेवा चलाई जाती है, तो वे डिफ़ॉल्ट रूप से एक ही थ्रेड ("मुख्य थ्रेड") का इस्तेमाल करती हैं.
सेवाओं को, आने वाले इंटेंट को तुरंत प्रोसेस करना चाहिए. साथ ही, उनका जवाब देते समय कभी भी लंबी गणनाएं नहीं करनी चाहिए. आपको कोई भी मुश्किल काम या ब्लॉकिंग कॉल एसिंक्रोनस तरीके से करना होगा. इसके लिए, या तो आपको खुद से लागू की गई किसी दूसरी थ्रेड का इस्तेमाल करना होगा या एसिंक्रोनस प्रोसेसिंग के लिए फ़्रेमवर्क की कई सुविधाओं का इस्तेमाल करना होगा.
उदाहरण के लिए, अगर आपको अपनी मुख्य थ्रेड से MediaPlayer का इस्तेमाल करना है, तो आपको:
prepare()के बजायprepareAsync()को कॉल करें. साथ ही,- तैयारी पूरी होने पर सूचना पाने के लिए,
MediaPlayer.OnPreparedListenerलागू करें, ताकि आपको गेम खेलने की सुविधा शुरू होने की सूचना मिल सके.
उदाहरण के लिए:
Kotlin
private const val ACTION_PLAY: String = "com.example.action.PLAY"
class MyService: Service(), MediaPlayer.OnPreparedListener {
private var mMediaPlayer: MediaPlayer? = null
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
...
val action: String = intent.action
when(action) {
ACTION_PLAY -> {
mMediaPlayer = ... // initialize it here
mMediaPlayer?.apply {
setOnPreparedListener(this@MyService)
prepareAsync() // prepare async to not block main thread
}
}
}
...
}
/** Called when MediaPlayer is ready */
override fun onPrepared(mediaPlayer: MediaPlayer) {
mediaPlayer.start()
}
}
Java
public class MyService extends Service implements MediaPlayer.OnPreparedListener {
private static final String ACTION_PLAY = "com.example.action.PLAY";
MediaPlayer mediaPlayer = null;
public int onStartCommand(Intent intent, int flags, int startId) {
...
if (intent.getAction().equals(ACTION_PLAY)) {
mediaPlayer = ... // initialize it here
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.prepareAsync(); // prepare async to not block main thread
}
}
/** Called when MediaPlayer is ready */
public void onPrepared(MediaPlayer player) {
player.start();
}
}
एसिंक्रोनस गड़बड़ियों को ठीक करना
सिंक करने वाले ऑपरेशन में, गड़बड़ियों के बारे में अपवाद या गड़बड़ी कोड से सूचना दी जाती है. हालांकि, असिंक्रोनस संसाधनों का इस्तेमाल करते समय, आपको अपने ऐप्लिकेशन को गड़बड़ियों के बारे में सही तरीके से सूचना देनी चाहिए. MediaPlayer के मामले में, आपको MediaPlayer.OnErrorListener लागू करना होगा और इसे अपने MediaPlayer इंस्टेंस में सेट करना होगा:
Kotlin
class MyService : Service(), MediaPlayer.OnErrorListener {
private var mediaPlayer: MediaPlayer? = null
fun initMediaPlayer() {
// ...initialize the MediaPlayer here...
mediaPlayer?.setOnErrorListener(this)
}
override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
// ... react appropriately ...
// The MediaPlayer has moved to the Error state, must be reset!
}
}
Java
public class MyService extends Service implements MediaPlayer.OnErrorListener {
MediaPlayer mediaPlayer;
public void initMediaPlayer() {
// ...initialize the MediaPlayer here...
mediaPlayer.setOnErrorListener(this);
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// ... react appropriately ...
// The MediaPlayer has moved to the Error state, must be reset!
}
}
गड़बड़ी होने पर, MediaPlayer गड़बड़ी की स्थिति में चला जाता है. इसे फिर से इस्तेमाल करने से पहले, आपको इसे रीसेट करना होगा. ज़्यादा जानकारी के लिए, MediaPlayer क्लास का पूरा स्टेट डायग्राम देखें.
वेक लॉक इस्तेमाल करना
बैकग्राउंड में संगीत चलाने या स्ट्रीम करने के दौरान, आपको वेक लॉक का इस्तेमाल करना होगा. इससे सिस्टम को संगीत चलाने में रुकावट डालने से रोका जा सकेगा. उदाहरण के लिए, डिवाइस को स्लीप मोड में जाने से रोका जा सकेगा.
वेक लॉक, सिस्टम को यह सिग्नल देता है कि आपका ऐप्लिकेशन ऐसी सुविधाओं का इस्तेमाल कर रहा है जो फ़ोन के इस्तेमाल में न होने पर भी उपलब्ध रहनी चाहिए.
यह पक्का करने के लिए कि MediaPlayer के चलने के दौरान सीपीयू काम करता रहे, MediaPlayer को शुरू करते समय setWakeMode() तरीके को कॉल करें. MediaPlayer, वीडियो चलाने के दौरान लॉक को होल्ड करता है. वीडियो रोकने या बंद करने पर, लॉक को रिलीज़ कर देता है:
Kotlin
mediaPlayer = MediaPlayer().apply {
// ... other initialization here ...
setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}
Java
mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
हालांकि, इस उदाहरण में हासिल किया गया वेक लॉक सिर्फ़ यह पक्का करता है कि सीपीयू चालू रहे. अगर नेटवर्क पर मीडिया स्ट्रीम किया जा रहा है और वाई-फ़ाई का इस्तेमाल किया जा रहा है, तो आपको WifiLock को भी होल्ड करना होगा. इसे आपको मैन्युअल तरीके से हासिल करना होगा और रिलीज़ करना होगा. इसलिए, रिमोट यूआरएल के साथ MediaPlayer तैयार करते समय, आपको वाई-फ़ाई लॉक बनाना और उसे हासिल करना चाहिए.
उदाहरण के लिए:
Kotlin
val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")
wifiLock.acquire()
Java
WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
wifiLock.acquire();
मीडिया को रोकने या बंद करने पर या जब आपको नेटवर्क की ज़रूरत न हो, तो आपको लॉक हटाना चाहिए:
Kotlin
wifiLock.release()
Java
wifiLock.release();
सफ़ाई करना
जैसा कि हमने पहले बताया था, MediaPlayer ऑब्जेक्ट, सिस्टम के काफ़ी संसाधनों का इस्तेमाल कर सकता है. इसलिए, आपको इसे सिर्फ़ तब तक रखना चाहिए, जब तक इसकी ज़रूरत हो. साथ ही, जब इसका इस्तेमाल पूरा हो जाए, तब release() को कॉल करें. सिस्टम के गार्बेज कलेक्शन पर भरोसा करने के बजाय, इस क्लीनअप तरीके को साफ़ तौर पर कॉल करना ज़रूरी है. ऐसा इसलिए, क्योंकि गार्बेज कलेक्टर को MediaPlayer को वापस पाने में कुछ समय लग सकता है. ऐसा इसलिए, क्योंकि यह सिर्फ़ मेमोरी की ज़रूरतों के हिसाब से काम करता है. साथ ही, यह मीडिया से जुड़े अन्य संसाधनों की कमी के बारे में नहीं जानता. इसलिए, किसी सेवा का इस्तेमाल करते समय, आपको हमेशा onDestroy() तरीके को बदलना चाहिए. इससे यह पक्का किया जा सकेगा कि MediaPlayer को रिलीज़ किया जा रहा है:
Kotlin
class MyService : Service() {
private var mediaPlayer: MediaPlayer? = null
// ...
override fun onDestroy() {
super.onDestroy()
mediaPlayer?.release()
}
}
Java
public class MyService extends Service {
MediaPlayer mediaPlayer;
// ...
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) mediaPlayer.release();
}
}
आपको MediaPlayer को बंद करने के अलावा, इसे रिलीज़ करने के अन्य मौके भी ढूंढने चाहिए. उदाहरण के लिए, अगर आपको लगता है कि लंबे समय तक मीडिया नहीं चलाया जा सकेगा (जैसे, ऑडियो फ़ोकस खो जाने के बाद), तो आपको मौजूदा MediaPlayer को रिलीज़ कर देना चाहिए और बाद में इसे फिर से बनाना चाहिए. दूसरी ओर, अगर आपको सिर्फ़ कुछ समय के लिए मीडिया चलाना बंद करना है, तो आपको MediaPlayer को बनाए रखना चाहिए, ताकि इसे फिर से बनाने और तैयार करने में लगने वाले समय से बचा जा सके.
ज़्यादा जानें
आपके ऐप्लिकेशन में मीडिया चलाने के लिए, Jetpack Media3 का इस्तेमाल करने का सुझाव दिया जाता है. इसके बारे में ज़्यादा जानें.
इन पेजों पर, ऑडियो और वीडियो रिकॉर्ड करने, सेव करने, और चलाने से जुड़े विषयों के बारे में जानकारी दी गई है: