With recent Android releases the wild west of endless running threads is over.
No more smoking barrels of "last 5% battery".
You are required to act and seriously consider how you became the excellent citizen of Android device and play side by side with a marshall law of background tasks. Or die trying.
It's a talk we will explore how memory affect a background process, what solutions we have today and how new WorkManager can save our lives and galaxy :)
13. Activity Manager
Process Process Process Process Process Process
oom_adj: 0 oom_adj: 2 oom_adj: 8 oom_adj: 7 oom_adj: 1 oom_adj: 9
14. Activity Manager
Process Process Process Process Process Process
oom_adj: 0 oom_adj: 2 oom_adj: 8 oom_adj: 7 oom_adj: 1 oom_adj: 9
OOM
Killer
Threshold: 10Kb, 7
16. bash-3.2# logcat -t 1000 | grep "has died"
01-29 15:01:09.577 1278 1283 I ActivityManager: Process
com.motorola.calendar (pid 8595) has died.
01-29 15:07:46.957 1278 1278 I ActivityManager: Process
com.dropbox.android (pid 8606) has died.
bash-3.2# dmesg | grep sigkill
<4>[58305.115783] send sigkill to 8595 (torola.calendar), adj 13, size
3198
<4>[58702.255462] send sigkill to 8606 (dropbox.android), adj 14, size
2942
17. What is a Service
A Service is an application component that can perform
long-running operations in the background, and it does not
provide a user interface.
18. Why Service
One of 4 core components → App entry points
Stay alive when users navigate out of your app
Can be cached
Can be run on separate process
27. Changes in O
The startService() method now throws an
IllegalStateException if an app targeting Android 8.0 tries to
use that method in a situation when it isn't permitted to
create background services.
28. More is coming
● August 2018: New apps required to target API level 26
(Android 8.0) or higher.
● November 2018: Updates to existing apps required to
target API level 26 or higher.
● 2019 onwards: Each year the targetSdkVersion
requirement will advance. Within one year following each
Android dessert release, new apps and app updates will
need to target the corresponding API level or higher.
30. "The service as we know it today - is
deprecated.
It's no longer allowed to fulfill the main
purpose - execute the long-running task in
the background. Therefore it's no longer
usable"
Yoni Levin
37. Build long running task
Maybe not so long running task, but it can takes minutes to
execute and update UI when it finished
Wait, but what if the user offline?
64. So here is the summary of what we need
- Abstraction
- Choose the best work scheduler/execution
- Execute when we meet work Criteria
- Work Persistency
- Handle Failure and Reschedule
- Remove finished job
66. WorkManager aims to simplify the developer experience by
providing a first-class API for system-driven background
processing. It is intended for background jobs that should
run even if the app is no longer in the foreground. Where
possible, it uses JobScheduler or Firebase JobDispatcher to
do the work; if your app is in the foreground, it will even try
to do the work directly in your process.
70. public class LocationUploadWorker extends Worker {
...
//Upload last passed location to the server
public WorkerResult doWork() {
ServerReport serverReport = new
ServerReport(getInputData().getDouble(LOCATION_LONG, 0),...);
FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference ref = db.getReference("WorkerReport");
ref.push().setValue(serverReport);
return WorkerResult.SUCCESS;
}
}
71. public class LocationUploadWorker extends Worker {
...
//Upload last passed location to the server
public WorkerResult doWork() {
ServerReport serverReport = new
ServerReport(getInputData().getDouble(LOCATION_LONG, 0),...);
FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference ref = db.getReference("WorkerReport");
ref.push().setValue(serverReport);
return WorkerResult.SUCCESS;
}
}
72. public class LocationUploadWorker extends Worker {
...
//Upload last passed location to the server
public WorkerResult doWork() {
ServerReport serverReport = new
ServerReport(getInputData().getDouble(LOCATION_LONG, 0),...);
FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference ref = db.getReference("WorkerReport");
ref.push().setValue(serverReport);
return WorkerResult.SUCCESS;
}
}
86. PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
WorkManager.getInstance().enqueue(locationWork);
Location
Every 15 min
87. PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
WorkManager.getInstance().enqueue(locationWork);
Location
Every 15 min
93. PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
Location
Every 15 min
94. Location
Every 15 min
PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();