如何在没有应用小部件活动的情况下注册BroadcastReceiver?

问题描述 投票:0回答:2

我建立了一个应用程序小部件,该小部件仅按固定的时间间隔获取数据,因此它没有活动;甚至没有配置活动。是否可以使用以下代码在不使用活动的情况下注册广播接收器?

context.registerReceiver(networkChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

基本上,我希望窗口小部件在设备重新连接到网络时自动刷新,而不是等待下一次刷新。

我已经尝试过在AppWidgetProvider的onEnabled()和onUpdate()方法中执行此操作,但它会抛出android.content.ReceiverCallNotAllowedException,所以,我不知道我还能在其他地方执行此操作。

清单也不是选项,因为ConnectivityManager.CONNECTIVITY_ACTION被SDK 24+忽略。

java android android-appwidget
2个回答
0
投票

首先,让我们确定应用程序的生命周期。 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)

在您的情况下,如果您需要对动态接收者的动作做出反应,这是更新窗口小部件的唯一方法。


0
投票

我试图使用服务来解决我的问题,但正如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);
© www.soinside.com 2019 - 2024. All rights reserved.