Under the hood JobIntentService
In this article, we will discuss one problem with the JobIntentService, about which there are many questions on the relevant resources and reports in the Google tracker bug. And also about the reason for which, judging by everything, Google does not consider it a bug and will close these reports.
JobIntentServices were created for background work. They received widespread use in Android 8 and above, when the ability to use services in the background has disappeared.
In essence, they replace services in the background, as well as being managed by a task scheduler (JobScheduler).
Thus, the system has the ability to control the progress of tasks in the background as well as manage wakelockes, which allowed optimizing the device’s battery consumption and avoiding incorrect use of wakelock developers. These steps allowed to minimize the situation when the device cannot plunge into sleep mode (Doze Mode), which again affects the battery saving.
JobIntentService in brief
In essence, JobIntentService is the same IntentService managed by a task scheduler (JobScheduler).
It is executed in the AsyncTask background thread.
In versions of Android 4.4 and below, the usual IntentService is used.
Life cycle and pitfalls
Both types of tasks have the same life cycle. Tasks are controlled by a Handler and have states.
Although these states are not accessible from the outside, under certain circumstances the system throws exceptions in which the application “crashes”. These behaviors are a problem and a headache for many developers and unfortunately do not have a simple solution. To begin with, we will study the states and the life cycle of tasks, and then we will look at possible solutions.
The sequence of task states
BINDING - task creation status (service binding) timeout 18 seconds.
STARTING - task start status, timeout 8 seconds.
EXECUTING - task execution status, timeout 10 minutes.
STOPPING - the task stop state (for example, after calling cancel ()), timeout 8 seconds.
FINISHED - the final state of the completed task, the last state in the life cycle of the task.
Simplified task life cycle diagram
Each task state has its own timeout. When the timeout expires, the task is interrupted regardless of its state. Actually, this is a timeout mechanism and is a pitfall. after the timeout expires, the system throws a type exception
java.lang.SecurityExceptionand the application “falls” with the following message
Caller no longer running, last stopped +1s600ms because: timed out while startingwhere
+1s600msthis time has passed since the timeout until the time the exception was thrown, and the “reason” (
because: timed out while starting) indicates what state the task was in when the timeout has expired
Experience shows that these exceptions are found in pretty loaded applications.
In confirmation of this problem can be observed both on the weak and on the top devices. This problem is also indicated by thrown exceptions with messages about timeouts. Accordingly, the decision on unloading the application and optimizing the use of JobIntentService, for example, to avoid situations when several JobIntentService are launched in parallel, suggests itself. The second solution, in some cases more trivial, and sometimes more difficult than the first option, is to use the JobService.
Also, if you google this problem, you can stumble upon other "dubious" solutions to this problem, for example, you can see the following links:
At the moment, Google is preparing a good replacement for JobService and JobIntentService - this is Worker and WorkManger from the androidx.work package.
Unfortunately, these tools are not yet ready for production and have a number of bugs, but already now, as tests have shown, they solve the problem described above.