观察结果
notification = notificationBuilder!!.setOngoing(true)
.setOnlyAlertOnce(true)
.setContentText(textToShowInNotification)
.setContentIntent(contentIntent)
.build()
notificationManager!!.notify(NOTIFICATION_ID, notification)
如果通知缺少setSmallIcon
或类似的setIcon
调用,则单击此通知可能无法启动Activity
。要解决此问题,请按照以下方式设置一些图标:
notification = notificationBuilder!!.setOngoing(true)
.setOnlyAlertOnce(true)
.setContentText(textToShowInNotification)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_launcher_background)
.build()
notificationManager!!.notify(NOTIFICATION_ID, notification)
之前的活动没有被销毁
这很可疑,因为您在启动一个Activity
时使用了标志Intent.FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TASK
,这将会结束所有先前的活动。否则,请展示相关代码。
当与设备的连接建立并从服务监听数据时,我杀死应用程序并从前台服务通知中打开它时,应该显示的对话框未显示,其中显示我的设备仍然连接且正在接收数据。
这听起来相当混乱。听起来像是您从Activity
中展示它,但如果您从Activity
的onCreate
中展示它,那么它不太可能失败:
override fun onCreate(savedInstanceState: Bundle?) {
...
showAlertDialog()
}
D/DialogExecption: 无法添加窗口-- null 标记无效;您的活动是否正在运行?D/DialogExecption: 无法添加窗口令牌 android.os.BinderProxy@4250d6d8 无效;您的活动是否正在运行?
这个错误信息很清楚——您在此处使用无效的Context
尝试显示对话框,例如,如果您在那里使用applicationContext
或Service
context
,就会出现此异常。
您声称使用以下代码以Activity
上下文启动对话框:
...
val dialogAlertDialog = AlertDialog.Builder(<Activity Context>)
...
然而,从您的代码中无法清楚地看出何时调用
showAlertDialog()
方法,也没有显示上下文对象。因此,我创建了一个示例项目来测试所描述的行为。
建议
准备工作
我尝试通过基于您在问题中提供的信息构建一个最小化的项目来复现此问题。
请注意,即使每个组件都以蓝牙作为前缀,但本示例不使用任何BLE功能。
我创建了一个前台服务
BluetoothDeviceService
,负责在单击通知时启动一个
Activity
。
BluetoothDeviceService.kt
class BluetoothDeviceService: Service() {
private val SERVICE_NOTIFICATION_ID = 123
private val SERVICE_NOTIFICATION_CHANNEL_ID = "channel_01"
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
SERVICE_NOTIFICATION_CHANNEL_ID,
"Bluetooth service",
NotificationManager.IMPORTANCE_DEFAULT)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
val pendingIntent = Intent()
pendingIntent.setClass(this,BluetoothDeviceActivity::class.java)
pendingIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val contentIntent = PendingIntent.getActivity(this, 0,
pendingIntent, 0)
val notification = NotificationCompat.Builder(this, SERVICE_NOTIFICATION_CHANNEL_ID)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setContentText("Bluetooth service running...")
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_launcher_background)
.build()
startForeground(SERVICE_NOTIFICATION_ID, notification)
}
}
override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
}
我创建了一个MainActivity
,需要启动前台服务。
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val startServiceIntent = Intent(this, BluetoothDeviceService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(startServiceIntent)
} else {
startService(startServiceIntent)
}
finish()
}
}
请注意,
Service
也可以由
BroadcastReceiver
启动,这样做更为合适,但出于简单起见,我使用了
Activity
。
此外,我引入了一个
BluetoothDeviceActivity
,该活动通过
PendingIntent
与服务一起启动:
BluetoothDeviceActivity.kt
class BluetoothDeviceActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showAlertDialog()
}
}
private fun showAlertDialog() {
val dialogAlertDialog = AlertDialog.Builder(this)
.setCancelable(false)
.setMessage("This is a test")
.setTitle("Information")
.create()
dialogAlertDialog.show()
}
为了确保,我也放置了我的清单。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.stackoverflowquestion2">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.StackOverflowQuestion2"
android:fullBackupContent="@xml/backup_descriptor">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/Theme.StackOverflowQuestion2.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".BluetoothDeviceActivity"/>
<service android:name=".BluetoothDeviceService"/>
</application>
</manifest>
结果
这个操作按照预期顺利完成,没有出现任何问题。
进一步建议
另一个想法是,你可以将你的 AlertDialog
转换成 Activity
并将其用作 Dialog
。为此,你需要完成两件事:
Create a new Àctivity
as below:
class AlertDialogActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val dialogAlertDialog = AlertDialog.Builder(this)
.setCancelable(false)
.setMessage("This is a test")
.setTitle("Information")
.setPositiveButton("OK") { dialog, which -> finish() }
.create()
dialogAlertDialog.show()
}
}
Add it to your manifest and set its theme as Dialog
:
<activity android:name=".AlertDialogActivity" android:theme="@style/Theme.AppCompat.Dialog"/>
Then, create a method in your Service
, and use it any time it's needed:
private fun showAlertDialog() {
val intent = Intent(applicationContext, AlertDialogActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
applicationContext.startActivity(intent)
}
结果
这就是它的样子: