Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Android SDK
Code

Âm thanh Nền trong Android Với MediaSessionCompat

by
Difficulty:BeginnerLength:LongLanguages:

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).

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.OnCompletionListenerAudioManager.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.

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).

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.

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.

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.

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.

Đố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.

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()onLoadChildren(). Bạn có thể sử dụng code sau đây cho các hàm mặc định của bạn.

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.

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().

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.

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.

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.

Đ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, MediaSessionCompatMediaPlayer, đã đế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.

Đ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.

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:

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.

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.

Điều quan trọng cần phải lưu ý là bạn sẽ cần cả cờ ACTION_PLAY_PAUSEACTION_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.

Media notification on 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 đó.

Cuối cùng, bạn sẽ khởi động MediaPlayer vào cuối của phương thức onPlay().

Media control notification on an Android Nougat device

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.

Phương thức trợ giúp showPausedNotification() của chúng ta sẽ tương tự như phương thức showPlayNotification().

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 StringBundle. Đâ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.

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.

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.

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.

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.

Media lock screen controls on Android Kit Kat

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ộ.

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.

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()onPause() trong đối tượng MediaSessionCompat.Callback của dịch vụ âm thanh của bạn.

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.

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ọchướng dẫn Android khác của chúng tôi ở đây trên Envato Tuts+!


Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.