重新将服务附加到活动?

时间:2018-09-03 18:58:21

标签: android android-activity kotlin mediabrowserservicecompat

当我第一次打开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()


    }


}

1 个答案:

答案 0 :(得分:1)

您看到的问题是由于连接和断开连接的调用是异步的。当您呼叫connect()时,不会立即建立连接。您只是在“请求连接”。只有在调用回调onConnected()之后,您才能建立连接。

因此,当用户从另一个Activity返回时,首先您在connect()中调用onStart(),然后立即调用onResume()。在onResume()中,当您调用isConnected()时,由于尚未建立连接(即:尚未调用回调false),它将返回onConnected()。然后,您调用connect(),但失败,并显示给定的异常。您甚至可以从异常消息中看到:

connect() called while not disconnected (state=CONNECT_STATE_CONNECTING)

当前状态不是“已连接”,而是“正在连接”

MediaBrowser进行交互之前,您需要等待异步回调到达。