صوت الخلفية في الروبوت مع ميدياسيسيونكومبات
Arabic (العربية/عربي) translation by Muhammad Hasrullah (you can also view the original English article)
أحد الاستخدامات الأكثر شعبية للأجهزة النقالة يلعب الصوت مرة أخرى من خلال تدفق الخدمات الصوتية التي تم تنزيلها أو أي عدد من مصادر الصوت الموسيقى. بينما هذا سمة مشتركة إلى حد ما، من الصعب أن تنفذ، مع الكثير من القطع المختلفة التي بحاجة إلى أن يبني بشكل صحيح من أجل إعطاء المستخدم الخاص بك الروبوت الكامل تجربة.
ستتعرف في هذا البرنامج التعليمي على MediaSessionCompat
من مكتبة دعم Android ، وكيف يمكن استخدامها لإنشاء خدمة صوت خلفية مناسبة للمستخدمين.
برنامج الإعداد
أول شيء سوف تحتاج إلى القيام به إدراج مكتبة دعم الروبوت في المشروع الخاص بك. يمكن أن يتم ذلك عن طريق إضافة السطر التالي إلى ملف build.gradle في الوحدة النمطية الخاصة بك تحت عقده التبعيات.
compile 'com.android.support:support-v13:24.2.1'
بعد أن كنت قد مزامن المشروع الخاص بك، قم بإنشاء فئة جافا جديدة. في هذا المثال ، سأتصل بالفئة BackgroundAudioService
. ستحتاج هذه الفئة إلى توسيع MediaBrowserServiceCompat
. سنقوم أيضًا بتنفيذ واجهات التالية: MediaPlayer.OnCompletionListener
و AudioManager.OnAudioFocusChangeListener
.
والآن بعد أن تم إنشاء تطبيق MediaBrowserServiceCompat
، فلنأخذ لحظة لتحديث AndroidManifest.xml قبل العودة إلى هذا الفصل الدراسي. في الجزء العلوي من الفئة، سوف تحتاج إلى طلب الإذن WAKE_LOCK
.
<uses-permission android:name="android.permission.WAKE_LOCK" />
المقبل ، داخل application
العقدة ، أعلن عن خدمتك الجديدة بما يلي intent-filter
العناصر. سيسمح ذلك لخدمتك باعتراض أزرار التحكم وأحداث سماعة الرأس وتصفح الوسائط للأجهزة ، مثل Android Auto (على الرغم من أننا لن نفعل أي شيء مع Android Auto لهذا البرنامج التعليمي ، إلا أن بعض الدعم الأساسي له ما زال مطلوبًا بواسطة MediaBrowserServiceCompat
).
<service android:name=".BackgroundAudioService"> <intent-filter> <action android:name="android.intent.action.MEDIA_BUTTON" /> <action android:name="android.media.AUDIO_BECOMING_NOISY" /> <action android:name="android.media.browse.MediaBrowserService" /> </intent-filter> </service>
وأخيرًا ، ستحتاج إلى إعلان استخدام MediaButtonReceive
r من مكتبة دعم Android. هذا سوف يسمح لك لاعتراض وسائل الإعلام عنصر تحكم زر التفاعلات والأحداث سماعة الرأس على أجهزة تشغيل كيتكات والإصدارات السابقة.
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver"> <intent-filter> <action android:name="android.intent.action.MEDIA_BUTTON" /> <action android:name="android.media.AUDIO_BECOMING_NOISY" /> </intent-filter> </receiver>
الآن وبعد أن الانتهاء من ملف AndroidManifest.xml الخاص بك، فيمكنك إغلاقه. سنقوم أيضًا بإنشاء فئة أخرى باسم MediaStyleHelper
، والتي كتبها Ian Lake ، Developer Advocate في Google ، لتنظيف إنشاء إعلامات على نمط الوسائط.
public class MediaStyleHelper { /** * Build a notification using the information from the given media session. Makes heavy use * of {@link MediaMetadataCompat#getDescription()} to extract the appropriate information. * @param context Context used to construct the notification. * @param mediaSession Media session to get information. * @return A pre-built notification with information from the given media session. */ public static NotificationCompat.Builder from( Context context, MediaSessionCompat mediaSession) { MediaControllerCompat controller = mediaSession.getController(); MediaMetadataCompat mediaMetadata = controller.getMetadata(); MediaDescriptionCompat description = mediaMetadata.getDescription(); NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder .setContentTitle(description.getTitle()) .setContentText(description.getSubtitle()) .setSubText(description.getDescription()) .setLargeIcon(description.getIconBitmap()) .setContentIntent(controller.getSessionActivity()) .setDeleteIntent( MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP)) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC); return builder; } }
بمجرد أن يتم إنشاء، والمضي قدما بإغلاق الملف. وسوف نركز على خدمة الصوت في الخلفية في المقطع التالي.
بناء على خدمة الصوت في الخلفية
الآن حان الوقت لحفر في صلب إنشاء التطبيق الخاص بك في وسائل الإعلام. هناك عدد قليل من المتغيرات الخاصة بالأعضاء التي ستقوم بتعريفها أولاً لهذا التطبيق النموذجي: وهو MediaPlaye
r للتشغيل الفعلي ، وكائن MediaSessionCompat
الذي سيدير البيانات الوصفية وعناصر التحكم / الحالات.
private MediaPlayer mMediaPlayer; private MediaSessionCompat mMediaSessionCompat;
بالإضافة إلى ذلك ، ستحتاج إلى جهاز BroadcastReceiver
يستمع إلى التغييرات في حالة سماعة الرأس. للحفاظ على بساطة الأشياء ، سيوقف جهاز الاستقبال هذا برنامج MediaPlayer
، إذا كان مشغلاً.
private BroadcastReceiver mNoisyReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if( mMediaPlayer != null && mMediaPlayer.isPlaying() ) { mMediaPlayer.pause(); } } };
لمتغير العضو النهائي، سوف لإنشاء كائن MediaSessionCompat.Callback
، الذي يستخدم لمعالجة حالة التشغيل عند حدوث إجراءات الدورة وسائل الإعلام.
private MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() { @Override public void onPlay() { super.onPlay(); } @Override public void onPause() { super.onPause(); } @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { super.onPlayFromMediaId(mediaId, extras); } };
سوف نعيد كل من الأساليب المذكورة أعلاه في وقت لاحق في هذا البرنامج التعليمي، كما أنها ستستخدم لعمليات محرك الأقراص في التطبيق وسائل الإعلام لدينا.
هناك طريقتين التي سوف نحتاج أيضا إلى أن تعلن، على الرغم من أنها لن تحتاج إلى القيام بأي شيء لأغراض هذا البرنامج التعليمي: onGetRoot()
و onLoadChildren()
. يمكنك استخدام التعليمات البرمجية التالية للافتراضيات الخاصة بك.
@Nullable @Override public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { if(TextUtils.equals(clientPackageName, getPackageName())) { return new BrowserRoot(getString(R.string.app_name), null); } return null; } //Not important for general audio service, required for class @Override public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) { result.sendResult(null); }
وأخيرًا ، سترغب في تجاوز أسلوب onStartCommand ()
، الذي يمثل نقطة الإدخال في Service
. سيأخذ هذا الأسلوب في Intent التي تم تمريرها إلى Service
وإرسالها إلى فئة MediaButtonReceiver
.
@Override public int onStartCommand(Intent intent, int flags, int startId) { MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent); return super.onStartCommand(intent, flags, startId); }
تهيئة جميع الأشياء
والآن بعد أن يتم إنشاء متغيرات عضو القاعدة الخاصة بك، حان الوقت لتهيئة كل شيء. سنقوم بذلك عن طريق استدعاء أساليب المساعد المختلفة في onCreate ()
.
@Override public void onCreate() { super.onCreate(); initMediaPlayer(); initMediaSession(); initNoisyReceiver(); }
الطريقة الأولى ، initMediaPlayer ()
، ستقوم بتهيئة كائن MediaPlayer
الذي أنشأناه في الجزء العلوي من الفصل ، وطلب قفل التنبيه الجزئي (وهذا هو السبب في أننا طلبنا هذا الإذن في AndroidManifest.xml) ، وضبط حجم المشغل.
private void initMediaPlayer() { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setVolume(1.0f, 1.0f); }
الطريقة التالية ، initMediaSession ()
، هي المكان الذي نقوم فيه بتهيئة كائن MediaSessionCompat
وسلكه إلى أزرار الوسائط وطرق التحكم التي تسمح لنا بالتعامل مع التشغيل وإدخال المستخدم. يبدأ هذا الأسلوب عن طريق إنشاء كائن ComponentName
الذي يشير إلى فئة MediaButtonReceiver
في مكتبة دعم Android ، ويستخدم ذلك لإنشاء MediaSessionCompat
جديد. ونحن ثم تمرير الكائن MediaSession.Callback
أن تم إنشاؤها في وقت سابق، وتعيين العلامات اللازمة لتلقي مدخلات زر الوسائط والتحكم بإشارات. بعد ذلك ، نخلق جديدًا Intent
للتعامل مع مدخلات زر الوسائط على أجهزة Pre-Lollipop ، وتعيين رمز جلسة عمل الوسائط لخدماتنا.
private void initMediaSession() { ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class); mMediaSessionCompat = new MediaSessionCompat(getApplicationContext(), "Tag", mediaButtonReceiver, null); mMediaSessionCompat.setCallback(mMediaSessionCallback); mMediaSessionCompat.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS ); Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setClass(this, MediaButtonReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0); mMediaSessionCompat.setMediaButtonReceiver(pendingIntent); setSessionToken(mMediaSessionCompat.getSessionToken()); }
أخيرًا ، سنسجل BroadcastReceiver
الذي أنشأناه في الجزء العلوي من الفصل الدراسي حتى نتمكن من الاستماع إلى أحداث تغيير سماعات الرأس.
private void initNoisyReceiver() { //Handles headphones coming unplugged. cannot be done through a manifest receiver IntentFilter filter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); registerReceiver(mNoisyReceiver, filter); }
التعامل مع تركيز الصوت
الآن بعد الانتهاء من تهيئة كائنات BroadcastReceiver
و MediaSessionCompat
و MediaPlayer
، فقد حان الوقت للنظر في التعامل مع التركيز الصوتي.
بينما قد نعتقد أن منطقتنا تطبيقات الصوت هي الأكثر أهمية في الوقت الراهن، سوف تكون المنافسة تطبيقات أخرى على الجهاز لجعل الأصوات الخاصة بهم، مثل إعلام بالبريد الإلكتروني أو لعبة الجوال. من أجل العمل مع هذه الحالات المختلفة، يستخدم نظام الروبوت تركيز الصوت لتحديد كيف ينبغي التعامل مع الصوت.
وفي الحالة الأولى أننا سوف ترغب في التعامل مع بدء التشغيل ومحاولة تلقي التركيز للجهاز. في كائن MediaSessionCompat.Callback
الخاص بك، انتقل إلى الأسلوب onPlay()
وإضافة شرط الاختيار التالية.
@Override public void onPlay() { super.onPlay(); if( !successfullyRetrievedAudioFocus() ) { return; } }
سيتم استدعاء التعليمات البرمجية أعلاه أسلوب مساعد أن محاولات لاسترداد التركيز، ولو أنه لا يمكن، فإنه سيعود ببساطة. في تطبيق حقيقي، قد ترغب في التعامل مع فشل تشغيل الصوت بأمان أكثر. سوف successfullyRetrievedAudioFocus()
الحصول على مرجع إلى نظام AudioManager
، ومحاولة لطلب التركيز الصوتية لدفق الموسيقى. سوف يعود بعد ذلك boolean
تمثل ما إذا كان الطلب قد نجح أم لا.
private boolean successfullyRetrievedAudioFocus() { AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); return result == AudioManager.AUDIOFOCUS_GAIN; }
ستلاحظ أننا نمرر this
أيضًا إلى requestAudioFocus ()
، الذي يربط OnAudioFocusChangeListener
مع خدمتنا. وهناك عدد قليل من الدول المختلفة التي سوف تحتاج للاستماع لكي تكون "مواطن الصالح" في النظام الإيكولوجي في التطبيق للجهاز.
-
AudioManager.AUDIOFOCUS_LOSS
: يحدث هذا عندما طلبت آخر التطبيق تركيز الصوت. عندما يحدث هذا، يجب عليك إيقاف تشغيل الصوت في التطبيق الخاص بك. -
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
: يتم إدخال هذه الدولة عندما يريد آخر التطبيق تشغيل الصوت، ولكن أنها تتوقع فقط تحتاج إلى التركيز لفترة قصيرة. يمكنك استخدام هذه الدولة لإيقاف تشغيل الصوت الخاص بك. -
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
: عندما تركيز الصوت ومطلوب، ولكن يلقي دولة 'يمكن بطة'، فهذا يعني أنك يمكن أن يستمر التشغيل الخاص بك، ولكن يجب إحضار وحدة التخزين إلى أسفل قليلاً. يمكن أن يحدث هذا عندما يتم لعب صوت إشعار بالجهاز.
-
AudioManager.AUDIOFOCUS_GAIN
: هو الحالة النهائية وسوف نناقشAUDIOFOCUS_GAIN
. هذه هي الحالة عندما انتهت قراءة صوت دوكابل، والتطبيق الخاص بك يمكن أن تستأنف في المستويات السابقة.
رد اتصال onAudioFocusChange()
مبسطة قد تبدو كما يلي:
@Override public void onAudioFocusChange(int focusChange) { switch( focusChange ) { case AudioManager.AUDIOFOCUS_LOSS: { if( mMediaPlayer.isPlaying() ) { mMediaPlayer.stop(); } break; } case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: { mMediaPlayer.pause(); break; } case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: { if( mMediaPlayer != null ) { mMediaPlayer.setVolume(0.3f, 0.3f); } break; } case AudioManager.AUDIOFOCUS_GAIN: { if( mMediaPlayer != null ) { if( !mMediaPlayer.isPlaying() ) { mMediaPlayer.start(); } mMediaPlayer.setVolume(1.0f, 1.0f); } break; } } }
فهم في MediaSessionCompat.Callback
الآن بعد أن لديك بنية عامة معا Service
الخاصة بك، حان الوقت يغوص MediaSessionCompat.Callback
. في المقطع الأخير قمت بإضافتها قليلاً إلى onPlay()
للتحقق إذا كان منح تركيز الصوت. أسفل العبارة الشرطية ، ستحتاج إلى تعيين كائن MediaSessionCompat
ليتم تنشيطه ، وإعطائه حالة من STATE_PLAYING
، وتعيين الإجراءات المناسبة الضرورية لإنشاء أزرار الإيقاف المؤقت على عناصر التحكم في قفل الشاشة السابق ، Lollipop ، وإخطارات الهاتف وإشعارات Android Wear.
@Override public void onPlay() { super.onPlay(); if( !successfullyRetrievedAudioFocus() ) { return; } mMediaSessionCompat.setActive(true); setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING); ... }
أسلوب setMediaPlaybackState ()
أعلاه هو أسلوب مساعد ينشئ كائن PlaybackStateCompat.Builder
ويعطيها الإجراءات المناسبة وحالة ثم ثم ينشئ ثم يقترن PlaybackStateCompat
مع كائن MediaSessionCompat
الخاص بك.
private void setMediaPlaybackState(int state) { PlaybackStateCompat.Builder playbackstateBuilder = new PlaybackStateCompat.Builder(); if( state == PlaybackStateCompat.STATE_PLAYING ) { playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PAUSE); } else { playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY); } playbackstateBuilder.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 0); mMediaSessionCompat.setPlaybackState(playbackstateBuilder.build()); }
من المهم ملاحظة أنك ستحتاج كل من ACTION_PLAY_PAUSE
وإعلام ACTION_PAUSE
أو ACTION_PLAY
في الإجراءات الخاصة بك من أجل الحصول على ضوابط سليمة على "ارتداء الروبوت".



مرة أخرى في onPlay ()
، ستحتاج إلى إظهار إعلام تشغيل مقترن كائن MediaSessionCompat
الخاص بك باستخدام فئة MediaStyleHelper
التي تم تعريفها مسبقًا ثم إظهار ذلك الإعلام.
private void showPlayingNotification() { NotificationCompat.Builder builder = MediaStyleHelper.from(BackgroundAudioService.this, mMediaSessionCompat); if( builder == null ) { return; } builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_pause, "Pause", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PLAY_PAUSE))); builder.setStyle(new NotificationCompat.MediaStyle().setShowActionsInCompactView(0).setMediaSession(mMediaSessionCompat.getSessionToken())); builder.setSmallIcon(R.mipmap.ic_launcher); NotificationManagerCompat.from(BackgroundAudioService.this).notify(1, builder.build()); }
أخيرا ، سوف تبدأ في MediaPlayer
في نهاية onPlay ()
.
@Override public void onPlay() { super.onPlay(); ... showPlayingNotification(); mMediaPlayer.start(); }



عندما يتلقى رد الاتصال أمر الإيقاف مؤقت، سيتم استدعاء onPause()
. هنا سوف تقوم بإيقاف MediaPlayer
مؤقتًا ، وتعيين الحالة إلى STATE_PAUSED
، وإظهار إعلام متوقف مؤقتًا.
@Override public void onPause() { super.onPause(); if( mMediaPlayer.isPlaying() ) { mMediaPlayer.pause(); setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED); showPausedNotification(); } }
لدينا أسلوب مساعد showPausedNotification()
مشابهاً لأسلوب showPlayNotification()
.
private void showPausedNotification() { NotificationCompat.Builder builder = MediaStyleHelper.from(this, mMediaSessionCompat); if( builder == null ) { return; } builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_play, "Play", MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PLAY_PAUSE))); builder.setStyle(new NotificationCompat.MediaStyle().setShowActionsInCompactView(0).setMediaSession(mMediaSessionCompat.getSessionToken())); builder.setSmallIcon(R.mipmap.ic_launcher); NotificationManagerCompat.from(this).notify(1, builder.build()); }
الطريقة التالية في معاودة الاتصال التي سنناقشها ، onPlayFromMediaId()
, يأخذ String
و Bundle
كمعلمات. هذا هو أسلوب رد الاتصال التي يمكنك استخدامها لتغيير المسارات/محتوى الصوت داخل التطبيق الخاص بك.
لهذا البرنامج التعليمي، سنقوم ببساطة قبول وجود معرف موارد خام ومحاولة اللعب التي ومن ثم تهيئة بيانات التعريف الدورة. كما يسمح لك لتمرير Bundle
في هذه الطريقة ، يمكنك استخدامها لتخصيص الجوانب الأخرى لتشغيل الوسائط ، مثل إعداد صوت خلفية مخصص لمسار.
@Override public void onPlayFromMediaId(String mediaId, Bundle extras) { super.onPlayFromMediaId(mediaId, extras); try { AssetFileDescriptor afd = getResources().openRawResourceFd(Integer.valueOf(mediaId)); if( afd == null ) { return; } try { mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); } catch( IllegalStateException e ) { mMediaPlayer.release(); initMediaPlayer(); mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); } afd.close(); initMediaSessionMetadata(); } catch (IOException e) { return; } try { mMediaPlayer.prepare(); } catch (IOException e) {} //Work with extras here if you want }
الآن أن لقد ناقشنا طريقتين الرئيسي في هذا رد الاتصال التي سيتم استخدامها في التطبيقات الخاصة بك، من المهم أن تعرف أن هناك أساليب أخرى الاختيارية التي يمكنك استخدامها لتخصيص الخدمة الخاصة بك. بعض الطرق تشمل onSeekTo()
الذي يسمح لك بتغيير موضع التشغيل للمحتوى الخاص بك، و onCommand()
والتي سوف تقبل String
تدل على نوع القيادة ، Bundle
للحصول على معلومات إضافية حول الأمر ، و ResultReceiver
رد الاتصال، والتي سوف تسمح لك بإرسال أوامر مخصصة إلى حسابك Service
.
@Override public void onCommand(String command, Bundle extras, ResultReceiver cb) { super.onCommand(command, extras, cb); if( COMMAND_EXAMPLE.equalsIgnoreCase(command) ) { //Custom command here } } @Override public void onSeekTo(long pos) { super.onSeekTo(pos); }
تمزيق
عند الانتهاء من ملف الصوت لدينا، سوف نريد أن تقرر ما سيكون عملنا المقبل. في حين قد ترغب في تشغيل المسار التالي في تطبيقك ، سنبقي الأمور بسيطة ونفرج عن MediaPlayer
.
@Override public void onCompletion(MediaPlayer mediaPlayer) { if( mMediaPlayer != null ) { mMediaPlayer.release(); } }
أخيراً ، سوف نرغب في القيام بأشياء قليلة في onDestroy()
طريقة لدينا Service
. أولاً ، احصل على مرجع إلى AudioManager
الخاص بخدمة النظام ، واتصل بـ abandonAudioFocus ()
باستخدام AudioFocusChangeListener
كمعلمة ، والتي ستقوم بإعلام التطبيقات الأخرى على الجهاز أنك تتخلى عن تركيز الصوت. بعد ذلك ، قم بإلغاء تسجيل BroadcastReceiver
الذي تم إعداده للاستماع لتغيرات سماعة الرأس وتحرير كائن MediaSessionCompat
. وأخيراً، سوف تحتاج إلى إلغاء الإخطار التحكم بالتشغيل.
@Override public void onDestroy() { super.onDestroy(); AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); audioManager.abandonAudioFocus(this); unregisterReceiver(mNoisyReceiver); mMediaSessionCompat.release(); NotificationManagerCompat.from(this).cancel(1); }
في هذه المرحلة ، يجب أن يكون لديك خدمة صوت Service
أساسية أساسية تستخدم MediaSessionCompat
للتحكم في التشغيل عبر الأجهزة. في حين قد حدثت بالفعل الكثير من المشاركة في مجرد إنشاء الدائرة، يجب أن تكون قادرة على التحكم في التشغيل من التطبيق الخاص بك، إعلام، وتأمين عناصر تحكم الشاشة على أجهزة مصاصة قبل (مصاصة وأعلاه سوف تستخدم الإخطار على الشاشة قفل)، ومن الأجهزة الطرفية، مثل "ارتداء الروبوت"، بمجرد تم بدء تشغيل Service
.



بدء تشغيل والتحكم في المحتوى من نشاط
في حين سوف تكون معظم عناصر التحكم التلقائي، سوف لا يزال لديك قليلاً من العمل بدء تشغيل والتحكم في جلسة عمل وسائل الإعلام من عناصر التحكم في التطبيق الخاص بك. على أقل تقدير ، سوف تحتاج إلى MediaBrowserCompat.ConnectionCallback
، و MediaControllerCompat.Callbac
k ، و MediaBrowserCompat
، و MediaControllerCompat
الكائنات التي تم إنشاؤها في التطبيق الخاص بك.
سيحتوي MediaControllerCompat.Callback
على أسلوب يسمى onPlaybackStateChanged ()
يتلقى تغييرات في حالة التشغيل ، ويمكن استخدامه للحفاظ على واجهة المستخدم الخاصة بك في المزامنة.
private MediaControllerCompat.Callback mMediaControllerCompatCallback = new MediaControllerCompat.Callback() { @Override public void onPlaybackStateChanged(PlaybackStateCompat state) { super.onPlaybackStateChanged(state); if( state == null ) { return; } switch( state.getState() ) { case PlaybackStateCompat.STATE_PLAYING: { mCurrentState = STATE_PLAYING; break; } case PlaybackStateCompat.STATE_PAUSED: { mCurrentState = STATE_PAUSED; break; } } } };
يحتوي MediaBrowserCompat.ConnectionCallback
على أسلوب onConnected ()
سيتم استدعاء عند إنشاء كائن MediaBrowserCompat
جديد وتوصيله. يمكنك استخدام هذا لتهيئة كائن MediaControllerCompat
الخاص بك ، قم بربطه بـ MediaControllerCompat.Callback
، وقم بربطه بـ MediaSessionCompat
من Service
الخاصة بك. وبمجرد الانتهاء من ذلك، يمكنك بدء تشغيل الصوت من هذا الأسلوب.
private MediaBrowserCompat.ConnectionCallback mMediaBrowserCompatConnectionCallback = new MediaBrowserCompat.ConnectionCallback() { @Override public void onConnected() { super.onConnected(); try { mMediaControllerCompat = new MediaControllerCompat(MainActivity.this, mMediaBrowserCompat.getSessionToken()); mMediaControllerCompat.registerCallback(mMediaControllerCompatCallback); setSupportMediaController(mMediaControllerCompat); getSupportMediaController().getTransportControls().playFromMediaId(String.valueOf(R.raw.warner_tautz_off_broadway), null); } catch( RemoteException e ) { } } };
ستلاحظ أن أجزاء التعليمات البرمجية المتكررة أعلاه يستخدم getSupportMediaController().getTransportControls()
للتواصل مع الدورة وسائل الإعلام. باستخدام نفس الأسلوب، يمكنك استدعاء onPlay()
و onPause()
في كائن خدمة الصوت الخاص بك MediaSessionCompat.Callback
.
if( mCurrentState == STATE_PAUSED ) { getSupportMediaController().getTransportControls().play(); mCurrentState = STATE_PLAYING; } else { if( getSupportMediaController().getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING ) { getSupportMediaController().getTransportControls().pause(); } mCurrentState = STATE_PAUSED; }
عند الانتهاء من تشغيل الصوت ، يمكنك إيقاف خدمة الصوت مؤقتًا وفصل كائن MediaBrowserCompat
، وهو ما سنفعله في هذا البرنامج التعليمي عند إتلاف هذا Activity
.
@Override protected void onDestroy() { super.onDestroy(); if( getSupportMediaController().getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING ) { getSupportMediaController().getTransportControls().pause(); } mMediaBrowserCompat.disconnect(); }
وفي ختام
يا للعجب! كما ترون، هناك الكثير من القطع تتحرك المعنية مع إنشاء واستخدام خدمة صوت خلفية بشكل صحيح.
في هذا البرنامج التعليمي ، قمت بإنشاء خدمة تقوم بتشغيل ملف صوتي بسيط ، والاستماع إلى التغييرات في تركيز الصوت ، والارتباطات إلى MediaSessionCompat
لتوفير التحكم في التشغيل العام على أجهزة Android ، بما في ذلك الهواتف المحمولة و Android Wear. إذا قمت بتشغيل إلى حواجز الطرق أثناء العمل من خلال هذا البرنامج التعليمي، أوصى بشدة بالتحقق من التعليمات البرمجية المقترنة المشروع الروبوت في Envato Tuts + في GitHub.
وتحقق بعض دورات الروبوت والدروس هنا في Envato Tuts + الأخرى!
- الروبوت SDKما الجديد في Android N و Wear 2.0بول تريبيلكو-رويس
- الروبوت SDKخدمات Google Play: Google Cast v3 and Mediaبول تريبيلكو-رويس
- الروبوت SDKالتقاط صور مع الروبوت التطبيق الخاص بكهاثيبيلاجال أشرف