美文网首页
自定义MediaPlayer音频播放器

自定义MediaPlayer音频播放器

作者: 丿沧海一粟丿 | 来源:发表于2018-12-26 16:54 被阅读0次

    做安卓家用镜项目,自定义一款播放器,方便以后修改。
    包括功能

    0、查询本地所有音乐,筛选小于30s的音频文件;

    1、播放、暂停;

    2、上一曲、下一曲;

    3、随机、顺序播放;

    4、当前播放时间、总时间、进度条显示;

    5、进度条拖动播放;

    封装模型

    data class MediaEntity (
    
            var id: Int?,
    
            var title: String?,
    
            var displayName: String?,
    
            var path: String?,
    
            var duration: Int?,
    
            var albums: String?,
    
            var artist: String?,
    
            var singer: String?,
    
            var size: Long?
    
    ): Serializable
    

    封装为anko使用

    inline fun ViewManager.lfmusicPlayer() = lfmusicPlayer() {}
    
    inline fun ViewManager.lfmusicPlayer(init: LFMusicPlayer.() -> Unit): LFMusicPlayer {
    
        return ankoView({ LFMusicPlayer(it) },0,init)
    
    }
    
    image.png

    播放器

    class LFMusicPlayer: FrameLayout {
    
        object ViewID {
    
            val dt = 181251758
    
            val name = dt + 101
    
            val play = dt + 102
    
            val progress = dt + 103
    
            val currentTime = dt + 104
    
            val totalTime = dt + 105
    
            val random = dt + 106
    
        }
    
        enum class PlayControl {
    
            PLAY, NEXT, PREVIOUS
    
        }
    
        private var progressTimer: Timer? = null
    
        private var isRecycle = false
    
        private var mediaPlayer = MediaPlayer()
    
        private var cnt: Context
    
        private var currentIndex = -1
    
        private var currentPosition = 0
    
        private var musicList: List<MediaEntity> = ArrayList<MediaEntity>()
    
        constructor(context: Context) : this(context, null)
    
        constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    
        constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) {
    
            this.cnt = context
    
            //UI
    
            verticalLayout {
    
                linearLayout {
    
                    imageView {
    
                        imageResource = R.mipmap.ic_random
    
                        id = ViewID.random
    
                        onClick { randomOrReclycle() }
    
                    }.lparams(dip(0), matchParent) {
    
                        weight = 1f
    
                        margin = dip(5)
    
                    }
    
                    imageView {
    
                        imageResource = R.mipmap.ic_previous
    
                        onClick {
    
                            playLocalMusic(PlayControl.PREVIOUS)
    
                        }
    
                    }.lparams(dip(0), matchParent) {
    
                        weight = 1f
    
                        margin = dip(5)
    
                    }
    
                    imageView {
    
                        imageResource = R.mipmap.ic_play
    
                        id = ViewID.play
    
                        onClick {
    
                            playLocalMusic(PlayControl.PLAY)
    
                        }
    
                    }.lparams(dip(0), matchParent) {
    
                        weight = 1f
    
                        margin = dip(5)
    
                    }
    
                    imageView {
    
                        imageResource = R.mipmap.ic_next
    
                        onClick {
    
                            playLocalMusic(PlayControl.NEXT)
    
                        }
    
                    }.lparams(dip(0), matchParent) {
    
                        weight = 1f
    
                        margin = dip(5)
    
                    }
    
                    imageView {
    
                        imageResource = R.mipmap.ic_list
    
                    }.lparams(dip(0), matchParent) {
    
                        weight = 1f
    
                        margin = dip(5)
    
                    }
    
                }.lparams(matchParent, dip(0)) {
    
                    weight = 1f
    
                    leftMargin = dip(20)
    
                    rightMargin = dip(20)
    
                }
    
                linearLayout {
    
                    textView {
    
                        id = ViewID.name
    
                        textSize = 17f
    
                        textColor = Color.WHITE
    
    //                    text = musicList[currentIndex].displayName.toString()
    
                    }.lparams(wrapContent, wrapContent)
    
                }.lparams(matchParent, dip(0)) {
    
                    weight = 1f
    
                    leftMargin = dip(20)
    
                    rightMargin = dip(20)
    
                }
    
                linearLayout {
    
                    //2020110
    
                    textView {
    
                        textSize = 12f
    
                        textColor = Color.WHITE
    
                        text = "0:0"
    
                        id = ViewID.currentTime
    
                    }.lparams(dip(0), matchParent) {
    
                        weight = 2f
    
                    }
    
                    seekBar {
    
    //                    progressDrawable = context.resources.getDrawable(R.drawable.seek_bar_progress, null)
    
    //                    thumb = context.resources.getDrawable(R.drawable.seek_bar_thumb, null)
    
                        id = ViewID.progress
    
                        max = 100
    
                        progress = 0
    
    //                    secondaryProgress = 80
    
                        isIndeterminate = false
    
                    }.lparams(dip(0), wrapContent) {
    
                        weight = 11f
    
                    }
    
                    textView {
    
                        textSize = 12f
    
                        textColor = Color.WHITE
    
    //                    text = "4:32"
    
                        id = ViewID.totalTime
    
                    }.lparams(dip(0), matchParent) {
    
                        weight = 2f
    
                    }
    
                }.lparams(matchParent, dip(0)) {
    
                    weight = 1f
    
                    leftMargin = dip(20)
    
                    rightMargin = dip(20)
    
                }
    
            }
    
            this.localMusicData()
    
            this.seekBarChangeAction()
    
        }
    
        private fun randomOrReclycle() {
    
            this.isRecycle = !this.isRecycle
    
            val iv = find<ImageView>(ViewID.random)
    
            doAsync { uiThread {
    
                if (isRecycle) {
    
                    iv.imageResource = R.mipmap.ic_recycle
    
                }else {
    
                    iv.imageResource = R.mipmap.ic_random
    
                }
    
            } }
    
        }
    
        private fun seekBarChangeAction() {
    
            val seekBar = find<SeekBar>(ViewID.progress)
    
            val tv = find<TextView>(ViewID.currentTime)
    
            seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
    
                override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
    
                }
    
                override fun onStartTrackingTouch(p0: SeekBar?) {
    
                }
    
                override fun onStopTrackingTouch(p0: SeekBar?) {
    
                    currentPosition = ((p0?.progress!!.toFloat()/100)*mediaPlayer.duration.toFloat()).toInt()
    
                    playLocalMusic(PlayControl.PLAY, true)
    
                }
    
            })
    
        }
    
        private fun localMusicData() {
    
            this.musicList = this.getAllMediaList()
    
            if (this.musicList.count() < 1) {
    
                currentIndex = -1
    
            }else {
    
                currentIndex = 0
    
            }
    
            this.displayMusicName(currentIndex)
    
        }
    
        //显示歌名
    
        private fun displayMusicName(index: Int) {
    
            val tv = find<TextView>(ViewID.name)
    
            val totalTv = find<TextView>(ViewID.totalTime)
    
            if (index < 0) {
    
                tv.text = "没有本地音乐"
    
            }else {
    
                tv.text = this.musicList[index].displayName.toString()
    
                val m = (this.musicList[index].duration!!/1000)/60
    
                val s = (this.musicList[index].duration!!/1000)%60
    
                totalTv.text = m.toString() + ":" + s.toString()
    
            }
    
            //一定要实现此错误处理方法,否则会很多时候比如reset()调用OnCompletion方法!!!
    
            this.mediaPlayer.setOnErrorListener(object : MediaPlayer.OnErrorListener {
    
                override fun onError(p0: MediaPlayer?, p1: Int, p2: Int): Boolean {
    
                    return true
    
                }
    
            })
    
            this.mediaPlayer.setOnCompletionListener(object : MediaPlayer.OnCompletionListener {
    
                override fun onCompletion(p0: MediaPlayer?) {
    
                    playLocalMusic(PlayControl.NEXT)
    
                }
    
            })
    
        }
    
        //获取本地(不包括SD卡)的音乐文件
    
        private fun getAllMediaList(): List<MediaEntity> {
    
            var cursor: Cursor? = null
    
            var mediaList = ArrayList<MediaEntity>()
    
            try {
    
                cursor = cnt.contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null,
    
                        null, MediaStore.Audio.AudioColumns.IS_MUSIC)
    
                if (cursor == null) {
    
                    return mediaList
    
                }
    
                var count = cursor.count
    
                if (count <= 0) {
    
                    return mediaList
    
                }
    
                mediaList = ArrayList()
    
                var mediaEntity: MediaEntity
    
                while (cursor.moveToNext()) {
    
                    mediaEntity = MediaEntity(null, null, null, null, null, null, null, null, null)
    
                    mediaEntity.id = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media._ID))
    
                    mediaEntity.title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE))
    
                    mediaEntity.displayName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME))
    
                    mediaEntity.duration = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION))
    
                    mediaEntity.size = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE))
    
                    if (!checkIsMusic(cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION)), cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE)))) {
    
                        continue
    
                    }
    
                    mediaEntity.artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))
    
                    mediaEntity.path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))
    
                    mediaList.add(mediaEntity)
    
                }
    
            }catch (e: Exception) {
    
            }finally {
    
                if (cursor != null) {
    
                    cursor.close()
    
                }
    
            }
    
            return mediaList
    
        }
    
        fun checkIsMusic(time: Int, size: Long): Boolean {
    
            if (time <= 0 || size <= 0) {
    
                return false
    
            }
    
            var time = time/1000
    
            var minute = time/60
    
            var second = time%60
    
            minute %= 60
    
            if (minute <= 0 && second <= 30) {
    
                return false
    
            }
    
            if (size <= 1024 * 1024) {
    
                return false
    
            }
    
            return true
    
        }
    
        //判断本地是否有音乐,再进行播放选择
    
        private fun playLocalMusic(control: PlayControl, isSeekBar: Boolean? = false) {
    
            if (this.musicList.count() < 1) {
    
                val builder = AlertDialog.Builder(this.cnt)
    
                builder.setTitle("没有本地音乐").create().show()
    
            }else {
    
                var index: Int
    
                when (control) {
    
                    PlayControl.PLAY -> {
    
                        //是否第一次播放
    
                        if (currentIndex < 0) currentIndex = 0
    
                        //判断是暂停还是播放操作
    
                        if (this.mediaPlayer.isPlaying && (!isSeekBar!!)) {
    
                            this.mediaPlayer.pause()
    
                            currentPosition = this.mediaPlayer.currentPosition
    
                            this.playStateChange()
    
                        }else {
    
                            this.playAssignMusic(currentIndex)
    
                        }
    
                    }
    
                    PlayControl.NEXT -> {
    
                        if (isRecycle) {
    
                            currentIndex += 1
    
                        }else {
    
                            //随机
    
                            currentIndex = (0..(this.musicList.count()-1)).shuffled().last()
    
                        }
    
                        index = currentIndex%this.musicList.count()
    
                        currentPosition = 0
    
                        this.playAssignMusic(index)
    
                    }
    
                    PlayControl.PREVIOUS -> {
    
                        currentIndex -= 1
    
                        if (currentIndex < 0) {
    
                            currentIndex += this.musicList.count()
    
                        }
    
                        index = currentIndex%this.musicList.count()
    
                        currentPosition = 0
    
                        this.playAssignMusic(index)
    
                    }
    
                }
    
            }
    
        }
    
        //播放指定音乐
    
        private fun playAssignMusic(index: Int) {
    
    //        AlertDialog.Builder(this.cnt).setTitle("播放开始" + index.toString()).show()
    
            try {
    
                // 切歌之前先重置,释放掉之前的资源。注意:reset会触发OnCompletion监听方法!!!
    
                this.mediaPlayer.reset()
    
                this.mediaPlayer.setDataSource(this.musicList[index].path)
    
                this.mediaPlayer.prepareAsync()
    
                //装载完毕,开始播放
    
                this.mediaPlayer.setOnPreparedListener(object : MediaPlayer.OnPreparedListener {
    
                    override fun onPrepared(p0: MediaPlayer?) {
    
                        //记忆播放
    
                        mediaPlayer.seekTo(currentPosition)
    
                        mediaPlayer.start()
    
                        //变更歌名
    
                        doAsync {
    
                            uiThread {
    
                                displayMusicName(index)
    
                                playStateChange()
    
                            }
    
                        }
    
                    }
    
                })
    
                currentIndex = index
    
            }catch (e: Exception) {
    
                doAsync { uiThread {
    
                    AlertDialog.Builder(cnt).setTitle("播放错误").create().show()
    
                } }
    
            }
    
        }
    
        private fun playStateChange() {
    
            val img = find<ImageView>(ViewID.play)
    
            if (this.mediaPlayer.isPlaying) {
    
                img.imageResource = R.mipmap.ic_stop
    
                //进度设置
    
                playingProgress()
    
            }else {
    
                img.imageResource = R.mipmap.ic_play
    
                //暂停显示操作
    
                stopProgressTimer()
    
            }
    
            //总时长只设置一次
    
            val tv = find<TextView>(ViewID.totalTime)
    
            val m = (this.mediaPlayer.duration/1000)/60
    
            val s = (this.mediaPlayer.duration/1000)%60
    
            tv.text = m.toString() + ":" + s.toString()
    
        }
    
        private fun playingProgress() {
    
            val tv = find<TextView>(ViewID.currentTime)
    
            val seekBar = find<SeekBar>(ViewID.progress)
    
            //定时器,1秒获取一次
    
            if (progressTimer == null) {
    
                progressTimer = Timer()
    
            }
    
            val task = object : TimerTask() {
    
                override fun run() {
    
                    //获取当前播放位置
    
                    val m = (mediaPlayer.currentPosition/1000)/60
    
                    val s = (mediaPlayer.currentPosition/1000)%60
    
                    val progress = (mediaPlayer.currentPosition.toFloat()/mediaPlayer.duration.toFloat())
    
                    doAsync { uiThread {
    
                        tv.text = m.toString() + ":" + s.toString()
    
                        seekBar.progress = (progress*100).toInt()
    
                    } }
    
                }
    
            }
    
            progressTimer?.schedule(task, 0, 1000)
    
        }
    
        private fun stopProgressTimer() {
    
            progressTimer?.cancel()
    
            progressTimer = null
    
        }
    
    }
    

    相关文章

      网友评论

          本文标题:自定义MediaPlayer音频播放器

          本文链接:https://www.haomeiwen.com/subject/nctklqtx.html