Android 当我刷出我的应用程序时,单独进程上的服务 运行 被杀死(运行 在其他进程中)

Android Service running on separate Process gets killed when I swipe out my App (running in other process)

我有一个 Android 服务(Servcie 接口的实现),与我的真实应用程序相比,它 运行 在一个单独的进程中。不幸的是,当我离开我的真实应用程序(我在其中单击按钮以启动我的服务)并将其从任务管理器中滑出时,我的服务也被终止了。

我知道这里有很多这样的问题,但不知何故 none 是针对我具体星座中的问题,或者他们的回答含糊不清。

所以在我的清单中我有类似的东西:

<application ...>
    <activity .../>
    <service Android:name="MyService"
        Android:label="MyLabel"
        Android:export="false"
        Android:process=":MyRemoteProcessName" />
</application>

我首先使用了 IntentService,但也切换到自己的服务接口实现(消除了 IntentService 成为故障点),它看起来像:

public class MyService extends Service {

    private ScheduledExecutorService scheduledWorker = Executors.newSingleThreadScheduledExecutor();

    @Override
    public void onStart() {
        // Init components
        startForeground(this, MyNotification);
    }

    @Override
    public int onStartCommand(Intent i, int startId) {
        // Execute Work on Threadpool here
        scheduledWorker.execute(new ScheduledStopRequest(this, startId), 5, TimeUnit.Minutes);
        return START_REDILIVER_INTENT;
    }

    // Overwritten onDestroy-Method

    @Override
    public void onLowMemory() {
        Log.e(LOG_TAG, "On Low Memory called!");
    }

    @Override
    public IBind onBind() {
        // Dont't want to let anyone bind here
        return null;
    }

    // Simply tries to stop the service after e.g. 5 Minutes after a call
    private static class MyRunnable implements Runnable {

        // Constructor with params used in run method..

        @Override
        public void run() {
            mReferenceToMyService.stopSelfResult(startId);
        }
    }
}

我在一个特殊按钮上的 onClick-Listener 中启动我的服务,具有明确的 Intent,类似于以下内容:

@Override
public void onClick(View v) {
    Intent i = new Intent(this, MyService.class);
    startService(i);
}

我的意图是在用户离开应用程序时保留服务 运行,以便服务可以完成下载和存储一些重要数据。当用户再次回到我的应用程序时,他可以查看数据(这就是我在单独的进程中执行它的原因)。那么这可能吗?

我现在的假设是,Android 以某种方式注意到我的服务正被我的应用程序使用(由于清单中缺少 IntentFilters 或显式调用而不是过滤器?!)并因此立即终止它当我的应用程序关闭时(即使 运行 为 ForegroundService,如上所示)。

在您看来这是否可行,服务调用中的一些更改是否可以解决此问题,或者我对服务的概念理解有误?

(最后一点:onLowMemory-Method 没有被调用 -> 没有日志条目。)

很遗憾,运行 单独进程中的服务对您没有帮助。我认为如果用户删除其任务,您无法阻止您的服务关闭。然而,您可以重新启动您的服务覆盖 onTaskRemoved。看到这个 .

如果你想运行这个服务 class 在关闭应用程序后也无限期..你应该使用 Alaram Manager class ..

public void scheduleAlarm() {
        // Construct an intent that will execute the AlarmReceiver
        Intent intent = new Intent(this, LocationListnerServiec.class);
        // Create a PendingIntent to be triggered when the alarm goes off
        final PendingIntent pIntent = PendingIntent.getBroadcast(this, MyAlarmReceiver.REQUEST_CODE,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        // Setup periodic alarm every 5 seconds
        long firstMillis = System.currentTimeMillis(); // alarm is set right away
        AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        // First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
        // Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
        alarm.setRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
                60000, pIntent);
    }

使用此方法继续检查服务 class 是否打开。通过使用此方法,您的服务 class 将在您的应用程序销毁后继续工作。

所以,根据您的提示(以及让我寻找的新关键字)和我自己的一些额外研究,我想我已经解决了我的问题。在我的研究过程中,我发现了一个关于这个主题的非常有趣的博客 post,也许也适合你,这就是为什么我想与你分享它:http://workshop.alea.net/post/2016/06/android-service-kill/ .

在验证并完成本文中的步骤后,一切似乎都正常(因此 startForeground 似乎解决了问题)。我想在这里指出,我只测试过它,我的服务实例仍在单独的进程中 运行,因此清单条目如上所述。

一开始真正让我感到困惑的是我的 android 工作室调试会话每次都被终止,就在从最近的应用程序(菜单)中刷出我的应用程序之后。这让我觉得我的服务也被系统杀死了。但是根据文章(我在提供的回调方法中添加了一些日志)当

  1. 正在打开我的应用程序

  2. 正在启动服务

  3. 刷出应用程序

  4. 再次启动应用程序,终于

  5. 再次调用服务,

我只收到了对方法的回调,就好像我的服务仍然 运行 一样。明确查看 DDMS(工具)也证明了我的第二个过程,因此我的服务仍然存在。验证这一点后,我清除了所有应用程序数据并重复上述步骤(不包括第 5 步)。之后查看了数据库,证明数据已经被服务下载了。

好奇的你:

从最近的应用程序中刷出我的应用程序(并因此调用 onTaskRemoved 回调方法)的过程导致了另一个问题。它以某种方式将 onStartCommand 的 startId 参数增加 1,以便我的 DelayedStopRequest 发生故障并且不再停止我的服务。

这意味着:重复上述步骤 1 - 3 使我在 onStartCommand 中收到 startId = 1。通过稍后调用 stopSelfResult(1)(这是最新的 startId),它返回 false 并且服务保持 运行。然后继续执行步骤 4 + 5,使 onStartCommand 以 startId = 3 被调用(但实际上应该是 2!以某种方式被跳过)。稍后使用参数 3 调用 stopSelfResult(3) 将再次停止服务(在屏幕截图中也可见)。

我希望到目前为止我的回答是正确的(可以理解)并且对您也有帮助。感谢您提供的所有答案,这些答案提供了有益的输入,也为我指出了解决方案。我一直在使用的 android 版本是:

4.1.2 - 果冻豆 | API 等级 : 16

我还添加了来自 DDMS 的日志条目的屏幕截图(imgur 拒绝我的上传,所以你会暂时有一个 link 到我的保管箱): screenshots from logs from DDMS