我建立了一个应用程序小部件,该小部件仅按固定的时间间隔获取数据,因此它没有活动;甚至没有配置活动。是否可以使用以下代码在不使用活动的情况下注册广播接收器?
context.registerReceiver(networkChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
基本上,我希望窗口小部件在设备重新连接到网络时自动刷新,而不是等待下一次刷新。
我已经尝试过在AppWidgetProvider的onEnabled()和onUpdate()方法中执行此操作,但它会抛出android.content.ReceiverCallNotAllowedException
,所以,我不知道我还能在其他地方执行此操作。
清单也不是选项,因为ConnectivityManager.CONNECTIVITY_ACTION
被SDK 24+忽略。
首先,让我们确定应用程序的生命周期。 AppWidgetProvider默认情况下是BroadcastReceiver,因此它可以生存很短的时间(onReceive()具有10秒的超时时间-因此onUpdate()和onEnabled() ,并且AppWidgetProvider的所有其他回调将在onReceive()回调上执行)。因此,注册动态广播接收器不是一种选择。您只有一个选择(因为您没有任何活动,并且想要在不使用ui的情况下更新小部件)-前台服务(是,您需要针对oreo +设备的通知,但没有其他方法)。您可以注册接收器并在ConnectivityManager.CONNECTIVITY_ACTION上进行更新,并更新小部件,例如:
val intent = Intent(this, YourAppWidgetProvider::class.java)
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
val ids = AppWidgetManager.getInstance(application).getAppWidgetIds(ComponentName(getApplicationContext(), YourAppWidgetProvider::class.java)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
sendBroadcast(intent)
在您的情况下,如果您需要对动态接收者的动作做出反应,这是更新窗口小部件的唯一方法。
我试图使用服务来解决我的问题,但正如HeyAlex所指出的那样,服务在Android的Oreo v8.0 +中的工作方式有所不同,要求您显示一条通知,就UI而言,这是非常难看的。
经过进一步研究后,我发现了一个有关这些更改的独立Stackoverflow线程:
Android 8.0: java.lang.IllegalStateException: Not allowed to start service Intent
这可能不是最佳解决方案,因为它已过时且不再维护,但JobServiceIntent可与Oreo一起使用并向后兼容。您需要在清单中具有以下权限:
<!-- < 8.0 --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- >= 8.0, inside application --> <service android:name="com.example.ListenerService" android:permission="android.permission.BIND_JOB_SERVICE" />
然后,我将服务扩展JobIntentService而不是Service,并且一切正常;无需进行任何活动即可设置网络侦听器,并且在Android 8+上无需通知。
public class ListenerService extends JobIntentService { public static final int JOB_ID = 1; @Override protected void onHandleWork(@NonNull Intent intent) { getApplicationContext().registerReceiver(networkChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); } public static void enqueueWork(Context context, Intent intent) { ListenerService.context = context; enqueueWork(context, ListenerService.class, JOB_ID, intent); } private static final BroadcastReceiver networkChangeReceiver = new BroadcastReceiver() { // usual broadcast methods in here such as onReceive } }
可以使用以下方式触发服务:
ListenerService.enqueueWork(context,intent);