来自appWidget的网络请求

时间:2019-11-26 11:09:28

标签: android android-appwidget

SO上有许多类似的问题,但是它们都是O之前的版本,因此IntentService可以正常工作。我尝试将其作为JobIntentService进行,但是延迟是不可接受的。我的小部件的网络交换应该是真的很快,或者根本没有,socketTimeout设置为100ms,所以几秒钟的延迟令人沮丧。

我想在这里尝试几种解决方案。首先,从上下文创建一个前台服务。据我了解,我在服务终止前还有5秒钟的时间,因此,如果我的交换只花了其中的一小部分,那我应该很好。这个假设正确吗?这对前台服务有用吗?

接下来,如果我只是通过在我的AppWidgetProvider的onReceive中手动启动一个新线程来执行此操作,该怎么办?正如我所说,网络交换应该花费不到四分之一秒。在这段时间内上下文可能会发生什么?

从appWidget发出快速网络请求的最佳方法是什么,它应该在发送广播后立即发生?

1 个答案:

答案 0 :(得分:1)

回答这个问题有几点要指出。我们有一些appWidgets使用服务来处理事务,因为jobService不是我们的选择。分享一些我们已经完成的事情,希望会对您有所帮助。

第一个问题:
该服务是从appWidget提供程序调用的,并完成了所有工作,并且必须在Oreo +上将其作为前台服务调用,如果该调用前5秒钟内未启动该前台服务,您将得到一个异常:“ Context.startForegroundService执行了然后再调用Service.startForeground”。 Google跟踪器中有一个尚未解决的问题,似乎尚未解决,因此,您还应该确保也阅读此内容。有人建议将以下代码放入服务的onCreate()和onStart()中。问题是https://issuetracker.google.com/issues/76112072

我建议在从提供商处调用服务后,完成服务中所需的所有工作。 (也请记住将通知通道用于Oreo +),例如:

在appWidget提供程序中的onUpdate():

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(new Intent(serviceIntent));
    } else {
        context.startService(new Intent(serviceIntent));
    }

然后在您的服务类中-按照我上面发布的问题链接将其放在onStartCommand()和onCreate()中。

savedIntent = intent;
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    //Google Issue tracker https://issuetracker.google.com/issues/76112072 as of 9/26/2018. StartForeground notification must be in both onCreate and onStartCommand to minimize
    //crashes in event service was already started and not yet stopped, in which case onCreate is not called again
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(PRIMARY_NOTIF_CHANNEL, "YOUR NOTIFICATION CHANNEL", NotificationManager.IMPORTANCE_DEFAULT);
        channel.setSound(null, null);
        channel.enableVibration(false);
        if (notificationManager != null) {
            notificationManager.createNotificationChannel(channel);
        }

        Notification notification = new NotificationCompat.Builder(this, PRIMARY_NOTIF_CHANNEL)
                .setSmallIcon(R.drawable.your_drawable)
                .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setContentTitle(getText(R.string.app_name))
                .setStyle(new NotificationCompat.InboxStyle()
                        .addLine("Needs to sync periodically. Long press to hide.")
                        .addLine(""))
                .build();

        startForeground(PRIMARY_FOREGROUND_NOTIF_SERVICE_ID, notification);
    }

关于第二个问题:

AppWidget Provider的onReceive()方法由有意图的广播触发,可用于执行不同的任务,部分更新appWidget或重新启动服务。因此,根据您提供的信息,您应该可以在提供程序的onReceive区域中进行网络调用,但是您可能需要为其指定一个自定义方法来触发onReceive(),并确保更新所有实例并更新远程视图。例如,我们有几个自定义方法,它们会触发onReceive()并部分更新我们的appWidget:

在appWidget提供程序中:

    // sample custom intent name    
public static final String ACTION_CLICK_ADVANCE_STATUS = "widget_action_click_advance_status";

...

@Override
public void onReceive(Context context, Intent intent) {
    super.onReceive(context, intent);

    if (ACTION_CLICK_ADVANCE_STATUS.equals(intent.getAction())) {
        // update all instances of appWidgets
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, WidgetJobProvider.class));
        // Do your work here 
    }