通过解除绑定的所有边界活动停止服务

问题描述 投票:4回答:2

我有一个开始和有限服务(音乐播放器),我想阻止它被点击通知的关闭按钮时。然而,该服务不会,如果有一定到它的活动停止。如何才能停止服务,单击按钮时?

我试图收集的服务活动列表,并调用回调给他们解除绑定(实际上finish()然后在onStop()将调用unbind()),然后我通过调用stopSelf()停止服务,但我不认为这是个好主意,因为生命周期问题和一些活动被多次添加和维护该列表是很难的。应该有一个更好的办法!虽然我还没有寻找小时后发现任何东西。

这里是我的PlayerServiceonStartCommand()

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    info("Starting Player Service ...")
    started=true

    if (intent == null) {
        error("intent was null")
        pause()
        return START_STICKY
    }

    if (intent.hasExtra(KEY_SONGS)) {
        if(intent.hasExtra(KEY_PLAYLIST_ID)) playlistId=intent.getStringExtra(KEY_PLAYLIST_ID)
        initExoPlayer(intent)
    } else {
        info("No new song information found for intent, intent's action: ${intent.action}")
    }
    if (intent.action == null) intent.action = ""
    when (intent.action) {
        ACTION_PLAY -> if (isPlaying()) pause() else play()
        ACTION_CANCEL -> {
            //TODO: implement a better and the correct way
            for (client in clients) {
                client.onStop()
            }
            stopSelf()
        }
        else -> showNotification()
    }

    return START_STICKY
}

我的活动:

 playerService.clients.add(object : PlayerService.Client {
        override fun onStop() {
            finish()
        }
    })

这里是我的自定义通知:

private fun getCustomNotification(name: String, showMainActivity: Intent): Notification {
    /*
        some codes to prepare notificationLayout
     */
    notificationLayout.setTextViewText(R.id.tv_name, name)
    notificationLayout.setImageViewResource(R.id.btn_play, playDrawableID)
    notificationLayout.setOnClickPendingIntent(R.id.btn_play, playPendingIntent)
    notificationLayout.setOnClickPendingIntent(R.id.btn_cancel, cancelPendingIntent)

    // Apply the layouts to the notification
    return NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.logo_mouj)
            .setCustomContentView(notificationLayout)
            .setContentIntent(PendingIntent.getActivity(this, 0, showMainActivity, 0))
            .setOngoing(true)
            .build()

}
android android-service android-notifications android-service-binding
2个回答
1
投票

如果这个任务看起来令人沮丧,这可能是因为这是一个不寻常的使用情况,以及有些什么外面了Android设计者的初衷。您可能要问自己是否有实现自己的目标更“机器人式”的方式(即无需枚举绑定客户端)。

考虑你的要求:

  1. 当用户正在使用该应用进行交互(通过Activity)播放器应提供
  2. 玩家应该继续存在,而用户在后台应用程序
  3. 当用户点击该通知的玩家应该停止
  4. 该应用程序应该得到清理,当用户用它做

我想你可能选择通过结合到Service开始播放,并通过onDestroy()-ING它播放结束。这是设计错误,并且它会导致你很多的问题。毕竟,根据docs,本地,进程Service真的只是代表“的应用程序的愿望,而不是与用户的交互进行长时间运行的操作”,它“不是手段本身做工作过的主线程“。

取而代之的是,通过保持ActivityonStart()之间的绑定每个onStop(),通过游戏开始时使用startService()stopSelf()当播放停止时,你会自动完成目标1,2和4。当应用程序是在所有Activities是国营屏幕外,它将具有0绑定客户。如果在除此之外,没有startService()都很优秀,它是由OS立即终止的候选人。在任何其他状态下,操作系统将保持它周围。

这是没有任何多余的花哨的逻辑来跟踪绑定Activities。当然,你可能会想,而玩家玩到startForeground(),并stopForeground()当它这样做(想必你已经处理这个细节)。

这使得如何完成目标#3的问题。为了实现在Service的状态变化,无论从Activities或通知,您可以只使用Intents(就像你已经是)。在这种情况下,Service将管理通过stopSelf()自己的生命周期。这是假设,再一次,您正在使用startForeground()在适当的时间(奥利奥+),否则的Android可能会终止你的应用程序,由于background execution limits

事实上,如果你选择使用Intents,你会发现你甚至不需要在所有的Activities绑定到Service(IOW,目标#1是在这种情况下不相关)。你只需要如果你需要一个直接引用该服务(通过Service)绑定到一个Binder


1
投票

尝试这样的事情

fun stopServices() {
    val serviceIntent = Intent(this, NotificationService::class.java)
    serviceIntent.action = Constants.ACTION.STOPTFOREGROUND_ACTION
    stopService(serviceIntent)
}

在您的活动调用此方法

在您的服务启动命令

 ACTION.STOPFOREGROUND_ACTION -> {
            //Toast.makeText(this, "Service Stoped", Toast.LENGTH_SHORT).show();
            stopForeground(true);
            stopSelf();
            Intent intents = new Intent("com.app.package.ACTION_STOP");
            LocalBroadcastManager.getInstance(this).sendBroadcast(intents);
            //startActivity(new Intent(this,MainActivity.class));

        }



val notificationLayout= new RemoteViews(getPackageName(), R.layout.custom_layout);


 Intent closeIntent = new Intent(this, NotificationService.class);
    closeIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
    PendingIntent cancelPendingIntent= PendingIntent.getService(this, 0, closeIntent, 0);

关闭按钮点击

    notificationLayout.setOnClickPendingIntent(R.id.btn_cancel, cancelPendingIntent);
© www.soinside.com 2019 - 2024. All rights reserved.