Building a simple audio app in Android (Part 3/3)

Synchronizing with the SeekBar

Nazmul Idris (Naz)
Android Developers
4 min readAug 22, 2017

--

Introduction

The goal of this series of articles is to get you started with the Android MediaPlayer API by going thru the journey of creating a very basic audio playback application called “A Simple MediaPlayer” app. This is the last part of a 3 part series that includes:

  1. MediaPlayer introduction
  2. Building the app
  3. Synchronizing with the SeekBar (this article)

Part 3/3 — Synchronizing with the SeekBar

This article will cover the following:

  • How to synchronize the audio playback position, and duration with a SeekBar.
  • How to use the SeekBar to jump to different time positions in the audio during playback.

What does the app look like, and where is the source code?

Please checkout Part 2 of the series to see the app in action, and get the source on GitHub.

Synchronize with Seekbar

The app’s UI also has a SeekBar. This does 2 things:

  1. It provides visual feedback to the user as media playback is progressing (by moving the scrubber in the SeekBar forwards as audio plays).
  2. Allows the user to jump to any specific time location in the media by touching and dragging the scrubber. This ends up calling seekTo() in the MediaPlayer to change its audio playback position.

1. Scrubber updating the UI to reflect playback position — PlaybackInfoListener interface

In order for the MediaPlayerHolder to provide updates to the UI (in MainActivity) that the playback position is progressing, the PlaybackInfoListener interface is used. The MainActivity implements this callback. It allows the MediaPlayerHolder and MainActivity to be decoupled.

  1. The MediaPlayerHolder reports its progress and duration, without concerning itself with how the UI displays this information.
  2. The MediaPlayerHolder also reports its current state (which can be PLAYING, PAUSED, RESET, COMPLETED).
  3. The MainActivity takes care of displaying the duration and progress in the UI via the SeekBar.

1.1. Setting the SeekBar max to match the playback duration

The SeekBar is used to display a range of values along a horizontal line. To configure the SeekBar (which is the MainActivity) we need to tell it what its maximum value should be. In our simple app, we will set the maximum value to the duration of our audio track in milliseconds. This happens in the MediaPlayerHolder as follows after the MediaPlayer is created, and the MP3 file is loaded.

1.2. Provide visual feedback as audio playback progresses

As the audio playback progresses, the SeekBar’s setProgress(time) method has to be called with the amount of time that has elapsed during playback. There’s no listener that can be attached to the MediaPlayer to get this information, so we have to poll. There are 2 strategies for polling — using Handler, or Executor. This app uses an Executor as it makes the code easier to read.

An SingleThreadScheduledExecutor dispatches a Runnable to execute every 500 ms (PLAYBACK_POSITION_REFRESH_INTERVAL_MS). This means that at this regular interval this task is executed which paints the UI with the current position of MediaPlayer position. You can try changing this to different numbers and press the PLAY button to see how this changes the UI behavior.

2. User moving the scrubber — PlayerAdapter interface

In order to change the playback position you can use the the PlayerAdapter interface. The MediaPlayerHolder implements this interface, and here’s what it looks like partially.

2.1. Jump to any position in the media using seekTo

While the app is playing audio, if the user drags the scrubber in the SeekBar (in MainActivity), two things have to happen:

  1. The Executor that was running to provide playback progress updates has to be terminated. Otherwise it will move the scrubber and fight with the user as they are trying to move the scrubber themselves.
  2. Once, the user completes dragging the scrubber, the position must be reported to the MediaPlayer using seekTo().

Methods to handle both of these situations are provided in the PlayerAdapter interface, which is implemented by MediaPlayerHolder.

Here’s the code from MainActivity where the case of the user moving the scrubber is handled. Note: mPlayerAdapter is of type PlayerAdapter, which is an interface implemented by MediaPlayerHolder.

State Machine

The MediaPlayer has a sophisticated state machine. You don’t need to fully understand it to get started. For deeper integration into MediaPlayer’s capabilities, please refer to the state machine diagram on developers.android.com.

Android Media Resources

--

--

Nazmul Idris (Naz)
Android Developers

Google SWE, entrepreneur, leader, designer, dancer, TaiChi'er, Yogi, racer, healer, storyteller. I ❤️ leadership, authenticity, empowerment, & lifelong learning