Android-在前台服务屏幕上打开时,处理程序重复任务停止执行

时间:2018-12-19 07:50:19

标签: android multithreading foreground-service

首先,这是一个很长的问题,但仅针对一个主题,很抱歉,我不能共享任何代码,因为它是我们公司的项目,并且属于机密。我们正在使用仅在100毫秒内执行任务的前台服务。在我问这个问题之前,我们使用了多种方法在短时间内执行代码,如下所示:

  • 其中包含“ Thread.sleep”的线程(不是最佳方法,但这是我们的首次尝试,不一致),
  • 具有“ Object.wait”的线程(与上述结果相同),
  • Timer(也不一致,过一段时间就会停止执行),
  • ScheduledThreadPoolExecutor也存在上述所有问题。

在我的手机(HUAWEI P20 Lite)上,尝试了这些方法之后,我们最终决定将HandlerHandlerThread一起使用,因为该工作不需要与UI线程进行交互。 (并非总是如此,但我们为此使用了单独的处理程序。)在每种方法之间,这似乎是最一致的一种方法,但是我们不知道它是否取决于电话,制造商或其他任何因素,我的电话会停止执行使用postDelayed 循环处理程序,直到我以某种方式与应用程序UI交互,例如:在屏幕打开时触摸通知。是的,我不是在谈论单击通知本身,而是触摸或像展开详细信息文本一样再次启动处理程序。这意味着,我认为我的手机正试图通过暂停后台执行来节省电量。

现在,我们只想在屏幕打开的情况下运行此方法,因为我们已经通过删除前台运行程序的回调,通过前台服务中注册的“屏幕开关广播接收器”暂停了处理程序本身,但是在屏幕打开后,可以接收广播,但是即使执行了“ Handler.post()”,它也不会在内部运行可运行对象,因此它永远不会循环。

为您提供一些背景信息,这是我们遵循的逻辑:

我们用类似于以下代码的内容打开前台服务:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
    getApplicationContext().startForegroundService(
        new Intent(getApplicationContext(),
                   MyService.class));
}
else
{
    getApplicationContext().startService(
         new Intent(getApplicationContext(), MyService.class));
}

然后,在服务内部,我们执行以下操作:

public int onStartCommand()
{
    // notification stuff

    HandlerThread thread = new HandlerThread("myThread");
    thread.start();

    Handler handler = new Handler(thread.getLooper());
    handler.post(new Runnable() 
    {
         // do stuff
         // this runnable stops executing after some time. This is where the problem lies.
         handler.postDelayed(this, 100);
    })

    return START_STICKY;
}

onStartCommand内的处理程序不稳定,有时它不遵守延迟,或者有时根本不执行。现在,不考虑延迟不是问题,因为我们的计算不取决于经过的时间或其他因素,所以我们不必保持一致,但是如果它停止执行(在这种情况下,它确实要执行),那就是问题开始了。

要处理此问题,我们将使用Android Jetpack提供的全新类WorkManager,该类非常适合检查处理程序的状态。为了了解线程是否处于活动状态,我们在处理程序中注册了代码的最后执行时间,并将通过worker类对其进行访问。现在,如果处理程序出现故障,我们想唤醒这些处理程序。如何才能做到这一点?因为请记住,这是在屏幕打开时发生的。

编辑:这是一些有关线程执行过程的日志。

//2018-12-19 11:35:15.048 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
//2018-12-19 11:35:15.154 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
2018-12-19 11:35:15.262 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
2018-12-19 11:35:45.262 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
//2018-12-19 11:35:45.365 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
//2018-12-19 11:35:45.468 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true

有什么建议吗?有任何解决方法吗?感谢您的每一次帮助和评论,非常感谢。

2 个答案:

答案 0 :(得分:0)

在Oreo之前的设备上会发生这种情况吗?

如果您通过startForegroundService启动服务,则应立即致电setForeground上的onStartCommand。否则,服务会在短时间内被终止。

此外,您的处理程序引用是onStartCommand的本地引用,这可能就是为什么它不持久的原因。

答案 1 :(得分:0)

发现问题所在,它在我的设备(以及可能在其系统上具有EMUI的其他设备)上的其他所有地方都运行正常,这显然对电源管理非常严格。

以下是日志:

2018-12-19 16:45:52.943 12619-12822/com.example.something D/ThreadHelper: MainThread looping.
2018-12-19 16:45:52.986 1699-2028/? I/ash: com.example.something skips not important notification
2018-12-19 16:45:52.996 1699-2028/? I/ash: com.example.something { doze duration=40061 UptimeDuration=40061 } transition to: hibernation reason:
2018-12-19 16:45:52.996 1699-2028/? I/ash: perform hibernation actions: com.example.something

我的设备自行决定可以悄悄地停止不重要通知的进程,因此我通过 NotificationManager.IMPORTANCE_MAX 提高了通知的重要性。现在,它根本不会停止工作。

如果您遇到这种情况,并想确保发出通知不足以满足您的需求,那么在HUAWEI设备上,可以使用设置->电池->启动来打开一个设置。禁用自动应用程序电源管理并将其设置为手动,这样操作系统就不会(希望如此)干扰该过程。