Android 通过解除绑定所有绑定活动来停止服务

Android 通过解除绑定所有绑定活动来停止服务,android,android-service,android-notifications,android-service-binding,Android,Android Service,Android Notifications,Android Service Binding,我有一个已启动且绑定的服务(音乐播放器),我想在单击通知的关闭按钮时停止它。但是,如果存在绑定到该服务的活动,则不会停止该服务。 单击按钮时,如何停止服务 我已尝试收集服务中活动的列表,并调用回调以解除绑定(实际上是finish(),然后在onStop()上调用unbind()),然后通过调用stopSelf()停止服务但我认为这不是一个好主意,因为生命周期问题和某些活动会被多次添加并维护列表很困难。应该有更好的办法!虽然我找了好几个小时没找到任何东西 这是我的PlayerService的onS

我有一个已启动且绑定的服务(音乐播放器),我想在单击通知的关闭按钮时停止它。但是,如果存在绑定到该服务的活动,则不会停止该服务。 单击按钮时,如何停止服务

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

这是我的
PlayerService
onStartCommand()

我的活动:

 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()

}

试试这样的方法

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);

如果这项任务看起来令人沮丧,可能是因为这是一个不寻常的用例,有点超出了Android设计者的想法。您可能想问问自己,是否有一种更“类似Android”的方式来实现您的目标(也就是说,不需要列举绑定的客户端)

考虑您的要求:

  • 当用户与应用程序交互时(通过
    活动
  • 当用户将应用程序置于后台时,播放器应继续存在
  • 当用户点击通知时,播放机应该停止
  • 当用户使用完应用程序后,应用程序应该得到清理
  • 我想您可能已经选择了通过绑定到
    服务开始播放,并通过
    onDestroy()
    终止播放。这是设计错误,它会给你带来很多问题。毕竟,根据,本地进程内
    服务
    实际上只是表示“应用程序希望在不与用户交互的情况下执行更长时间的运行操作”,而“它本身并不是一种脱离主线程工作的手段”

    相反,通过在
    onStart()
    onStop()
    之间保持每个
    活动的绑定,在播放开始时使用
    startService()
    ,在播放停止时使用
    stopSelf()
    ,您将自动完成目标1、2和4。当应用程序处于所有
    活动都在屏幕外的状态时,它将有0个绑定客户端。除此之外,如果没有未完成的
    startService()
    ,则可能会被操作系统立即终止。在任何其他状态下,操作系统都会将其保留

    这不需要任何额外的逻辑来跟踪绑定的
    活动
    。当然,您可能希望在播放器播放时
    startForeground()
    ,播放完毕后
    stopForeground()
    (可能您已经处理了该细节)

    这就留下了如何实现目标3的问题。要在
    服务
    中通过
    活动
    或通知实现状态更改,您只需使用
    意图
    (就像您已经在做的那样)。在这种情况下,
    服务将通过
    stopSelf()
    管理自己的生命周期。这再次假设您在适当的时间使用
    startForeground()
    (Oreo+),否则Android可能会因为错误而终止您的应用程序


    事实上,如果您选择使用
    意图
    ,您可能会发现您甚至不需要将
    活动
    绑定到
    服务
    (在这种情况下,目标1是不相关的)。如果您需要直接引用某个
    服务(通过
    活页夹
    ),您只需绑定到该服务即可。

    它不起作用,您只是在接收时发送一个带有操作的意图,我不太明白该代码应该做什么。我想要的是解除所有活动的绑定,以便服务可以停止。是否使用音乐播放器的自定义通知布局?是。谢谢提醒,我将把它添加到问题中。问题不是为了关闭通知,它已经完成了。问题是如何解除所有活动的绑定,以便服务可以停止。在我看来,这个问题也可以用“如何从服务中关闭所有活动?”来表达。你能解释一下这与使用
    System.exit(0)
    有什么不同吗?我不需要关闭我的活动。我只需要停止我的服务,但是因为活动绑定到它,它们需要“解除绑定”,而不是关闭OK,那么为什么您需要停止
    服务
    ?您是否出于某种原因试图将其发送到
    ondestory()
    ?如果您的活动在可见时不需要引用
    服务
    ,那么为什么要首先绑定它们?它是一个音乐播放器。我想关闭,因为用户想停止音乐并关闭应用程序,而绑定是用来控制音乐的。您让我有点不知所措了——从您的代码看,播放似乎是通过
    onStartCommand()中的
    Intents
    来控制的
    。我正在将它们绑定到
    onStart
    上,并将它们解除绑定到
    onStop
    上,但这仍然留下了一个问题,即当我仍在其中一个活动中时,如何停止服务。如果我调用
    stopSelf
    服务将不会停止。我需要首先分离所有活动。im绑定到服务的原因是我需要iBinder调用服务上的函数,并在手头的任务中获取一些信息。也许我不明白你的答案。感谢您详细回答“当我仍在某项活动中时如何停止服务”典型的方法是,如果您的
    活动
    需要
    服务
    ,则它对该
    服务
    具有“依赖性”,并且
        notificationLayout.setOnClickPendingIntent(R.id.btn_cancel, cancelPendingIntent);