Detailed explanation of Android MediaPlayer audio player, tearful finishing experience

Posted by kabucek on Fri, 17 Dec 2021 00:58:04 +0100

  • stop() stops playback

  • prepare() resource preparation

  • prepareAsync() prepares asynchronously and does not block UI threads

  • seekTo(int msec) locates the specified location in milliseconds

  • Is isLooping looping

  • Isplayingplayback status

  • Duration total duration

  • currentPosition current position

  • release() resource release

Component Tree

=========================================================================

The specific xml code will not be posted. Take a look at the component tree

initialization

==============================================================

    /**

     * Initialization and resource preparation

     */

    private fun audioPrepare(path: String) { 

        mMediaPlayer = MediaPlayer().apply {

            setDataSource(path)//Support file, network address, uri

            prepareAsync()//Asynchronous preparation without blocking UI threads

            isLooping = false//Loop Playback

        }



        initMediaPlayerListener()

    }



setDataSource, set the data source, support local files, network requested addresses, URIs, etc. take a look at the source code:

  • setDataSource(FileDescriptor)

  • setDataSource(String)

  • setDataSource(Context, Uri)

  • setDataSource(FileDescriptor, long, long)

  • setDataSource(MediaDataSource)

If it is a local file, pay attention to read and write permissions.

prepareAsync() prepares asynchronously and does not block UI threads

Then look at the initMediaPlayerListener method called

Player monitoring events and interaction

=====================================================================

    /**

     * Player listening events

     */

    private fun initMediaPlayerListener() {



        mMediaPlayer?.setOnBufferingUpdateListener { mp, percent ->

            LogUtil.i("Buffer progress $percent%")

        }



        mMediaPlayer?.setOnPreparedListener {

            LogUtil.i("Ready to finish")

            //Get the information after the preparation is completed, otherwise there will be exceptions 

            val duration = mMediaPlayer?.duration//duration

            val currentPosition = mMediaPlayer?.currentPosition//current location

            LogUtil.i("current location $currentPosition/duration $duration")



            tv_currentPosition.text = formatDuration(currentPosition!!)

            tv_duration.text = formatDuration(duration!!)



            seek_bar.max = duration

        }



        mMediaPlayer?.setOnCompletionListener {

            LogUtil.i("Play complete")

        }



        mMediaPlayer?.setOnErrorListener { mp, what, extra ->

            LogUtil.i("Playback error")

            return@setOnErrorListener true

        }



        mMediaPlayer?.setOnSeekCompleteListener {

            LogUtil.i("Positioning complete")

        }



        seek_bar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {

            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {

                tv_currentPosition.text = formatDuration(seekBar!!.progress)

            }



            override fun onStartTrackingTouch(seekBar: SeekBar?) {

            }



            override fun onStopTrackingTouch(seekBar: SeekBar?) {

                //Set after dragging. If it is set in onProgressChanged, there will be noise

                mMediaPlayer?.seekTo(seekBar!!.progress)

                tv_currentPosition.text = formatDuration(seekBar!!.progress)

            }

        })



        btn_start.setOnClickListener {

            audioStart()

        }

        btn_pause.setOnClickListener {

            audioPause()

        }

        btn_seek.setOnClickListener {

            seek_bar.progress = (seek_bar.max * 0.8).roundToInt()

            mMediaPlayer?.seekTo(seek_bar!!.progress)

            tv_currentPosition.text = formatDuration(seek_bar!!.progress)

            audioStart()

        }

        btn_restart.setOnClickListener {

            audioRestart()

        }

    }



It is mainly some player listening events and button operation events.

https://blog.csdn.net/yechaoa

Focus on two:

[](

)1,setOnPreparedListener

Note that when obtaining the resource length, you need to obtain it after the player is ready, otherwise there will be exceptions:

Attempt to call getDuration in wrong state: mPlayer=0x7244676280, mCurrentState=4

error (-38, 0)



And will call back OnErrorListener.

Then set the display and assign the duration to seek_ Maximum value of bar.

[](

)2,setOnSeekBarChangeListener

3 methods:

  • onProgressChanged

  • onStartTrackingTouch starts dragging

  • onStopTrackingTouch stop dragging

We need to update the current playback duration during and after the change, and play at the last position.

If the program does not locate the specified playback position, do not perform playback in onProgressChanged, because there will be noise due to frequent progress changes and frequent call playback.

Therefore, it is recommended that users manually drag to trigger playback.

If you want the program to skip to the specified location for playback, the following operations are recommended:

        btn_seek.setOnClickListener {

            seek_bar.progress = (seek_bar.max * 0.8).roundToInt()

            mMediaPlayer?.seekTo(seek_bar!!.progress)

            tv_currentPosition.text = formatDuration(seek_bar!!.progress)

            audioStart()

        }



Manually assign progress and call play.

[](

)Format playback time

This fetch duration returns milliseconds, so we need to format it.

    /**

     * Format playback time

     */

    private fun formatDuration(duration: Int): String {

        val d = duration / 1000

        val minute = d / 60

        val second = d % 60

        val m: String = if (minute < 10) "0$minute" else "$minute"

        val s: String = if (second < 10) "0$second" else "$second"

        return "$m:$s"

    }



After making a judgment, if it is less than two digits, the first digit shall be supplemented with 0.

Start playing

===============================================================

    /**

     * Start playing

     */

    private fun audioStart() {

        mMediaPlayer?.run {

            if (!this.isPlaying) {

                start()

                startTimer()

            }

        }

    }



Because there is no callback interface in playback, a Timer is started here to get the current location and update the UI

[](

)Timer update UI

    /**

     * Execute every second to update the current playback time

     */

    private fun startTimer() {

        mTimer = Timer().apply {

            schedule(object : TimerTask() {

                override fun run() {

                    //Non ui threads cannot update the view, so the value here is assigned to seek_bar, in seek_ Update in the event of bar

                    seek_bar.progress = mMediaPlayer!!.currentPosition

                    //tv_currentPosition.text = formatDuration(mMediaPlayer!!.currentPosition)

                }

            }, 0, 1000)

        }

    }



Note that non ui threads cannot update the view, so it is assigned to seek_bar, in seek_bar is updated in the onProgressChanged callback.

Pause playback

===============================================================

    /**

     * Pause playback

     */

    private fun audioPause() {

        mMediaPlayer?.run {

            if (this.isPlaying) {

                pause()

                cancelTimer()

            }

        }
#### last

**Code is really a high-quality code, which is advocated by the current code industry. Of course, writing high-quality code certainly requires a very high professional quality, which needs to be gradually absorbed and mastered in daily code writing. Who is not learning every day? The purpose is not to write high-quality code for a function.**

Therefore, the long march road is still long. We'd better be a Pragmatic Programmer.

Finally, Xiaobian has a series here Android To improve the learning materials, interested friends can have a look~

**[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://codechina.csdn.net/m0_60958482/android_p7)**

Topics: Android Design Pattern