Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)
Một trong những ứng dụng phổ biến nhất trên các thiết bị di động là phát nhạc thông qua các dịch vụ stream nhạc, các podcast hoặc bất kỳ nguồn âm thanh nào khác. Mặc dù đây là một tính năng khá phổ biến nhưng rất khó cài đặt, với nhiều phần khác nhau cần được xây dựng một cách chính xác để mang lại cho người dùng của bạn một trải nghiệm Android đầy đủ.
Trong hướng dẫn này, bạn sẽ được học về MediaSessionCompat
từ Android support library và cách sử dụng nó để tạo một dịch vụ âm thanh nền thích hợp cho người dùng của bạn.
Thiết lập
Điều đầu tiên bạn cần làm là bao gồm Android support library trong dự án của bạn. Điều này có thể được thực hiện bằng cách thêm dòng dưới đây vào trong tập tin build.gradle cấp mô-đun của bạn dưới nút phụ thuộc (dependencies).
compile 'com.android.support:support-v13:24.2.1'
Sau khi bạn đã đồng bộ hóa dự án của bạn, hãy tạo một lớp Java mới. Đối với ví dụ này, tôi đặt tên lớp là BackgroundAudioService
. Lớp này sẽ cần phải thừa kế từ lớp MediaBrowserServiceCompat
. Chúng ta cũng sẽ cài đặt các giao diện sau đây: MediaPlayer.OnCompletionListener
và AudioManager.OnAudioFocusChangeListener
.
Bây giờ thì cài đặt của lớp MediaBrowserServiceCompat
đã được tạo ra, hãy dành một chút thời gian để cập nhật AndroidManifest.xml trước khi quay lại lớp này. Ở phía trên của lớp, bạn sẽ cần phải yêu cầu được cấp quyền WAKE_LOCK
.
<uses-permission android:name="android.permission.WAKE_LOCK" />
Tiếp theo, bên trong nút application
, hãy khai báo dịch vụ mới của bạn với các thành phần intent-filter
sau đây. Những điều này sẽ cho phép dịch vụ của bạn bắt lấy các nút điều khiển, các sự kiện tai nghe và trình duyệt media cho các thiết bị, chẳng hạn như Android Auto (mặc dù chúng ta sẽ không làm bất cứ điều gì với Android Auto trong hướng dẫn này, nhưng một số hỗ trợ cơ bản cho nó vẫn được yêu cầu bởi 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>
Cuối cùng, bạn sẽ cần phải khai báo việc sử dụng MediaButtonReceiver
từ Android support library. Điều này sẽ cho phép bạn nắm bắt các tương tác nút điều khiển media và các sự kiện khi gắn tai nghe trên thiết bị chạy KitKat và cũ hơn.
<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>
Bây giờ tập tin AndroidManifest.xml của bạn đã hoàn tất, bạn có thể đóng nó. Chúng ta cũng sẽ tạo một lớp khác có tên là MediaStyleHelper
, được viết bởi Ian Lake, Developer Advocate tại Google, để dọn dẹp các thông báo kiểu media.
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; } }
Khi nó đã được tạo xong, hãy tiếp tục và đóng tập tin. Chúng ta sẽ tập trung vào dịch vụ âm thanh nền trong phần tiếp theo.
Xây dựng Dịch vụ Âm thanh Nền
Bây giờ đã đến lúc để đi sâu vào phần cốt lõi của việc tạo ứng dụng media của bạn. Có một vài biến thành viên mà bạn sẽ cần khai báo trước tiên cho ứng dụng mẫu này: một MediaPlayer
để thật sự phát nhạc, và một đối tượng MediaSessionCompat
sẽ quản lý metadata và các điều khiển hoặc trạng thái của trình phát nhạc.
private MediaPlayer mMediaPlayer; private MediaSessionCompat mMediaSessionCompat;
Ngoài ra, bạn sẽ cần một BroadcastReceiver
để lắng nghe những thay đổi trong trạng thái của tai nghe. Để giữ cho mọi thứ đơn giản, receiver này sẽ tạm dừng MediaPlayer
, nếu nó đang phát.
private BroadcastReceiver mNoisyReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if( mMediaPlayer != null && mMediaPlayer.isPlaying() ) { mMediaPlayer.pause(); } } };
Đối với biến thành viên cuối cùng, bạn sẽ tạo ra một đối tượng MediaSessionCompat.Callback
, cái mà sẽ được sử dụng để xử lý trạng thái của trình phát nhạc khi các hành động media session xảy ra.
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); } };
Chúng ta sẽ xem xét lại từng phương thức trên sau trong hướng dẫn này, vì chúng sẽ được sử dụng để điều khiển các hoạt động trong ứng dụng media của chúng ta.
Có hai phương thức mà chúng ta cũng cần phải khai báo, mặc dù chúng sẽ không cần phải làm bất cứ điều gì đối với mục đích của hướng dẫn này: onGetRoot()
và onLoadChildren()
. Bạn có thể sử dụng code sau đây cho các hàm mặc định của bạn.
@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); }
Cuối cùng, bạn sẽ cần override phương thức onStartCommand()
, đây là điểm truy cập vào trong Service
của bạn. Phương thức này sẽ nhận Intent được truyền tới Service
và gửi nó đến lớp MediaButtonReceiver
.
@Override public int onStartCommand(Intent intent, int flags, int startId) { MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent); return super.onStartCommand(intent, flags, startId); }
Khởi tạo mọi thứ
Bây giờ thì các biến thành viên cơ bản của bạn đã được tạo ra, đã đến lúc khởi tạo mọi thứ. Chúng ta sẽ thực hiện điều này bằng cách gọi các phương thức trợ giúp khác nhau trong onCreate()
.
@Override public void onCreate() { super.onCreate(); initMediaPlayer(); initMediaSession(); initNoisyReceiver(); }
Phương thức đầu tiên, initMediaPlayer()
, sẽ khởi tạo đối tượng MediaPlayer
mà chúng ta đã tạo ở trên cùng của lớp, yêu cầu quyền wake lock (đó là lý do tại sao chúng ta yêu cầu quyền đó trong AndroidManifest.xml), và thiết lập âm lượng của trình phát nhạc.
private void initMediaPlayer() { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setVolume(1.0f, 1.0f); }
Phương thức tiếp theo, initMediaSession()
, là nơi chúng ta khởi tạo đối tượng MediaSessionCompat
và nối nó với các nút media và các phương thức điều khiển cho phép chúng ta xử lý trình phát nhạc và đầu vào từ người dùng. Phương thức này bắt đầu bằng cách tạo ra một đối tượng ComponentName
trỏ đến lớp MediaButtonReceiver
của Android support library và sử dụng nó để tạo một MediaSessionCompat
mới. Sau đó chúng ta truyền đối tượng MediaSession.Callback
mà chúng ta đã tạo ra trước đó vào nó, và thiết lập các cờ cần thiết để nhận đầu vào là các nút bấm media và các tín hiệu điều khiển. Tiếp theo, chúng ta tạo ra một Intent
mới để xử lý các nút media trên các thiết bị chạy Android phiên bản cũ hơn Lollipop và thiết lập media session token của chúng ta.
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()); }
Cuối cùng, chúng ta sẽ đăng ký BroadcastReceiver
mà chúng ta đã tạo ra ở bên trên của lớp từ đó chúng ta có thể lắng nghe các sự kiện thay đổi tai nghe.
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); }
Điều khiển Tập trung Âm thanh
Bây giờ bạn đã hoàn tất việc khởi tạo các đối tượng BroadcastReceiver
, MediaSessionCompat
và MediaPlayer
, đã đến lúc tìm hiểu về điều khiển tập trung âm thanh.
Mặc dù hiện tại chúng ta có thể nghĩ ứng dụng âm thanh của chúng ta là quan trọng nhất, nhưng các ứng dụng khác trên thiết bị sẽ cạnh tranh để tạo ra âm thanh của riêng chúng, chẳng hạn như một thông báo email hoặc game. Để làm việc với các tình huống khác nhau này, hệ thống Android sử dụng tập trung âm thanh để xác định cách âm thanh có thể được xử lý.
Trường hợp đầu tiên mà chúng ta muốn xử lý là bắt đầu phát nhạc và cố gắng nhận được tập trung của thiết bị. Trong đối tượng MediaSessionCompat.Callback
của bạn, hãy truy cập vào phương thức onPlay()
và thêm các điều kiện kiểm tra sau đây.
@Override public void onPlay() { super.onPlay(); if( !successfullyRetrievedAudioFocus() ) { return; } }
Đoạn code ở trên sẽ gọi một phương thức trợ giúp để cố gắng truy vấn tập trung, và nếu không thể, thì nó sẽ trả về (return). Trong một ứng dụng thực tế, bạn sẽ cần xử lý việc phát âm thanh không thành công một cách tinh tế hơn. successfullyRetrievedAudioFocus()
sẽ lấy một tham chiếu đến AudioManager
của hệ thống, và cố gắng yêu cầu tập trung âm thanh để stream nhạc. Nó sẽ trả về một boolean
đại diện kết quả của yêu cầu có thành công hay không.
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; }
Bạn sẽ thấy rằng chúng ta cũng truyền this
vào trong phương thức requestAudioFocus()
, nó liên kết OnAudioFocusChangeListener
với dịch vụ của chúng ta. Có một vài trạng thái khác nhau mà bạn sẽ muốn lắng nghe để trở thành một "công dân tốt" trong hệ sinh thái ứng dụng của thiết bị.
-
AudioManager.AUDIOFOCUS_LOSS
: Trạng thái này xảy ra khi một ứng dụng khác yêu cầu tập trung âm thanh. Khi việc này xảy ra, bạn nên dừng phát nhạc trong ứng dụng của bạn. -
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
: Trạng thái này được bắt đầu khi một ứng dụng khác muốn phát âm thanh, nhưng nó chỉ báo trước nhu cầu tập trung trong một thời gian ngắn. Bạn có thể sử dụng trạng thái này để tạm dừng việc phát âm thanh của bạn. -
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
: Khi tập trung âm thanh được yêu cầu, nhưng phát sinh một trạng thái 'can duck', điều đó có nghĩa là bạn có thể tiếp tục phát nhạc, nhưng nên giảm âm lượng xuống một chút. Trạng thái này có thể xảy ra khi âm thanh thông báo được phát bởi thiết bị.
-
AudioManager.AUDIOFOCUS_GAIN
: Trạng thái cuối cùng mà chúng ta sẽ thảo luận làAUDIOFOCUS_GAIN
. Đây là trạng thái khi trạng thái 'can duck' đã hoàn tất và ứng dụng của bạn có thể tiếp tục tại mức âm lượng như trước.
Một callback đã được đơn giản hoá onAudioFocusChange()
có thể trông giống như sau:
@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; } } }
Tìm hiểu về MediaSessionCompat.Callback
Bây giờ thì bạn đã có một cấu trúc chung cho Service
của bạn, đã đến lúc tìm hiểu sâu về MediaSessionCompat.Callback
. Trong phần trước, bạn đã thêm một ít code vào onPlay()
để kiểm tra xem tập trung âm thanh đã được cấp hay chưa. Bên dưới câu lệnh điều kiện, bạn sẽ cần kích hoạt đối tượng MediaSessionCompat
, cung cấp cho nó một trạng thái STATE_PLAYING
, và chỉ định các hành động phù hợp cần thiết để tạo nút tạm dừng trên màn hình của các thiết bị chạy phiên bản cũ hơn Lollipop, các thông báo trên điện thoại và Android Wear.
@Override public void onPlay() { super.onPlay(); if( !successfullyRetrievedAudioFocus() ) { return; } mMediaSessionCompat.setActive(true); setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING); ... }
Phương thức setMediaPlaybackState()
ở trên là một phương thức trợ giúp để tạo ra một đối tượng PlaybackStateCompat.Builder
và cung cấp cho nó các hành động và trạng thái thích hợp, và sau đó xây dựng và liên kết một PlaybackStateCompat
với đối tượng MediaSessionCompat
của bạn.
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()); }
Điều quan trọng cần phải lưu ý là bạn sẽ cần cả cờ ACTION_PLAY_PAUSE
và ACTION_PAUSE
hoặc ACTION_PLAY
trong các hành động của bạn để có được các điều khiển phù hợp trên Android Wear.

Quay trở lại onPlay()
, bạn sẽ cần hiển thị một thông báo đang phát được liên kết với đối tượng MediaSessionCompat
của bạn bằng cách sử dụng lớp MediaStyleHelper
mà chúng ta đã định nghĩa trước đó, và sau đó hiển thị thông báo đó.
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()); }
Cuối cùng, bạn sẽ khởi động MediaPlayer
vào cuối của phương thức onPlay()
.
@Override public void onPlay() { super.onPlay(); ... showPlayingNotification(); mMediaPlayer.start(); }

Khi callback nhận một lệnh tạm dừng, thì onPause()
sẽ được gọi. Ở đây bạn sẽ tạm dừng MediaPlayer
, thiết lập trạng thái thành STATE_PAUSED
và hiển thị một thông báo tạm dừng.
@Override public void onPause() { super.onPause(); if( mMediaPlayer.isPlaying() ) { mMediaPlayer.pause(); setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED); showPausedNotification(); } }
Phương thức trợ giúp showPausedNotification()
của chúng ta sẽ tương tự như phương thức 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()); }
Phương thức tiếp theo trong callback mà chúng ta sẽ thảo luận là, onPlayFromMediaId()
, nhận các tham số kiểu String
và Bundle
. Đây là phương thức callback mà bạn có thể sử dụng để thay đổi bài hát hoặc nội dung âm thanh trong ứng dụng của bạn.
Đối với hướng dẫn này, chúng ta sẽ chỉ đơn giản chấp nhận một ID tài nguyên thô và cố gắng phát nó, và sau đó khởi tạo lại metadata của session. Vì bạn được phép truyền một Bundle
vào phương thức này, nên bạn có thể sử dụng nó để tùy biến các khía cạnh khác của trình phát media của bạn, chẳng hạn như thiết lập một âm thanh nền tùy biến cho một bài nhạc.
@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 }
Bây giờ thì chúng ta đã thảo luận về hai phương thức chính trong callback này mà bạn sẽ sử dụng trong các ứng dụng của mình, điều quan trọng cần phải biết là còn có các phương thức tùy chọn khác mà bạn có thể sử dụng để tuỳ biến dịch vụ của bạn. Một số phương thức bao gồm onSeekTo()
, cho phép bạn thay đổi vị trí phát nội dung của bạn, và onCommand()
, nhận một String
biểu thị kiểu lệnh, một Bundle
cho thông tin phụ về lệnh và một callback ResultReceiver
, sẽ cho phép bạn gửi các lệnh tùy biến tới Service
của bạn.
@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); }
Bóc tách
Khi tập tin âm thanh của chúng ta đã được phát triển xong, chúng ta sẽ cần quyết định hành động tiếp theo của chúng ta sẽ là gì. Mặc dù bạn có thể muốn phát bài hát tiếp theo trong ứng dụng của mình, nhưng chúng ta sẽ giữ cho mọi thứ đơn giản và giải phóng MediaPlayer
.
@Override public void onCompletion(MediaPlayer mediaPlayer) { if( mMediaPlayer != null ) { mMediaPlayer.release(); } }
Cuối cùng, chúng ta sẽ cần làm một vài thứ trong phương thức onDestroy()
của Service
của chúng ta. Đầu tiên, lấy một tham chiếu đến AudioManager
của dịch vụ hệ thống và gọi abandonAudioFocus()
với AudioFocusChangeListener
của chúng ta như là một tham số, sẽ thông báo cho các ứng dụng khác trên thiết bị mà bạn đang ngưng tập trung âm thanh. Tiếp theo, bỏ đăng ký BroadcastReceiver
đã được thiết lập để lắng nghe các thay đổi tai nghe và giải phóng đối tượng MediaSessionCompat
. Cuối cùng, bạn sẽ cần hủy thông báo chứa điều khiển phát nhạc.
@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); }
Lúc này, bạn sẽ có một Service
âm thanh nền cơ bản đang hoạt động sử dụng MediaSessionCompat
để điều khiển việc phát nhạc trên các thiết bị. Mặc dù đã có rất nhiều thứ liên quan đến việc tạo Service, nhưng bạn vẫn có thể điều khiển phát nhạc từ ứng dụng của bạn, trên thông báo, các điều khiển trên màn hình khóa trên thiết bị chạy phiên Android thấp hơn Lollipop (Lollipop và cao hơn sẽ sử dụng thông báo trên màn hình khóa), và từ các thiết bị ngoại vi, chẳng hạn như Android Wear, một khi Service
đã được khởi động.

Khởi động và Điều khiển Nội dung từ một Activity
Mặc dù hầu hết các điều khiển sẽ tự động, nhưng bạn vẫn sẽ cần khởi động và điều khiển media session từ các điều khiển bên trong ứng dụng của bạn. Ít nhất, bạn sẽ cần một MediaBrowserCompat.ConnectionCallback
, MediaControllerCompat.Callback
, MediaBrowserCompat
và các đối tượng MediaControllerCompat
được tạo ra trong ứng dụng của bạn.
MediaControllerCompat.Callback
sẽ có một phương thức được gọi là onPlaybackStateChanged()
nhận các thay đổi trong trạng thái phát nhạc và có thể được sử dụng để giữ cho giao diện của bạn được đồng bộ.
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
có một phương thức onConnected()
sẽ được gọi khi một đối tượng MediaBrowserCompat
mới được tạo và kết nối. Bạn có thể sử dụng phương thức này để khởi tạo đối tượng MediaControllerCompat
của bạn, liên kết nó với MediaControllerCompat.Callback
của bạn, và liên kết nó với MediaSessionCompat
từ Service
của bạn. Sau khi hoàn tất điều đó, bạn có thể bắt đầu phát âm thanh từ phương thức này.
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 ) { } } };
Bạn sẽ thấy rằng, đoạn code ở trên sử dụng phương thức getSupportMediaController().getTransportControls()
để giao tiếp với media session. Sử dụng kỹ thuật tương tự, bạn có thể gọi onPlay()
và onPause()
trong đối tượng MediaSessionCompat.Callback
của dịch vụ âm thanh của bạn.
if( mCurrentState == STATE_PAUSED ) { getSupportMediaController().getTransportControls().play(); mCurrentState = STATE_PLAYING; } else { if( getSupportMediaController().getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING ) { getSupportMediaController().getTransportControls().pause(); } mCurrentState = STATE_PAUSED; }
Khi bạn kết thúc việc phát nhạc, bạn có thể tạm dừng dịch vụ âm thanh và ngắt kết nối đối tượng MediaBrowserCompat
của bạn, cái mà chúng ta sẽ làm trong hướng dẫn này khi Activity
này bị hủy.
@Override protected void onDestroy() { super.onDestroy(); if( getSupportMediaController().getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING ) { getSupportMediaController().getTransportControls().pause(); } mMediaBrowserCompat.disconnect(); }
Tóm tắt
Ối chà! Như bạn có thể thấy, có rất nhiều bước các phần liên quan đến việc tạo và sử dụng một dịch vụ âm thanh nền một cách chính xác.
Trong hướng dẫn này, bạn đã tạo một Service để phát một tập tin âm thanh đơn giản, lắng nghe những thay đổi trong tập trung âm thanh, và các liên kết đến MediaSessionCompat
để cung cấp việc điều khiển phát nhạc chung trên các thiết bị Android, bao gồm các thiết bị cầm tay và Android Wear. Nếu bạn gặp phải các khó khăn khi thực hiện theo hướng dẫn này, thì tôi thành thật khuyên bạn nên xem qua code dự án Android được liên kết trên GitHub của Envato Tuts+.
Và kiểm tra một số các khóa học và hướng dẫn Android khác của chúng tôi ở đây trên Envato Tuts+!
- Android SDKCó gì mới trong Android N và Wear 2.0Paul Trebilcox-Ruiz
- Android SDKGoogle Play Services: Google Cast v3 và MediaPaul Trebilcox-Ruiz
- Android SDKChụp ảnh Với Ứng dụng Android Của bạnAshraff Hathibelagal
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post