android-studio - Android Studio、MediaPlayer 快进/快退无法正常工作
问题描述
我正在尝试在我的音乐播放器应用程序中创建快进和快退按钮。目前,当我点击快进按钮时,无论当前位置在哪里,它都会在歌曲中寻找相同的位置。倒带只是在 0 处重新开始歌曲。
在我看来,这里的 SONG_POSITION 始终为 0。seekForward 和 seekBackward = 5000 毫秒。因此 0 + seekForward 总是 == 5000ms,无论当前位置如何,都将歌曲位置移动到 5000ms。并且 0 - seekBackward 总是 == -5000ms,-5000ms < 持续时间,所以它从 0 开始歌曲。
快进:
fastForwardBtn!!.setOnClickListener {
refreshRecyclerView(false)
SONG_POSITION = getPosition(currentSong)
if (SONG_POSITION + seekForward <= mMediaPlayer!!.duration) {
mMediaPlayer!!.seekTo(SONG_POSITION + seekForward)
} else {
mMediaPlayer!!.seekTo(mMediaPlayer!!.duration)
}
}
倒带:
rewindBtn!!.setOnClickListener {
refreshRecyclerView(false)
SONG_POSITION = getPosition(currentSong)
if (SONG_POSITION - seekBackward >= mMediaPlayer!!.duration) {
mMediaPlayer!!.seekTo(SONG_POSITION - seekBackward)
} else {
mMediaPlayer!!.seekTo(0)
}
}
完整的 MainActivity,fwd/rwnd 在 handleEvents() 中大约一半:
package com.duncan.repea.ui.view
import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.Typeface
import android.media.MediaPlayer
import android.media.PlaybackParams
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.view.WindowManager
import android.widget.SeekBar
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.duncan.repea.data.model.Song
import com.duncan.repea.data.model.SongDao
import com.duncan.repea.databinding.ModelBinding
import com.duncan.repea.ui.viewmodel.SongsViewModel
import com.duncan.repea.utilities.constants.Constants
import com.duncan.repea.utilities.constants.Constants.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE
import com.duncan.repea.R
import info.camposha.pollux.PolluxAdapter
import kotlinx.android.synthetic.main.content_home.*
import java.util.ArrayList
class MainActivity : AppCompatActivity() {
private var hasFinished = false
private var currentSong: Song? = null
var mMediaPlayer: MediaPlayer? = null
var mHandler = Handler()
var adapter: PolluxAdapter<Song>? = null
private var sv: SongsViewModel? = null
var SONG_POSITION = 0
var seekForward = 5000
var seekBackward = 5000
var SONGS_CACHE = ArrayList<Song>()
var playbackParams = PlaybackParams()
private fun initializeViews() {
songsRV!!.layoutManager = LinearLayoutManager(this)
progressSPD.isEnabled = false
}
private fun getPosition(s: Song?): Int {
val pos = 0
for (song in SONGS_CACHE) {
if (s!!.id.equals(song.id, ignoreCase = true)) {
return SONGS_CACHE.indexOf(s)
}
}
return pos
}
private val player: MediaPlayer?
private get() {
if (mMediaPlayer == null) {
if (currentSong == null) {
currentSong = if (SONGS_CACHE.size > 0) {
SONGS_CACHE[0]
} else {
return null
}
}
mMediaPlayer = MediaPlayer.create(this, Uri.parse(currentSong!!.data))
}
return mMediaPlayer
}
private fun cleanUpMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer!!.release()
mMediaPlayer = null
}
}
private fun fetchAllSongs() {
sv!!.loadAllSongs(this).observe(this, Observer { requestCall: SongDao ->
val linkedHashSet = LinkedHashSet(requestCall.songs)
SONGS_CACHE.clear()
SONGS_CACHE.addAll(linkedHashSet)
SONGS_CACHE.sortWith(compareBy({ it.title }))
if (currentSong == null && SONGS_CACHE.size > 0) {
currentSong = SONGS_CACHE.get(0)
}
})
}
private fun checkPermissionsThenLoadSongs() {
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED
) {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE
)
show("Please allow external storage access")
} else {
fetchAllSongs()
}
}
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>,
grantedResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantedResults)
when (requestCode) {
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE -> {
if (grantedResults.size > 0
&& grantedResults[0] == PackageManager.PERMISSION_GRANTED
) {
fetchAllSongs()
// permission was granted, yay! Do the
// SONGS related task you need to do.
} else {
show("Please allow external storage access")
}
return
}
}
}
private fun playOrPause(song: Song) {
currentSong = song
if (player == null) {
show("Please add songs")
return
}
hasFinished = false
try {
songsRV.smoothScrollToPosition(getPosition(song))
} catch (e: Exception) {
}
if (player!!.isPlaying) {
sv!!.pause(player, this, song).observe(this, Observer { requestCall: SongDao ->
if (requestCall.status == Constants.STOPPED) {
progressSPD.isEnabled = false
song.isPlaying = false
refreshRecyclerView(song.isPlaying)
playBtn!!.setImageResource(R.drawable.ic_play)
waveLineView.stopAnim()
}
})
} else {
sv!!.play(player, this, song).observe(this, Observer { requestCall: SongDao ->
if (requestCall.status == Constants.PLAYING) {
progressSPD.isEnabled = true
song.isPlaying = true
SONG_POSITION = getPosition(song)
refreshRecyclerView(song.isPlaying)
playBtn!!.setImageResource(R.drawable.ic_pause)
waveLineView.startAnim()
updateSongProgress()
}
})
}
}
private fun handleEvents() {
playBtn!!.setOnClickListener {
if (currentSong != null) {
playOrPause(currentSong!!)
} else {
show("Please add songs")
}
}
nextBtn!!.setOnClickListener {
refreshRecyclerView(false)
SONG_POSITION = getPosition(currentSong) + 1
if (SONG_POSITION >= SONGS_CACHE.size) {
SONG_POSITION = 0
}
cleanUpMediaPlayer()
//keeps speedSeek at 100 when skipping
findViewById<TextView>(R.id.speedPercentage).text = "100"
progressSPD.progress = 100
val nextSong: Song = SONGS_CACHE.get(SONG_POSITION)
playOrPause(nextSong)
}
fastForwardBtn!!.setOnClickListener {
refreshRecyclerView(false)
SONG_POSITION = getPosition(currentSong)
if (SONG_POSITION + seekForward <= mMediaPlayer!!.duration) {
mMediaPlayer!!.seekTo(SONG_POSITION + seekForward)
} else {
mMediaPlayer!!.seekTo(mMediaPlayer!!.duration)
}
}
prevBtn!!.setOnClickListener {
refreshRecyclerView(false)
SONG_POSITION--
if (SONG_POSITION < 0) {
if (SONGS_CACHE.size > 0) {
SONG_POSITION = SONGS_CACHE.size - 1
} else {
SONG_POSITION = 0
}
}
//keeps speedSeek at 100 when skipping
findViewById<TextView>(R.id.speedPercentage).text = "100"
progressSPD.progress = 100
val prevSong: Song = SONGS_CACHE[SONG_POSITION]
cleanUpMediaPlayer()
playOrPause(prevSong)
}
rewindBtn!!.setOnClickListener {
refreshRecyclerView(false)
SONG_POSITION = getPosition(currentSong)
if (SONG_POSITION - seekBackward >= mMediaPlayer!!.duration) {
mMediaPlayer!!.seekTo(SONG_POSITION - seekBackward)
} else {
mMediaPlayer!!.seekTo(0)
}
}
progressSB!!.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
if (player == null) {
show("Please add songs")
return
}
mMediaPlayer!!.seekTo(
(sv!!.getTimeFromProgress(
seekBar.progress,
player!!.duration
))
)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
})
progressSPD!!.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
var speedPercentage = findViewById<TextView>(R.id.speedPercentage)
var progString = progress.toString()
speedPercentage.text = progString + "%"
var speed = (progress.toFloat()) / 100
mMediaPlayer!!.playbackParams = mMediaPlayer!!.playbackParams!!.setSpeed(speed)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
})
}
private fun refreshRecyclerView(playing: Boolean) {
if (currentSong != null && SONGS_CACHE.size > 0) {
currentSong!!.isPlaying = playing
val s = SONGS_CACHE.find { it.id == currentSong!!.id }
if (s != null) {
SONGS_CACHE[getPosition(s)] = currentSong!!
}
adapter!!.notifyDataSetChanged()
currentSongTV.text = currentSong!!.title
currentSongTV.marqueeRepeatLimit = -1
} else {
currentSongTV.text = "Repea"
}
}
//toast
private fun show(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun setupRecycler(songs: ArrayList<Song>) {
adapter =
PolluxAdapter.with<Song, ModelBinding>(R.layout.model) { adapterPosition, song, mb ->
//val color = mMaterialColors[Random().nextInt(mMaterialColors.size)]
//binding.root.setBackgroundColor(color)
mb.titleTV.text = song.title
if (song.isPlaying && !hasFinished) {
mb.playBtn.setImageResource(R.drawable.ic_pause)
mb.titleTV.setTextColor(Color.rgb(203, 167, 255))
mb.titleTV.setTypeface(null, Typeface.BOLD_ITALIC)
} else {
mb.playBtn.setImageResource(R.drawable.ic_play)
mb.titleTV.setTextColor(Color.GRAY)
mb.titleTV.setTypeface(null, Typeface.NORMAL)
if (hasFinished) {
mb.playBtn.setImageResource(R.drawable.ic_play)
mb.titleTV.setTextColor(Color.GRAY)
mb.titleTV.setTypeface(null, Typeface.NORMAL)
} else {
if (currentSong != null && currentSong!!.id === song.id) {
mb.playBtn.setImageResource(R.drawable.ic_play)
mb.titleTV.setTextColor(Color.rgb(203, 167, 255))
mb.titleTV.setTypeface(null, Typeface.NORMAL)
}
}
}
mb.playBtn.setOnClickListener { view: View? ->
if (!song.isPlaying) {
if (SONG_POSITION != getPosition(song)) {
if (mMediaPlayer != null) {
mMediaPlayer!!.release()
mMediaPlayer = null
}
}
SONG_POSITION = getPosition(song)
if (currentSong != null) {
currentSong!!.isPlaying = false
adapter!!.notifyDataSetChanged()
}
currentSong = SONGS_CACHE.get(SONG_POSITION)
playOrPause(song)
show("Now Playing: " + song.title)
mb.playBtn.setImageResource(android.R.drawable.ic_media_pause)
mb.titleTV.setTextColor(Color.GREEN)
mb.titleTV.setTypeface(null, Typeface.ITALIC)
} else {
if (SONG_POSITION != getPosition(song)) {
if (mMediaPlayer != null) {
mMediaPlayer!!.release()
mMediaPlayer = null
}
}
SONG_POSITION = getPosition(song)
show("Stopped: " + song.title)
playOrPause(song)
mb.playBtn.setImageResource(android.R.drawable.ic_media_play)
mb.titleTV.setTextColor(Color.RED)
mb.titleTV.setTypeface(null, Typeface.ITALIC)
//adapter!!.notifyDataSetChanged()
}
}
}
songsRV.layoutManager = GridLayoutManager(this@MainActivity, 2)
adapter!!.addAll(songs)
songsRV!!.adapter = adapter
}
private fun updateSongProgress() {
mHandler.postDelayed(runnable, 1000)
}
private var runnable: Runnable = object : Runnable {
override fun run() {
if (!hasFinished) {
if (mMediaPlayer == null) {
return
}
val currentDuration = mMediaPlayer!!.currentPosition
val totalDuration = mMediaPlayer!!.duration
currentPosTV!!.text = sv!!.convertToTimerMode(currentDuration.toString())
progressSB!!.progress = sv!!.getSongProgress(totalDuration, currentDuration)
totalDurationTV!!.text = sv!!.convertToTimerMode(totalDuration.toString())
if (progressSB!!.progress >= 99 && !mMediaPlayer!!.isPlaying) {
playBtn!!.setImageResource(android.R.drawable.ic_media_play)
hasFinished = true
adapter!!.notifyDataSetChanged()
// show("Finished");
//Click Next to play next song
nextBtn!!.performClick()
} else {
hasFinished = false
}
mHandler.postDelayed(this, 1000)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//keeps screen from locking
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
sv = ViewModelProvider(this).get(SongsViewModel::class.java)
initializeViews()
handleEvents()
}
override fun onResume() {
super.onResume()
if (SONGS_CACHE.isEmpty()) {
checkPermissionsThenLoadSongs()
setupRecycler(SONGS_CACHE)
}
}
override fun onPause() {
super.onPause()
if (currentSong != null && currentSong!!.isPlaying) {
currentSong!!.isPlaying = false
playOrPause(currentSong!!)
}
cleanUpMediaPlayer()
}
override fun onStop() {
super.onStop()
SONGS_CACHE.clear()
cleanUpMediaPlayer()
}
override fun onDestroy() {
super.onDestroy()
waveLineView.release()
}
}
任何帮助,将不胜感激。
解决方案
我不知道你为什么不使用 currentPosition() 方法来获取当前播放歌曲的位置,而不是你的方法 getPosition() 尝试使用这个..
SONG_POSITION = mMediaPlayer!!.currentPosition
看看这里了解更多.. https://developer.android.com/reference/android/media/MediaPlayer#getCurrentPosition()
推荐阅读
- c# - 如何为 SonarQube 创建自己的 C# 自定义规则?
- javascript - 量角器中的 by.tagName 与 by.css
- dns - 为什么我不能在我的 CentOS VPS 上与 tcp/3000 上的服务通话
- javascript - JSON 两次返回 url
- python - Ubuntu 18.04 上的张量流
- javascript - 从文件中获取日期,而不是在 js 文件中声明它
- php - 流明中间件排序(优先级)
- batch-file - 如何将多个文件夹复制到目录名称为当前年份和月份的新目录?
- python - 使用 BioPython 读取 fasta 文件时如何修复“生成器”对象不可下标”错误
- python - 如何一次读取多个文本文件并使用数据?