当我第一次打开Activity时,它将创建一个MediaBrowserService。当我尝试重新打开它时,我想重新连接到它。我尝试了多种方式:
override fun onResume(){
mMediaBrowser.connect()
buildTransportControls()
}
当我尝试这样做时,总是会出现错误消息:
connect() called while not disconnected (state=CONNECT_STATE_CONNECTING)
即使我通过onStop()
函数mMediaBrowser.disconnect()
调用也怎么可能?还是这只是错误的方式?当我通过BackButton返回时,所有这些都会发生。
我的完整代码:
class MusicPlayer : AppCompatActivity() {
private var songAdapter : RecyclerView.Adapter<MusicRecyclerSongAdapter.ViewHolder>? = null
private var albumAdapter: RecyclerView.Adapter<MusicRecyclerAlbumAdapter.ViewHolder>? = null
val context:Context = this
//Media Browser
private lateinit var mMediaBrowser: MediaBrowserCompat
//prepare variables for late init
lateinit var songUri:ArrayList<String>
lateinit var album_name:ArrayList<String>
lateinit var mediaController : MediaControllerCompat
//------------------------------------------------------------------------------
fun buildTransportControls(){
mMediaBrowser.subscribe(mMediaBrowser.root,object: MediaBrowserCompat.SubscriptionCallback(){})
mediaController = MediaControllerCompat.getMediaController(this@MusicPlayer)
//Show Init state
var metadat = mediaController.metadata
var pbState = mediaController.playbackState
//Register Callback to stay synced
mediaController.registerCallback(controllerCallback)
}
//------------------------------------------------------------------------------
val controllerCallback = object : MediaControllerCompat.Callback() {
override fun onMetadataChanged(metadat: MediaMetadataCompat){
Log.i("Musik",metadat.toString())
}
override fun onPlaybackStateChanged(state :PlaybackStateCompat){
}
}
//------------------------------------------------------------------------------
private val mConnectionCallbacks = object : MediaBrowserCompat.ConnectionCallback() {
override fun onConnected() {
Log.i("Connection","Connecting")
// Get the token for the MediaSession
val token = mMediaBrowser.sessionToken
// Create a MediaControllerCompat
val mediaController = MediaControllerCompat(this@MusicPlayer,token)
// Save the controller
MediaControllerCompat.setMediaController(this@MusicPlayer, mediaController)
// Finish building the UI
buildTransportControls()
}
override fun onConnectionSuspended() {
// The Service has crashed. Disable transport controls until it automatically reconnects
Log.i("ERROR","Connection Suspended")
}
override fun onConnectionFailed() {
// The Service has refused our connection
Log.i("ERROR","Connection Failed")
}
}
//------------------------------------------------------------------------------
fun startSong(position: Int){
if(songAdapter == null) {
songAdapter = MusicRecyclerSongAdapter(context, album_name[position])
//Getting the Location of the Songs
songUri = GetMusic.uris
recyclerViewMusic.adapter = songAdapter
}else{
var pbSate = MediaControllerCompat.getMediaController(this@MusicPlayer).playbackState.playbackState
MediaControllerCompat.getMediaController(this@MusicPlayer).transportControls.playFromUri(Uri.parse(songUri[position]), null)
//TODO Testing if no song is playing already
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_music_player)
//Initialize MediaBrowserServiceCompat
if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
//Create MediaBrowser Service
createMediaBrowser()
}else {
permissionRequest()
}
//Create Recycler View and get Adapter
//val recyclerViewMusic: RecyclerView = findViewById(R.id.recyclerViewMusic)
recyclerViewMusic.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,false)
albumAdapter = MusicRecyclerAlbumAdapter(context)
//Getting values from Companion Object
album_name = GetAlbum.albums
//Apply Adapter to Recyclerview and change Backgroundcolor
recyclerViewMusic.adapter = albumAdapter
recyclerViewMusic.setBackgroundColor(Color.BLUE)
recyclerViewMusic.addOnItemTouchListener(
RecyclerItemClickListener(context, recyclerViewMusic, object : RecyclerItemClickListener.OnItemClickListener {
override fun onItemClick(view: View, position: Int) {
//Change to Song selection
startSong(position)
}
override fun onLongItemClick(view: View, position: Int) {
//Change to Song selection
startSong(position)
}
}
)
)
musicprogressbar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if(fromUser) {
//mplayer.seekTo(progress)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
//if(::mplayer.isInitialized) {
// mplayer.pause()
//}
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
//if(::mplayer.isInitialized) {
// mplayer.start() }
}
}
)
}
override fun onStart() {
super.onStart()
mMediaBrowser.connect()
}
override fun onResume() {
super.onResume()
Log.i("I","RE OPEN")
Log.i("MediaBrowserStatus",mMediaBrowser.isConnected.toString())
if(!mMediaBrowser.isConnected) {
mMediaBrowser.connect()
}
buildTransportControls()
volumeControlStream = AudioManager.STREAM_MUSIC
}
override fun onStop() {
super.onStop()
Log.i("STOP","STOP")
if(MediaControllerCompat.getMediaController(this@MusicPlayer) != null){
MediaControllerCompat.getMediaController(this@MusicPlayer).unregisterCallback(controllerCallback)
}
mMediaBrowser.disconnect()
}
fun permissionRequest(){
val permissions = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
if(permissions != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE
),101)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
createMediaBrowser()
}
fun createMediaBrowser(){
Log.i("HI","HI")
mMediaBrowser = MediaBrowserCompat(this,
ComponentName(this, MediaPlaybackService::class.java),
mConnectionCallbacks,
null)
}
fun musicControls(view: View) {
//applying functions to buttons
if (mMediaBrowser.isConnected) {
when (view.id) {
//Pause or Start Music
R.id.musicStart -> if (mediaController.playbackState.playbackState != null) {
mediaController.transportControls.play()
Log.i("TEST",mediaController.playbackState.playbackState.toString())}
R.id.musicPause -> if (mediaController.playbackState.playbackState != null) {
mediaController.transportControls.pause()
Log.i("TEST",mediaController.playbackState.playbackState.toString())}
/* //Forward/Backward Music
R.id.musicbackward -> {
mplayer.pause()
mplayer.seekTo(mplayer.currentPosition - 5000)
mplayer.start()
}
R.id.musicforward -> {
mplayer.pause()
mplayer.seekTo(mplayer.currentPosition + 5000)
mplayer.start()
}*/
}
}
}
override fun onBackPressed() {
super.onBackPressed()
}
}
// EDIT询问服务代码:
class MediaPlaybackService: MediaBrowserServiceCompat(){
//private val MY_MEDIA_ROOT_ID = "MediaStore.Audio.Media.EXTERNAL_CONTENT_URI"
private val MY_MEDIA_ROOT_ID ="root"
private lateinit var mMediaSession: MediaSessionCompat
private lateinit var mStateBuilder : PlaybackStateCompat.Builder
private lateinit var MySessionCallback : MediaSessionCompat.Callback
private lateinit var mMediaPlayer: MediaPlayer
override fun onCreate() {
super.onCreate()
initMediaPlayer()
//Create the MediaSession
mMediaSession = MediaSessionCompat(this,"PLAYER")
//Setting the necessary Flags (Media Buttons)
mMediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
//Set an inital PlaybackStatewith ACTION_BUTTONS, so Media buttons can start the player
mStateBuilder = PlaybackStateCompat.Builder().setActions(
PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE)
//Set our PLaybackState for the MediaSession
mMediaSession.setPlaybackState(mStateBuilder.build())
MySessionCallback = object : MediaSessionCompat.Callback() {
override fun onPlayFromUri(uri: Uri?, extras: Bundle?) {
super.onPlayFromUri(uri, extras)
if(!mMediaPlayer.isPlaying) {
mMediaPlayer.setDataSource(application.applicationContext, uri)
mMediaPlayer.setOnPreparedListener {
mMediaPlayer.start()
Log.i("DURATION",mMediaPlayer.duration.toString())
}
mMediaPlayer.prepareAsync()
}
}
override fun onPause() {
super.onPause()
if(mMediaPlayer.isPlaying){
mMediaPlayer.pause()}
}
override fun onPlay() {
super.onPlay()
mMediaPlayer.start()
}
}
//Handles callbacks from Media Controller MySessionCalback is a PlaeHolder
mMediaSession.setCallback(MySessionCallback)
mMediaSession.isActive = true
//Set SessionToken so Activites can communicate with it
setSessionToken(mMediaSession.getSessionToken());
}
override fun onLoadChildren(parentId: String, result: Result<MutableList<MediaBrowserCompat.MediaItem>>) {
var mediaItems:ArrayList<MediaBrowserCompat.MediaItem> = ArrayList()
/*
var albums = MusicLibrary(this@MediaPlaybackService).getMusic()
for(item in MusicLibrary.MusicFiles){
val songList = MediaBrowserCompat.MediaItem(item,
MediaBrowserCompat.MediaItem.FLAG_PLAYABLE)
mediaItems.add(songList)
}
Log.i("MEDIA_ITEMS",mediaItems.toString())
*/
result.sendResult(mediaItems)
}
override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot? {
return BrowserRoot(MY_MEDIA_ROOT_ID,null)
}
fun initMediaPlayer(){
mMediaPlayer = MediaPlayer()
}
}
答案 0 :(得分:1)
您看到的问题是由于连接和断开连接的调用是异步的。当您呼叫connect()
时,不会立即建立连接。您只是在“请求连接”。只有在调用回调onConnected()
之后,您才能建立连接。
因此,当用户从另一个Activity
返回时,首先您在connect()
中调用onStart()
,然后立即调用onResume()
。在onResume()
中,当您调用isConnected()
时,由于尚未建立连接(即:尚未调用回调false
),它将返回onConnected()
。然后,您调用connect()
,但失败,并显示给定的异常。您甚至可以从异常消息中看到:
connect() called while not disconnected (state=CONNECT_STATE_CONNECTING)
当前状态不是“已连接”,而是“正在连接” 。
与MediaBrowser
进行交互之前,您需要等待异步回调到达。