应用程序从应用程序托盘中删除后,AlarmManager启动的服务将以null意图重新启动

时间:2018-02-07 20:36:02

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

我是初学的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();
    }
}

这是来自Service的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 intent获取额外内容时崩溃)。经过一段时间后,Service将正常启动并完成其工作而不会崩溃(可能是AlarmManager在指定时间后使用适当的意图附加功能重新启动它)。偶尔它会再次崩溃。我设法通过检查intent是否为null来避免崩溃。它似乎工作。但问题仍然存在。

  

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

2 个答案:

答案 0 :(得分:0)

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处理某件事情时将其重新启动,请重新启动START_REDELIVER_INTENT,请从onStartCommand()返回min

documentation for Service解释了这一点:

  

对于已启动的服务,还有两种主要模式   根据他们的价值,他们可以决定参加比赛   从onStartCommand()返回:START_STICKY用于那些服务   根据需要显式启动和停止,同时START_NOT_STICKY   或START_REDELIVER_INTENT仅用于服务   在处理发送给他们的任何命令时保持运行。

答案 1 :(得分:0)

我最近遇到过这种问题。所以我所做的就是让我的服务看起来像一个前台任务,这将解决你的问题。要做到这一点,我能想到的最佳方法是使用通知。 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)。它不会扼杀您的服务,但您的流程将不再是前台任务。