Android 14中Widget的BroadcastReceiver无法正常工作问题
WiFi状态Widget在Android 14无法实时更新的问题
我开发了一个追踪WiFi状态并在Widget中显示的组件。在Android 14系统中,开启或关闭WiFi后,Widget状态不会实时更新,只有调整Widget尺寸时,所有积压的状态变更才会一次性执行;但在Android 12系统中功能完全正常。
以下是相关代码实现:
1. WifiStateReceiver 代码
class WifiStateReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (WifiManager.WIFI_STATE_CHANGED_ACTION == intent.action) { val wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN) val isWifiEnabled = wifiState == WifiManager.WIFI_STATE_ENABLED updateWidget(context, isWifiEnabled) } } private fun updateWidget(context: Context, isWifiEnabled: Boolean) { val appWidgetManager = AppWidgetManager.getInstance(context) val componentName = ComponentName(context, MyAppWidgetProvider::class.java) val appWidgetIds = appWidgetManager.getAppWidgetIds(componentName) for (appWidgetId in appWidgetIds) { val views = RemoteViews(context.packageName, R.layout.widget_layout) views.setTextViewText(R.id.statusWifi, if (isWifiEnabled) "已开启" else "已关闭") appWidgetManager.updateAppWidget(appWidgetId, views) } } }
2. MyAppWidgetProvider 代码
class MyAppWidgetProvider : AppWidgetProvider() { private var wifiStateReceiver: WifiStateReceiver? = null override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, ) { super.onUpdate(context, appWidgetManager, appWidgetIds) } override fun onEnabled(context: Context) { super.onEnabled(context) Log.d("WifiStateReceiver", "onEnabled") if (wifiStateReceiver == null) { wifiStateReceiver = WifiStateReceiver() val filter = IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { context.applicationContext.registerReceiver(wifiStateReceiver, filter, Context.RECEIVER_NOT_EXPORTED ) } } } override fun onDisabled(context: Context) { super.onDisabled(context) Log.d("WifiStateReceiver", "onDisabled") wifiStateReceiver?.let { context.applicationContext.unregisterReceiver(it) wifiStateReceiver = null } } }
3. AndroidManifest.xml 配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:installLocation="internalOnly"> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <application android:name=".App" android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Widget2" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".MyAppWidgetProvider" android:exported="true" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.net.wifi.supplicant.CONNECTION_CHANGE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> </receiver> <receiver android:name=".WifiStateReceiver" android:exported="false"> <intent-filter> <action android:name="android.net.wifi.WIFI_STATE_CHANGED" /> </intent-filter> </receiver> <service android:name=".WifiStatusService" /> </application> </manifest>
4. Widget配置文件(widget_info.xml)
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="300dp" android:minHeight="100dp" android:updatePeriodMillis="0" android:initialLayout="@layout/widget_layout" android:resizeMode="horizontal|vertical" android:widgetCategory="home_screen"> </appwidget-provider>
问题原因
Android 14对后台进程限制进一步加强:AppWidgetProvider的进程属于临时进程,Widget更新完成后会被系统快速回收,导致动态注册的广播接收器被销毁,无法接收后续WiFi状态变化。调整Widget尺寸时,系统会重启AppWidgetProvider进程,积压的状态变更会被一次性处理,因此出现延迟更新的现象。而Android 12的后台进程限制较宽松,进程存活时间更长,广播接收器可正常工作。
解决方案:使用前台服务托管广播接收器
通过前台服务持有广播接收器,保证进程不会被系统轻易回收,从而稳定接收WiFi状态变化。
1. 改造WifiStatusService为前台服务
class WifiStatusService : Service() { private lateinit var wifiStateReceiver: WifiStateReceiver override fun onCreate() { super.onCreate() wifiStateReceiver = WifiStateReceiver() val filter = IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION) registerReceiver(wifiStateReceiver, filter) // Android 8.0+需要创建通知渠道并启动前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "WIFI_WIDGET_CHANNEL", "WiFi状态监控", NotificationManager.IMPORTANCE_LOW ) getSystemService(NotificationManager::class.java).createNotificationChannel(channel) val notification = Notification.Builder(this, "WIFI_WIDGET_CHANNEL") .setSmallIcon(R.drawable.ic_launcher) .setContentTitle("WiFi状态监控") .setContentText("正在追踪WiFi状态") .build() startForeground(1, notification) } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { return START_STICKY } override fun onBind(intent: Intent): IBinder? { return null } override fun onDestroy() { super.onDestroy() unregisterReceiver(wifiStateReceiver) } }
2. 修改MyAppWidgetProvider,通过服务管理广播
class MyAppWidgetProvider : AppWidgetProvider() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, ) { // 初始化Widget初始状态 val wifiManager = context.getSystemService(WifiManager::class.java) val isWifiEnabled = wifiManager.isWifiEnabled val views = RemoteViews(context.packageName, R.layout.widget_layout) views.setTextViewText(R.id.statusWifi, if (isWifiEnabled) "已开启" else "已关闭") appWidgetManager.updateAppWidget(appWidgetIds, views) } override fun onEnabled(context: Context) { super.onEnabled(context) // 启动前台服务 val serviceIntent = Intent(context, WifiStatusService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent) } else { context.startService(serviceIntent) } } override fun onDisabled(context: Context) { super.onDisabled(context) // 停止前台服务 val serviceIntent = Intent(context, WifiStatusService::class.java) context.stopService(serviceIntent) } }
3. 添加必要权限
在AndroidManifest.xml中添加Android 13+的通知权限:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
4. 移除静态注册的广播接收器(可选)
删除AndroidManifest.xml中静态注册的WifiStateReceiver,避免重复接收广播:
<!-- 移除这段 --> <receiver android:name=".WifiStateReceiver" android:exported="false"> <intent-filter> <action android:name="android.net.wifi.WIFI_STATE_CHANGED" /> </intent-filter> </receiver>
内容的提问来源于stack exchange,提问作者Pilot777
相关产品推荐
相关产品推荐

