【问题标题】:Wear OS Tiles and Media ServiceWear OS 磁贴和媒体服务
【发布时间】:2022-07-17 06:11:01
【问题描述】:

Wear OS 磁贴示例很棒,不是什么大问题,而是如何启动播放在主应用程序中选择的歌曲的后台媒体服务,当我每次尝试启动服务时,我都会收到以下错误.没有 UI 线程可供参考,文档只有 onclick、LoadAction 和 LaunchAction 的方法。

override fun onTileRequest(request: TileRequest) = serviceScope.future {
when(request.state!!.lastClickableId){
"play"-> playClicked()
}....

suspend fun playClicked(){

    try {
        // Convert the asynchronous callback to a suspending coroutine
        suspendCancellableCoroutine<Unit> { cont ->
            mMediaBrowserCompat = MediaBrowserCompat(
                applicationContext, ComponentName(applicationContext, MusicService::class.java),
                mMediaBrowserCompatConnectionCallback, null
            )
            mMediaBrowserCompat!!.connect()

        }
    }catch (e:Exception){
        e.printStackTrace()
    } finally {
      mMediaBrowserCompat!!.disconnect()
    }
}

错误

java.lang.RuntimeException: Can't create handler inside thread Thread[DefaultDispatcher-worker-1,5,main] that has not called Looper.prepare()

【问题讨论】:

  • 确切的堆栈跟踪是什么?
  • 这个样本是不是比较全?是否有可能因为您没有调用 cont.completeResume() 并且还在调用 cont.invokeOnCancellation 而挂起?

标签: kotlin media wear-os wear-os-tiles


【解决方案1】:

serviceScope 在 Dispatchers.IO 上运行,您应该在调用 MediaBrowserCompat 时使用 withContext(Dispatchers.Main)。

【讨论】:

    【解决方案2】:

    响应上面的答案,serviceScope.future 创建了一个 CoroutineScope,它将导致返回到服务的 future 等待所有子作业完成。

    如果您想让它运行与 onTileRequest 调用分离,您可以运行以下命令,这将在应用程序 GlobalScope 内启动一个新作业并让 onTileRequest 立即返回。

    "play" -> GlobalScope.launch { 
    
    }
    

    这样做的好处是您不会将第三种并发模型、ListenableFutures、Coroutines 和现在的 Handler 混在一起。 LF 和 Coroutines 旨在避免您不得不求助于第三个并发选项。

    【讨论】:

      【解决方案3】:

      感谢 Yuri 工作,但它最终阻塞了 UI 线程,工作的解决方案如下

      fun playClicked(){
          mainHandler.post(playSong)
      }
      
        private val playSong: Runnable = object : Runnable {
              @RequiresApi(Build.VERSION_CODES.N)
              override fun run() {
                  mMediaBrowserCompat = MediaBrowserCompat(
                      applicationContext, ComponentName(applicationContext, MusicaWearService::class.java),
                      mMediaBrowserCompatConnectionCallback, null
                  )
                  mMediaBrowserCompat!!.connect()
              }
          }
      

      【讨论】:

        【解决方案4】:

        酷尤里,下面的工作,我认为更有效率

        fun playClicked() = GlobalScope.launch(Dispatchers.Main) {
                    mMediaBrowserCompat = MediaBrowserCompat(
                        applicationContext, ComponentName(applicationContext, MusicaWearService::class.java),
                        mMediaBrowserCompatConnectionCallback, null
                    )
                    mMediaBrowserCompat!!.connect()
                }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-02
          相关资源
          最近更新 更多