Android14 开发之Broadcast延迟及Service常驻等新特性说明
Broadcast延迟问题
FLAG_RECEIVER_FOREGROUND
是 Android 中的一种标志,它用于将广播接收器(BroadcastReceiver)标记为前台广播。前台广播具有较高的优先级,系统会尽快调度前台广播接收器处理广播,确保及时性。
使用方法
使用 FLAG_RECEIVER_FOREGROUND
主要在两个场景中:
- 发送广播时:将广播标记为前台广播。
- 接收广播时:确保接收器在前台运行。
发送前台广播
在发送广播时,可以使用 sendBroadcast
方法,并传入一个 Intent
和 FLAG_RECEIVER_FOREGROUND
标志。例如:
val intent = Intent("com.example.ACTION")
intent.flags = Intent.FLAG_RECEIVER_FOREGROUND
sendBroadcast(intent)
示例代码
下面是一个完整的示例,包括发送和接收前台广播的代码。
发送前台广播
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 发送前台广播
val intent = Intent("com.example.ACTION")
intent.flags = Intent.FLAG_RECEIVER_FOREGROUND
sendBroadcast(intent)
}
}
注册广播接收器
要接收广播,需要在 AndroidManifest.xml
中静态注册广播接收器,或者在代码中动态注册。
静态注册(AndroidManifest.xml):
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="com.example.ACTION" />
</intent-filter>
</receiver>
动态注册(代码):
class MainActivity : AppCompatActivity() {
private lateinit var receiver: MyBroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 动态注册广播接收器
receiver = MyBroadcastReceiver()
val filter = IntentFilter("com.example.ACTION")
registerReceiver(receiver, filter)
// 发送前台广播
val intent = Intent("com.example.ACTION")
intent.flags = Intent.FLAG_RECEIVER_FOREGROUND
sendBroadcast(intent)
}
override fun onDestroy() {
super.onDestroy()
// 注销广播接收器
unregisterReceiver(receiver)
}
}
创建广播接收器
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// 处理接收到的广播
Toast.makeText(context, "Received foreground broadcast", Toast.LENGTH_SHORT).show()
}
}
注意事项
- 权限:发送和接收广播可能需要特定的权限,例如
android.permission.BROADCAST_STICKY
或其他自定义权限。 - 性能影响:前台广播优先级较高,应谨慎使用,避免频繁发送大量前台广播,可能会影响系统性能。
通过以上示例,您可以了解如何使用 FLAG_RECEIVER_FOREGROUND
来发送和接收前台广播,确保广播接收器能够及时处理广播事件。
Service常驻问题
在 Android 13 中,根据 Intent
的 action
启动服务的方式与之前的版本大致相同,但需要注意一些新的权限要求和行为变化。以下是一个详细的指南,说明如何在 Android 13 中根据 Intent
的 action
启动服务。
创建服务
首先,我们需要创建一个服务。以下是一个简单的服务示例:
class MyService : Service() {
override fun onBind(intent: Intent?): IBinder? {
// 我们不会绑定此服务,因此返回null
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.let {
val action = it.action
when (action) {
"com.example.START_SERVICE" -> {
// 处理启动服务的逻辑
handleStartService()
}
// 可以添加更多的action处理逻辑
}
}
// 如果系统因内存不足而终止此服务,重启服务
return START_STICKY
}
private fun handleStartService() {
// 处理服务启动逻辑
Log.d("MyService", "Service started")
}
}
在 AndroidManifest.xml 中注册服务
在 AndroidManifest.xml
中注册服务:
<service
android:name=".MyService"
android:exported="true">
</service>
启动服务
在某些情况下,我们需要根据 Intent
的 action
来启动服务。以下是一个示例代码,展示如何从活动中启动服务:
val intent = Intent(this, MyService::class.java).apply {
action = "com.example.START_SERVICE"
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
处理权限
从 Android 8.0(API 级别 26)开始,后台启动服务受到了限制。为了确保服务能够在后台启动,您可能需要请求权限或采取其他措施。例如,可以使用前台服务来确保服务的持久性。
前台服务
为了确保服务在后台能够正常运行,我们可以将服务提升为前台服务。以下是如何实现的:
-
在服务中启动前台服务:
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val notification = createNotification() startForeground(1, notification) // 处理服务逻辑 handleStartService() return START_STICKY } private fun createNotification(): Notification { val notificationChannelId = "MY_SERVICE_CHANNEL" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( notificationChannelId, "My Background Service", NotificationManager.IMPORTANCE_DEFAULT ) val manager = getSystemService(NotificationManager::class.java) manager.createNotificationChannel(channel) } val builder = NotificationCompat.Builder(this, notificationChannelId) .setContentTitle("My Service") .setContentText("Running...") .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_DEFAULT) return builder.build() }
-
权限声明:
在
AndroidManifest.xml
中声明前台服务权限:<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
示例项目结构
- MainActivity: 负责启动服务。
- MyService: 服务类,包含启动前台服务的逻辑。
// MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent(this, MyService::class.java).apply {
action = "com.example.START_SERVICE"
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
}
}
// MyService.kt
class MyService : Service() {
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
startForeground(1, notification)
intent?.let {
val action = it.action
when (action) {
"com.example.START_SERVICE" -> {
handleStartService()
}
}
}
return START_STICKY
}
private fun createNotification(): Notification {
val notificationChannelId = "MY_SERVICE_CHANNEL"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
notificationChannelId,
"My Background Service",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
val builder = NotificationCompat.Builder(this, notificationChannelId)
.setContentTitle("My Service")
.setContentText("Running...")
.setSmallIcon(R.drawable.ic_notification)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
return builder.build()
}
private fun handleStartService() {
Log.d("MyService", "Service started")
}
}
总结
通过以上步骤,您可以在 Android 13 中根据 Intent
的 action
启动服务,并确保服务在后台运行时不会被系统终止。使用前台服务可以确保服务的持久性,并且可以处理新的权限要求和行为变化。