我有一个开始和有限服务(音乐播放器),我想阻止它被点击通知的关闭按钮时。然而,该服务不会,如果有一定到它的活动停止。如何才能停止服务,单击按钮时?
我试图收集的服务活动列表,并调用回调给他们解除绑定(实际上finish()
然后在onStop()
将调用unbind()
),然后我通过调用stopSelf()
停止服务,但我不认为这是个好主意,因为生命周期问题和一些活动被多次添加和维护该列表是很难的。应该有一个更好的办法!虽然我还没有寻找小时后发现任何东西。
这里是我的PlayerService
的onStartCommand()
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设计者的初衷。您可能要问自己是否有实现自己的目标更“机器人式”的方式(即无需枚举绑定客户端)。
考虑你的要求:
Activity
)播放器应提供我想你可能选择通过结合到Service
开始播放,并通过onDestroy()
-ING它播放结束。这是设计错误,并且它会导致你很多的问题。毕竟,根据docs,本地,进程Service
真的只是代表“的应用程序的愿望,而不是与用户的交互进行长时间运行的操作”,它“不是手段本身做工作过的主线程“。
取而代之的是,通过保持Activity
和onStart()
之间的绑定每个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
。
尝试这样的事情
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);