【问题标题】:Service started by AlarmManager gets restarted with null intent after application removed from apps tray从应用程序托盘中删除应用程序后,AlarmManager 启动的服务以空意图重新启动
【发布时间】:2018-07-18 06:35:13
【问题描述】:

我是初学者 android 程序员。在尝试后台服务和后台数据下载时,我遇到了这个特殊问题:

我正在使用 AlarmManager 来安排重复的后台数据下载。

public void setBackgroundDataService(Context context, long time_in_millis) {

    Intent background_service_intent = new Intent(context, BackgroundDataService.class);
    background_service_intent.putExtra("value", val);
    PendingIntent pending_intent = PendingIntent.getService(context, BACKGROUND_DATA_SERVICE_ID , background_service_intent, PendingIntent.FLAG_UPDATE_CURRENT);

    cancelBackgroundServiceAlarmIfExists(context, background_service_intent);

    AlarmManager alarm_manager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
    alarm_manager.setRepeating(AlarmManager.RTC, (System.currentTimeMillis() + time_in_millis), time_in_millis, pending_intent);
}


public static void cancelBackgroundServiceAlarmIfExists(Context context, Intent intent) {

    // try to cancel Pending Intent if exists
    try {
        PendingIntent pending_intent = PendingIntent.getService(context, BACKGROUND_DATA_SERVICE_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarm_manager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
        alarm_manager.cancel(pending_intent);
        Log.d("DEBUG", "Background service terminated");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

这是来自服务的 onStartCommand():

public int onStartCommand(Intent intent, int flags, int startId) {

    Log.d("DEBUG", "Background service invoked");

    if (intent == null)
        return super.onStartCommand(intent, flags, startId);

    Bundle extras = intent.getExtras();

    some_value = extras.getString("value");

    startDataDownload();

    return super.onStartCommand(intent, flags, startId);
}

数据下载在 AsyncTask 中进行

所以问题是: 为什么从应用程序托盘刷应用程序后服务重新启动并且传入参数的意图为空。服务的正常工作依赖于在意图中传递的额外内容。起初我的应用程序会崩溃(通常是 2 次,我假设某些东西试图重新启动它,但是在尝试从 null 意图中获取额外内容时崩溃了)。一段时间后,服务将正常启动并完成其工作而不会崩溃(可能 AlarmManager 在指定时间后以适当的意图重新启动它)。然后偶尔它会再次崩溃。我设法通过检查意图是否为空来避免崩溃。它似乎工作。但问题仍然存在。

为什么在我从应用程序托盘中滑动我的应用程序后,我的服务会重新启动并且 null 意图传递给它。有什么可以做的吗?有没有更好的定期下载数据的方法?

【问题讨论】:

    标签: android android-service scheduled-tasks android-pendingintent


    【解决方案1】:

    onStartCommand() 中,您将返回 START_STICKY,因为:

    return super.onStartCommand(intent, flags, startId);
    

    START_STICKY 告诉 Android 如果Service 被杀死(无论出于何种原因),它应该重新启动您的Service。当您从最近的任务列表中滑动您的应用时,Android 会终止托管您的应用的操作系统进程,然后,因为您的Service 返回了START_STICKY,Android 会重新启动您的Service

    重启你的Service后,Android调用onStartCommand()并带有一个空的Intent参数。

    数据下载完成后,您似乎也没有停止Service

    如果您只希望 Service 在处理某事时被杀死时重新启动,请从 onStartCommand() 返回 START_REDELIVER_INTENT

    documentation for Service 对此进行了解释:

    对于已启动的服务,还有两种额外的主要模式 他们可以决定运行的操作,具体取决于他们的价值 从 onStartCommand() 返回:START_STICKY 用于服务 根据需要显式启动和停止,而 START_NOT_STICKY 或 START_REDELIVER_INTENT 用于仅应 在处理发送给它们的任何命令时保持运行。

    【讨论】:

      【解决方案2】:

      我最近遇到了这种问题。所以我所做的就是让我的服务看起来像一个前台任务,这将解决你的问题。为此,我能想到的最好方法是使用通知。 Here is the required documentation。这是通知的示例代码 -

       private void showNotification() {
          String notificationTitle = "Notification Title";
          String notificationContent = "Notification Content";
      
          Intent notificationIntent = new Intent(getApplicationContext(), DashboardActivity.class)
                  .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
          PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0,
                  notificationIntent, 0);
      
          Notification notification = new NotificationCompat.Builder(context, channelId)
                  .setTicker(AppConstants.App_Name)
                  .setSmallIcon(R.drawable.logo)
                  .setContentTitle(notificationTitle)
                  .setColor(getApplicationContext().getResources().getColor(R.color.colorWhite))
                  .setStyle(new NotificationCompat.BigTextStyle().bigText(notificationContent))
                  .setAutoCancel(false)
                  .setOngoing(true)
                  .setContentIntent(pendingIntent)
                  .build();
      
          startForeground(1, notification);
      }
      

      如果您想停止此过程,只需在您喜欢的任何地方致电void stopForeground (int flags)。它不会终止您的服务,但您的进程将不再是前台任务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多