我有这个媒体播放器,其他一切正常,我开始播放这首歌,它通过2个州,最后一个是PlaybackStateCompat.STATE_PLAYING
因此我们可以说回调已注册。问题是每当我触发SeekBar监听器时,方法seekTo
都不会触发onPlaybackStateChanged
,因为这不会发生,我无法将SeekBar更新为新的进度。这仅涉及UI。在修改SeekBar进度后,音乐实际上是从进度中播放的。而且,trackDurationTextView也不会更新。当我将拇指拖过搜索栏时它会改变它的值,但是一旦我释放它,它就会进入初始进度,与搜索栏相同。
这是注册回调的地方。
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
if (service instanceof MediaPlayerService.ServiceBinder) {
try {
mediaController = new MediaControllerCompat(this, ((MediaPlayerService.ServiceBinder) service).getService().getMediaSessionToken());
} catch (RemoteException e) {
e.printStackTrace();
}
mediaController.registerCallback(mMediaControllerCallback);
}
}
这是回调初始化的方式:
private MediaControllerCompat.Callback mMediaControllerCallback = new MediaControllerCompat.Callback() {
@Override
public void onPlaybackStateChanged(@NonNull PlaybackStateCompat state) {
updatePlaybackState(state);
}
@Override
public void onMetadataChanged(MediaMetadataCompat metadata) {
if (metadata != null) {
updateMediaDescription(metadata.getDescription());
updateDuration(metadata);
}
}
};
这是OnSeekBarChangeListener
trackSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
trackDurationTextView.setText(DateUtils.formatElapsedTime(progress / 1000));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
stopSeekbarUpdate();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//TODO: look here! the seek bar position is not kept when the user slides it!
mediaController.getTransportControls().seekTo(seekBar.getProgress());
scheduleSeekBarUpdate();
}
});
private void updateProgress() {
if (mLastPlaybackState == null) {
return;
}
long currentPosition = mLastPlaybackState.getPosition();
if (mLastPlaybackState.getState() != PlaybackStateCompat.STATE_PAUSED) {
// Calculate the elapsed time between the last position update and now and unless
// paused, we can assume (delta * speed) + current position is approximately the
// latest position. This ensure that we do not repeatedly call the getPlaybackState()
// on MediaControllerCompat.
long timeDelta = SystemClock.elapsedRealtime() -
mLastPlaybackState.getLastPositionUpdateTime();
currentPosition += (int) timeDelta * mLastPlaybackState.getPlaybackSpeed();
}
trackSeekBar.setProgress((int) currentPosition);
}
这是更新搜索栏后mLastPlayBackState.getPosition应返回新值的位置,但它始终返回0,因为onPlaybackStateChanged永远不会被调用。有什么想法吗?
答案 0 :(得分:2)
MediaControllerCompat.Callback.onPlaybackStateChanged(PlaybackStateCompat state)
只有MediaSessionCompat
的{{1}} PlaybackStateCompat
更改才会调用state
。如果PlaybackStateCompat
的{{1}}在position
保持不变的情况下发生变化,则state
永远不会被调用。我假设“onPlaybackStateChanged”,API更具体地指的是onPlaybackStateChanged(...)
的{{1}}而不是PlaybackStateCompat
本身。
要解决此问题,我会在搜索命令后暂时将state
的{{1}}更新为PlaybackStateCompat
或PlaybackStateCompat
,以便在用户界面上触发state
这样我就可以将PlaybackStateCompat.STATE_REWINDING
的位置和已用时间PlaybackStateCompat.STATE_FAST_FORWARDING
的文本更新到新的播放位置。
更新:我无法再重现此问题。我不确定我究竟改变了什么来修复它。我的第一个建议是验证您是否在onPlaybackStateChanged(...)
对象SeekBar
上调用TextView
,其中setState(state)
是包含更新后的mediaSession
值的state
。这对我来说不是解决方案,但它是我首先要看的地方。
答案 1 :(得分:0)
我也遇到了这个问题并找到了一个有效的解决方案。基本上,正如Ryan所说,你需要调用MediaSession或MediaSessionCompat的setPlaybackState()。我的项目基于Google's older Android Music Player Codelab Github repo,因此我使用回放管理器跟踪MediaPlayer,并在状态发生变化时进行回调。因此,当管理器的seekTo()被调用时,它通过回调将状态发送到MusicService(MediaBrowserServiceCompat的子类),它跟踪MediaSessionCompat。 session.setPlaybackState(state)实际上是下面MusicService.kt中的关键行。
PlaybackManager.kt:
class PlaybackManager(private val context: Context, private val callback: Callback)
: AudioManager.OnAudioFocusChangeListener, MediaPlayer.OnCompletionListener {
/* A bunch of stuff not important to this answer goes here */
/* mediaPlayer gets set to a MediaPlayer at some point */
fun seekTo(position: Long) {
mediaPlayer?.seekTo(position, MediaPlayer.SEEK_CLOSEST_SYNC)
updatePlaybackState()
}
private fun updatePlaybackState() {
callback.onPlaybackStatusChanged(PlaybackStateCompat.Builder()
.setActions(getAvailableActions())
.setState(state, getCurrentStreamPosition().toLong(),
1.0f, SystemClock.elapsedRealtime())
.build())
}
interface Callback {
fun onPlaybackStatusChanged(state: PlaybackStateCompat)
}
}
MusicService.kt:
class MusicService : MediaBrowserServiceCompat() {
private lateinit var session: MediaSessionCompat
private lateinit var playback: PlaybackManager
val callback = object: MediaSessionCompat.Callback() {
/* Other methods like onPlay() and onPause() go here */
override fun onSeekTo(pos: Long) {
playback.seekTo(pos)
}
}
override fun onCreate() {
super.onCreate()
session = MediaSessionCompat(this, "MusicService")
session.setCallback(callback)
sessionToken = session.sessionToken
playback = PlaybackManager(this, object: PlaybackManager.Callback {
override fun onPlaybackStatusChanged(state: PlaybackStateCompat) {
session.setPlaybackState(state)
}
})
}
/* Other methods like onDestroy(), onGetRoot() and onLoadChildren() go here */
}
要查看的更有用的代码是the Google Universal Android Music Player Sample Github repo