【问题标题】:Network request from appWidget来自 appWidget 的网络请求
【发布时间】:2019-11-26 11:09:28
【问题描述】:

关于 SO 有许多类似的问题,但它们都是 pre-O,其中 IntentService 工作得很好。我尝试将其作为 JobIntentService 进行,但延迟是不可接受的。我的小部件的网络交换应该非常快,或者根本没有,socketTimeout 设置为 100 毫秒,所以几秒钟的延迟令人沮丧。

我想在这里尝试几种解决方案。首先,从上下文创建一个foregroundService。据我了解,在服务被终止之前我有 5 秒的时间,所以如果我的交换只需要它的一小部分,我应该很好。这个假设正确吗?这对foregroundService 有用吗?

接下来,如果我只是通过在我的 AppWidgetProvider 的 onReceive 中手动启动一个新线程来实现呢?正如我所说,网络交换应该不到四分之一秒。在此期间,上下文可能会发生什么?

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

【问题讨论】:

    标签: android android-appwidget


    【解决方案1】:

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

    关于您的第一个问题:
    该服务从 appWidget 提供者调用并完成所有工作,它必须作为 Oreo+ 上的前台服务调用,如果该前台服务未在该调用后 5 秒内启动,您将收到异常:“Context.startForegroundService did然后不调用 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(),并确保更新所有实例appWidget 以及更新远程视图。例如,我们有几个自定义意图触发 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 
        }
    

    【讨论】:

    • foregroundService 的想法是实际上从不显示任何通知或任何内容。无论如何,用户(在一秒钟内)会立即看到服务的工作结果,所以为什么要打扰无用的通知。所以我想知道如果我在超时到期之前完成所有工作并完成会发生什么。
    • 您必须启动前台服务,否则您会遇到异常,并且您无法在没有通知的情况下启动前台服务 - 这从版本 26 (Oreo) 开始。参见安卓文档:developer.android.com/about/versions/oreo/background。如果您不使用服务,您将被困在每个小部件 xml 文件的 appWidget 最少 30 分钟的定期更改中。并且如果不能使用 Job Service 代替前台 Service,则必须使用通知通道来启动前台服务。你能做的最好的就是尽量减少它。
    • 另一种选择是尝试使用我在答案后半部分提到的 onReceive() 方法。创建一个自定义意图并在 onReceive() 中捕获它。如果您所做的只是用户看不到的东西,那么在没有服务的情况下也可以工作。您要求回答 2 个选项。前台选项需要通知。
    猜你喜欢
    • 2015-05-09
    • 2022-10-02
    • 2020-10-11
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 2019-06-01
    • 2018-08-01
    • 1970-01-01
    相关资源
    最近更新 更多