Hi !
Yonatan V.Levin
levin.yonatan parahall
Google Developer Expert
CTO & Co Founder
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Why app is crashed when got an update
from widget?
Background
Android 101
Memory @ Android
!=
SWAP Space No Swap space
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
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
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
Activity Manager
Process Process Process
oom_adj: 0 oom_adj: 2 oom_adj: 1
Free memory
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
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.
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
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Rowing direction
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
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.
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.
The king is dead. Long live the king
"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
Let’s explore very simple scenario
App in Foreground - Let’s execute it now!
ExecutorService executor = Executors.newFixedThreadPool(threads);
executor.submit(myWork);
App in Foreground - Let’s execute it now!
ExecutorService executor = Executors.newFixedThreadPool(threads);
executor.submit(myWork);
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Login succeeded?
OkHttp
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
retry = 3;
Worst case scenario: 3 * 30 = 90 seconds.
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?
So, we need to switch to use a
service.
But you can’t!!!!
Don’t put your hands down
Let’s use JobScheduler
JobScheduler mJobScheduler = (JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE);
int jobInfoNetworkType = convertNetworkType(constraints.getRequiredNetworkType());
PersistableBundle extras = new PersistableBundle();
extras.putBoolean(EXTRA_IS_PERIODIC, isPeriodic);
JobInfo.Builder builder = new JobInfo.Builder(jobId, serviceComponent)
.setRequiredNetworkType(jobInfoNetworkType)
.setRequiresCharging(false)
.setRequiresDeviceIdle(false)
.setExtras(extras)
.setPersisted(true)
.build();
mJobScheduler.schedule(jobInfo);
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
if (Build.VERSION.SDK_INT >= 23) {
//use JobService
}
But I have minSDK < 21 23
JobDispatcher
Job myJob = firebaseJobDispatcher.newJobBuilder()
.setService(SmartService.class)
.setTag(SmartService.LOCATION_SMART_JOB)
.setRecurring(true)
.setLifetime(FOREVER)
.setTrigger(Trigger.executionWindow(0, 60 * 5))
.setReplaceCurrent(false)
.setConstraints(ON_ANY_NETWORK)
.build();
firebaseJobDispatcher.mustSchedule(myJob);
No promise when a job executed
And more…
+--- com.firebase:firebase-jobdispatcher:0.5.2
| +--- com.android.support:support-v4:25.0.0 -> 25.3.0 (*)
| --- com.google.android.gms:play-services-gcm:10.0.1 -> 10.2.1
| +--- com.google.android.gms:play-services-base:10.2.1
| | +--- com.google.android.gms:play-services-basement:10.2.1
| | | --- com.android.support:support-v4:24.0.0 -> 25.3.0 (*)
| | --- com.google.android.gms:play-services-tasks:10.2.1
| | --- com.google.android.gms:play-services-basement:10.2.1 (*)
| +--- com.google.android.gms:play-services-basement:10.2.1 (*)
| --- com.google.android.gms:play-services-iid:10.2.1
| +--- com.google.android.gms:play-services-base:10.2.1 (*)
| --- com.google.android.gms:play-services-basement:10.2.1 (*)
+--- com.firebase:firebase-jobdispatcher:0.5.2
| +--- com.android.support:support-v4:25.0.0 -> 25.3.0 (*)
| --- com.google.android.gms:play-services-gcm:10.0.1 -> 10.2.1
| +--- com.google.android.gms:play-services-base:10.2.1
| | +--- com.google.android.gms:play-services-basement:10.2.1
| | | --- com.android.support:support-v4:24.0.0 -> 25.3.0 (*)
| | --- com.google.android.gms:play-services-tasks:10.2.1
| | --- com.google.android.gms:play-services-basement:10.2.1 (*)
| +--- com.google.android.gms:play-services-basement:10.2.1 (*)
| --- com.google.android.gms:play-services-iid:10.2.1
| +--- com.google.android.gms:play-services-base:10.2.1 (*)
| --- com.google.android.gms:play-services-basement:10.2.1 (*)
Tens millions of devices
Let’s use Alarm + Executer?
AlarmManager alarmManager = (AlarmManager)
context.getSystemService(Context.ALARM_SERVICE);
Intent delayMet = CommandHandler.createIntent(context, workSpecId);
PendingIntent pendingIntent = PendingIntent.getService(
context, alarmId, delayMet, PendingIntent.FLAG_ONE_SHOT);
alarmManager.set(RTC_WAKEUP, triggerAtMillis, pendingIntent);
PowerManager powerManager = (PowerManager)
getSystemService(Context.POWER_SERVICE);
powerManager.newWakeLock(PARTIAL_WAKE_LOCK, "tag").acquire();
WakeLock Pain
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
What about constraints & rescheduling?
Wait.
But I still want to benefit from old
services on pre-O devices!
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
JobIntentService
Context.startService()
< >=
JobScheduler.enqueue()
setOverrideDeadline(0)
JobIntentService
onStartJob(JobParams)
JobService
onHandleWork(Intent intent);
onStopJob(JobParams ) onStopCurrentWork()
Oh! Someone restarted a phone!
BOOT_COMPLETED
<receiver
android:name=".AppReceiver"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"
/>
</intent-filter>
</receiver>
The fight which hard to win
So let’s start to think about more
abstract solution
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
WorkManager
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.
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Data
Data
enqueue()
WorkManager
JobScheduler
JobDispatcher
Executor
AlarmManager
WorkDatabase
WorkRequest
saveWork
updateWorkState
publish
Processor
Worker
WorkResult
Data
enqueue()
WorkManager
JobScheduler
JobDispatcher
Executer
AlarmManager
WorkDatabase
WorkRequest
saveWork
updateWorkState
publish
Processor
Worker
Data
WorkResult
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;
}
}
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;
}
}
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;
}
}
Data
enqueue()
WorkManager
JobScheduler
JobDispatcher
Executer
AlarmManager
WorkDatabase
WorkRequest
saveWork
updateWorkState
publish
Processor
Worker
Data
WorkResult
Constraints constr = new Constraints.Builder().
setRequiredNetworkType(NetworkType.CONNECTED).build();
Data inputData = new Data.Builder()
.putDouble(LOCATION_LAT, location.getLatitude())
.putDouble(LOCATION_LONG, location.getLongitude())
.putLong(LOCATION_TIME, location.getTime()).build();
OneTimeWorkRequest uploadWork = new
OneTimeWorkRequest.Builder(LocationUploadWorker.class)
.setConstraints(constr).setInputData(inputData).build();
Constraints constr = new Constraints.Builder().
setRequiredNetworkType(NetworkType.CONNECTED).build();
Data inputData = new Data.Builder()
.putDouble(LOCATION_LAT, location.getLatitude())
.putDouble(LOCATION_LONG, location.getLongitude())
.putLong(LOCATION_TIME, location.getTime()).build();
OneTimeWorkRequest uploadWork = new
OneTimeWorkRequest.Builder(LocationUploadWorker.class)
.setConstraints(constr).setInputData(inputData).build();
Constraints constr = new Constraints.Builder().
setRequiredNetworkType(NetworkType.CONNECTED).build();
Data inputData = new Data.Builder()
.putDouble(LOCATION_LAT, location.getLatitude())
.putDouble(LOCATION_LONG, location.getLongitude())
.putLong(LOCATION_TIME, location.getTime()).build();
OneTimeWorkRequest uploadWork = new
OneTimeWorkRequest.Builder(LocationUploadWorker.class)
.setConstraints(constr).setInputData(inputData).build();
Constraints constr = new Constraints.Builder().
setRequiredNetworkType(NetworkType.CONNECTED).build();
Data inputData = new Data.Builder()
.putDouble(LOCATION_LAT, location.getLatitude())
.putDouble(LOCATION_LONG, location.getLongitude())
.putLong(LOCATION_TIME, location.getTime()).build();
OneTimeWorkRequest uploadWork = new
OneTimeWorkRequest.Builder(LocationUploadWorker.class)
.setConstraints(constr).setInputData(inputData).build();
Data
enqueue()
WorkManager
JobScheduler
JobDispatcher
Executer
AlarmManager
WorkDatabase
WorkRequest
saveWork
updateWorkState
publish
Processor
Worker
Data
WorkResult
WorkManager.getInstance().enqueue(uploadWork);
Data
Data
enqueue()
WorkManager
JobScheduler
JobDispatcher
Executer
AlarmManager
WorkDatabase
WorkRequest
saveWork
updateWorkState
publish
Processor
Worker
WorkResult
JobScheduler
JobDispatcher
Executer
AlarmManager
WorkDatabase
updateWorkState
publish
Processor
Data
enqueue()
WorkManager
WorkRequest
saveWork
Worker
publish
Data
WorkResult
Data
Data
enqueue()
WorkManager
JobScheduler
JobDispatcher
Executer
AlarmManager
WorkDatabase
WorkRequest
saveWork
updateWorkState
publish
Processor
Worker
WorkResult
workManager.getStatusById(locationWork.getId()).observe(
this, workStatus -> {
if(workStatus!=null && workStatus.getState().isFinished()){
...
workStatus.getOutputData()...
}
}
workManager.getStatusById(locationWork.getId()).observe(
this, workStatus -> {
if(workStatus!=null && workStatus.getState().isFinished()){
...
workStatus.getOutputData()...
}
}
workManager.getStatusById(locationWork.getId()).observe(
this, workStatus -> {
if(workStatus!=null && workStatus.getState().isFinished()){
...
workStatus.getOutputData()...
}
}
PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
WorkManager.getInstance().enqueue(locationWork);
Location
Every 15 min
PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
WorkManager.getInstance().enqueue(locationWork);
Location
Every 15 min
WorkManager.getInstance(this)
.beginWith(Work.from(LocationWork.class))
.then(Work.from(LocationUploadWork.class))
.enqueue();
Upload
Location
WorkManager.getInstance(this)
.enqueue(Work.from(LocationWork.class,LocationUploadWork.class));
Upload
Location
Note:
You can’t enqueue chain of periodic and one-time work
together.
PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
workManager.enqueue(locationWork);
workManager.cancelWorkById(locationWork.getId());
Cancel
PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
workManager.enqueue(locationWork);
workManager.cancelWorkById(locationWork.getId());
Cancel
PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
Location
Every 15 min
Location
Every 15 min
PeriodicWorkRequest locationWork = new
PeriodicWorkRequest.Builder(LocationWork.class, 15,TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
workManager.cancelAllWorkByTag(LocationWork.TAG);
Real Life
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
public class MyActivity extends AppCompatActivity {
protected void onCreate(...) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType .CONNECTED).build();
OneTimeWorkRequest profileFetchWork =
new OneTimeWorkRequest.Builder(ProfileFetchWorker.class)
.setConstraints(constraints).build();
WorkManager workManager = WorkManager.getInstance();
workManager.enqueue(profileFetchWork);
…
}
}
public class MyActivity extends AppCompatActivity {
protected void onCreate(...) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType .CONNECTED).build();
OneTimeWorkRequest profileFetchWork =
new OneTimeWorkRequest.Builder(ProfileFetchWorker.class)
.setConstraints(constraints).build();
WorkManager workManager = WorkManager.getInstance();
workManager.enqueue(profileFetchWork);
…
}
}
public class MyActivity extends AppCompatActivity {
protected void onCreate(...) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType .CONNECTED).build();
OneTimeWorkRequest profileFetchWork =
new OneTimeWorkRequest.Builder(ProfileFetchWorker.class)
.setConstraints(constraints).build();
WorkManager workManager = WorkManager.getInstance();
workManager.enqueue(profileFetchWork);
…
}
}
public class MyActivity extends AppCompatActivity {
protected void onCreate(...) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType .CONNECTED).build();
OneTimeWorkRequest profileFetchWork =
new OneTimeWorkRequest.Builder(ProfileFetchWorker.class)
.setConstraints(constraints).build();
WorkManager workManager = WorkManager.getInstance();
workManager.enqueue(profileFetchWork);
…
}
}
public class MyActivity extends AppCompatActivity {
protected void onCreate(...) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType .CONNECTED).build();
OneTimeWorkRequest profileFetchWork =
new OneTimeWorkReques .Builder(ProfileFetchWorker.class)
.setConstraints(constraints).build();
WorkManager workManager = WorkManager.getInstance();
workManager.enqueue(profileFetchWork);
…
}
}
public class ProfileFetchWorker extends Worker {
public WorkerResult doWork() {
List<Profile> profiles = loadProfiles(getAppContext());
Data profileData = ResUtil.profileToMap(profiles);
setOutputData(profileData);
return WorkerResult.SUCCESS;
}
}
public class ProfileFetchWorker extends Worker {
public WorkerResult doWork() {
List<Profile> profiles = loadProfiles(getAppContext());
Data profileData = ResUtil.profileToMap(profiles);
setOutputData(profileData);
return WorkerResult.SUCCESS;
}
}
public class ProfileFetchWorker extends Worker {
public WorkerResult doWork() {
List<Profile> profiles = loadProfiles(getAppContext());
Data profileData = ResUtil.profileToMap(profiles);
setOutputData(profileData);
return WorkerResult.SUCCESS;
}
}
public class ProfileFetchWorker extends Worker {
public WorkerResult doWork() {
List<Profile> profiles = loadProfiles(getAppContext());
Data profileData = ResUtil.profileToMap(profiles);
setOutputData(profileData);
return WorkerResult.SUCCESS;
}
}
What about status update?
public class MyActivity extends AppCompatActivity {
public void startFetchProfiles() {
...
UUID workId = profileFetchWork.getId();
workManager.getStatusById(workId).observe(this,workStatus-> {
if (workStatus.getState().isFinished()) {
updateUI(workStatus.getOutputData());
}
});
}
}
public class MyActivity extends AppCompatActivity {
public void startFetchProfiles() {
...
UUID workId = profileFetchWork.getId();
workManager.getStatusById(workId).observe(this,workStatus-> {
if (workStatus.getState().isFinished()) {
updateUI(workStatus.getOutputData());
}
});
}
}
public class MyActivity extends AppCompatActivity {
public void startFetchProfiles() {
...
UUID workId = profileFetchWork.getId();
workManager.getStatusById(workId).observe(this,workStatus-> {
if (workStatus.getState().isFinished()) {
updateUI(workStatus.getOutputData());
}
});
}
}
public class MyActivity extends AppCompatActivity {
public void startFetchProfiles() {
...
UUID workId = profileFetchWork.getId();
workManager.getStatusById(workId).observe(this,workStatus-> {
if (workStatus.getState().isFinished()) {
updateUI(workStatus.getOutputData());
}
});
}
}
MV{x} pattern
View ViewModel Very fast API
List<Profile>
UpdateUI
ProfileFetchWorker
onChange
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Get
Profiles
ProfileDao
View ViewModel
Profile
Repository
ProfileNetworkDataSource
SQLite
Very fast API
Room
LiveData<List<Profile>
LiveData<Profile[]>
Observe
Observe
LifecycleOwner
Load
Profiles
ProfileFetchWorker
Get
Profiles
ProfileDao
View ViewModel
Profile
Repository
ProfileNetworkDataSource
SQLite
Very fast API
Room
LiveData<List<Profile>
MutableLiveData<Profile[]>
Observe
Observe
LifecycleOwner
Load
Profiles
ProfileFetchWorker
LiveData<WorkStatus>
insert
ProfileDao
View ViewModel
Profile
Repository
ProfileNetworkDataSource
SQLite
Very fast API
Room
LiveData<List<Profile>
MutableLiveData<Profile[]>
onChange
LifecycleOwner
ProfileFetchWorker
LiveData<WorkStatus>
onChange
onChange
onChange
success
Get Location
Main
Activity
Service
HandlerThread
Looper
Location
Handler
Network
Handler
Location
Tracker
BOOT_COMPLETE
D
Receiver
AlarmManager
Every 15 min
View
WorkManager
UploadWork
Location
Tracker
Every 15 min
LocationWork
public class LocationWork extends Worker {
public WorkerResult doWork() {
...
return WorkerResult.SUCCESS;
}
}
Synchronous execution
mLocationManager.
requestSingleUpdate(LocationManager.GPS_PROVIDER,
mGpsLocationListener, looper);
Asynchronous execution
public class GpsLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
...
}
}
public class LocationWork extends Worker {
public WorkerResult doWork() {
...
return WorkerResult.SUCCESS;
}
}
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
public class LocationWork extends Worker {
public WorkerResult doWork() {
handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
looper = handlerThread.getLooper();
locationTracker = new LocationTracker(getAppContext(), looper);
locationTracker.start();
...
return WorkerResult.SUCCESS;
}
}
public class LocationWork extends Worker {
public WorkerResult doWork() {
handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
looper = handlerThread.getLooper();
locationTracker = new LocationTracker(getAppContext(), looper);
locationTracker.start();
...
return WorkerResult.SUCCESS;
}
}
public class LocationWork extends Worker {
public WorkerResult doWork() {
handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
looper = handlerThread.getLooper();
locationTracker = new LocationTracker(getAppContext(), looper);
locationTracker.start();
...
return WorkerResult.SUCCESS;
}
}
public class LocationWork extends Worker {
public WorkerResult doWork() {
handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
looper = handlerThread.getLooper();
locationTracker = new LocationTracker(getAppContext(), looper);
locationTracker.start();
...
return WorkerResult.SUCCESS;
}
}
public class LocationWork extends Worker {
public WorkerResult doWork() {
...
try {
locationWait = new CountDownLatch(1);
locationWait.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
cleanUp();
return WorkerResult.SUCCESS;
}
public class LocationWork extends Worker {
public WorkerResult doWork() {
...
try {
locationWait = new CountDownLatch(1);
locationWait.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
cleanUp();
return WorkerResult.SUCCESS;
}
public class LocationWork extends Worker {
public WorkerResult doWork() {
...
try {
locationWait = new CountDownLatch(1);
locationWait.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
cleanUp();
return WorkerResult.SUCCESS;
}
PeriodicWorkRequest locationWork = new PeriodicWorkRequest
.Builder(LocationWork.class, 15, TimeUnit.MINUTES)
.addTag(LocationWork.TAG)
.build();
WorkManager.getInstance().enqueue(locationWork);
What’s next?
UploadWorker
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Naive: Foreground service
Periodic 15 min
44 locations
6% battery
Smart: JobDispatcher
Periodic 15 min
37 locations
1% battery
Worker: Mix
Periodic 15 min
38 locations
2% battery
What about getting update from system?
e.g. Alarm, GeoFence?
geofencingClient.
addGeofences(getGeofencingRequest(), getGeofencePendingIntent());
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeoFenceReceiver.class);
return PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeoFenceReceiver.class);
return PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
WHY?
sendBroadcast(new Intent("this.is.an.implicit.broadcast"));
04-11 14:12:36.340 753-763/? W/BroadcastQueue: Background execution
not allowed: receiving Intent {
act=android.intent.action.PACKAGE_REMOVED
dat=package:com.commonsware.cwac.cam2.demo flg=0x4000010 (has
extras) } to
com.commonsware.android.sysevents.pkg/.OnPackageChangeReceiver
<receiver
android:name=".GeoFenceReceiver"
android:enabled="true"
android:exported="true"/>
public class GeoFenceReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
...
}
}
public class GeoFenceReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
Location location = event.getTriggeringLocation();
Data inputData = ResourceUtil.locToData(location);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest
.Builder(LocationUploadWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
}
}
public class GeoFenceReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
Location location = event.getTriggeringLocation();
Data inputData = ResourceUtil.locToData(location);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest
.Builder(LocationUploadWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
}
}
public class GeoFenceReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
Location location = event.getTriggeringLocation();
Data inputData = ResourceUtil.locToData(location);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest
.Builder(LocationUploadWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
}
}
public class GeoFenceReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
Location location = event.getTriggeringLocation();
Data inputData = ResourceUtil.locToData(location);
OneTimeWorkRequest workRequest = new OneTimeWorkRequest
.Builder(LocationUploadWorker.class)
.setInputData(inputData).build();
WorkManager.getInstance().enqueue(workRequest);
}
}
Alpha Version
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
“...But android-job will soon reach it’s
end of life…”
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions
parahall

More Related Content

PDF
Knock, knock, who is there? Doze.
PDF
Deep Dive into Zone.JS
PDF
Practical Celery
PPTX
Guice gin
PDF
Exploring OpenFaaS autoscalability on Kubernetes with the Chaos Toolkit
PDF
Troubleshooting JIRA & Confluence
PDF
Creating Asha Games: Game Pausing, Orientation, Sensors and Gestures
PDF
Celery
Knock, knock, who is there? Doze.
Deep Dive into Zone.JS
Practical Celery
Guice gin
Exploring OpenFaaS autoscalability on Kubernetes with the Chaos Toolkit
Troubleshooting JIRA & Confluence
Creating Asha Games: Game Pausing, Orientation, Sensors and Gestures
Celery

What's hot (12)

PPTX
Ultimate Node.js countdown: the coolest Application Express examples
PDF
Advanced task management with Celery
PDF
PLNOG 18 - Piotr Jabłoński - Co i jak można zautomatyzować u operatora?
PPT
Find bottleneck and tuning in Java Application
PDF
Getting physical with web bluetooth in the browser hackference
PPTX
Beat the Clock: Background Tasking in Windows 8
PPTX
Physical web
PDF
Why Task Queues - ComoRichWeb
PDF
Celery - A Distributed Task Queue
PDF
50 new features of Java EE 7 in 50 minutes
PDF
Future Decoded - Node.js per sviluppatori .NET
PPTX
Will it run or will it not run? Background processes in Android 6 - Anna Lifs...
Ultimate Node.js countdown: the coolest Application Express examples
Advanced task management with Celery
PLNOG 18 - Piotr Jabłoński - Co i jak można zautomatyzować u operatora?
Find bottleneck and tuning in Java Application
Getting physical with web bluetooth in the browser hackference
Beat the Clock: Background Tasking in Windows 8
Physical web
Why Task Queues - ComoRichWeb
Celery - A Distributed Task Queue
50 new features of Java EE 7 in 50 minutes
Future Decoded - Node.js per sviluppatori .NET
Will it run or will it not run? Background processes in Android 6 - Anna Lifs...
Ad

Similar to Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions (20)

PPTX
Easy job scheduling with android
PDF
Analysing in depth work manager
PDF
Analysing in depth work manager
 
PPT
Gaad01 job scheduler
PDF
Dicoding Developer Coaching #18: Android | Membuat Aplikasi Pengingat dengan ...
PDF
Migrating From Foreground Services To WorkManager
PPTX
Android scheduling.pptx
PPTX
Services I.pptx
PDF
Android 5.0 internals and inferiority complex droidcon.de 2015
PPTX
Job schedulers android
PDF
Android Lollipop internals and inferiority complex droidcon.hr 2015
PDF
Android Best Practices - Thoughts from the Trenches
PDF
Android 8 behavior changes
PDF
Advanced android app development
PPTX
Android Whats running in background
PDF
Not Quite As Painful Threading
PPTX
A journey through android development
PDF
Android101
PPTX
Android Training (Services)
Easy job scheduling with android
Analysing in depth work manager
Analysing in depth work manager
 
Gaad01 job scheduler
Dicoding Developer Coaching #18: Android | Membuat Aplikasi Pengingat dengan ...
Migrating From Foreground Services To WorkManager
Android scheduling.pptx
Services I.pptx
Android 5.0 internals and inferiority complex droidcon.de 2015
Job schedulers android
Android Lollipop internals and inferiority complex droidcon.hr 2015
Android Best Practices - Thoughts from the Trenches
Android 8 behavior changes
Advanced android app development
Android Whats running in background
Not Quite As Painful Threading
A journey through android development
Android101
Android Training (Services)
Ad

More from MobileFest2018 (13)

PPTX
Mobile Fest 2018. Enrique López Mañas. TensorFlow for Mobile Poets
PDF
Mobile Fest 2018. Łukasz Mróz. Let’s make your DATA sexy
PDF
Mobile Fest 2018. Алексей Демедецкий. Отладка с архитектурой Redux на iOS
PPTX
Mobile Fest 2018. Илья Иванов. Как React-Native перевернул наше представление...
PDF
Mobile Fest 2018. Владимир Бондаренко. Почему переход с Apache Cordova на Rea...
PDF
Mobile Fest 2018. Алексей Лизенко. Make your project great again
PDF
Mobile Fest 2018. Артем Гетьман. Архитектура обработки ошибок: чистый, быстры...
PDF
Mobile Fest 2018. Кирилл Розов. Insert Koin
PPTX
Mobile Fest 2018. Алеся Подлесная. UX в разработке мобильных приложений
PDF
Mobile Fest 2018. Александр Сергиенко. Flutter - что за зверь такой?
PDF
Mobile Fest 2018. Fernando Cejas. What Mom Never Told You About Multi-threading
PDF
Mobile Fest 2018. Håvard Hvassing. Working with sharp tools — continuous inte...
PDF
Mobile Fest 2018. Александр Корин. Болеутоляющее
Mobile Fest 2018. Enrique López Mañas. TensorFlow for Mobile Poets
Mobile Fest 2018. Łukasz Mróz. Let’s make your DATA sexy
Mobile Fest 2018. Алексей Демедецкий. Отладка с архитектурой Redux на iOS
Mobile Fest 2018. Илья Иванов. Как React-Native перевернул наше представление...
Mobile Fest 2018. Владимир Бондаренко. Почему переход с Apache Cordova на Rea...
Mobile Fest 2018. Алексей Лизенко. Make your project great again
Mobile Fest 2018. Артем Гетьман. Архитектура обработки ошибок: чистый, быстры...
Mobile Fest 2018. Кирилл Розов. Insert Koin
Mobile Fest 2018. Алеся Подлесная. UX в разработке мобильных приложений
Mobile Fest 2018. Александр Сергиенко. Flutter - что за зверь такой?
Mobile Fest 2018. Fernando Cejas. What Mom Never Told You About Multi-threading
Mobile Fest 2018. Håvard Hvassing. Working with sharp tools — continuous inte...
Mobile Fest 2018. Александр Корин. Болеутоляющее

Recently uploaded (20)

PDF
FORM 1 BIOLOGY MIND MAPS and their schemes
PDF
Chinmaya Tiranga quiz Grand Finale.pdf
PPTX
20th Century Theater, Methods, History.pptx
DOC
Soft-furnishing-By-Architect-A.F.M.Mohiuddin-Akhand.doc
PDF
Vision Prelims GS PYQ Analysis 2011-2022 www.upscpdf.com.pdf
PDF
What if we spent less time fighting change, and more time building what’s rig...
PDF
advance database management system book.pdf
PDF
BP 704 T. NOVEL DRUG DELIVERY SYSTEMS (UNIT 1)
PPTX
202450812 BayCHI UCSC-SV 20250812 v17.pptx
PDF
My India Quiz Book_20210205121199924.pdf
PDF
Complications of Minimal Access-Surgery.pdf
PDF
Practical Manual AGRO-233 Principles and Practices of Natural Farming
PDF
Weekly quiz Compilation Jan -July 25.pdf
PDF
1.3 FINAL REVISED K-10 PE and Health CG 2023 Grades 4-10 (1).pdf
PPTX
Share_Module_2_Power_conflict_and_negotiation.pptx
PDF
Empowerment Technology for Senior High School Guide
PDF
CISA (Certified Information Systems Auditor) Domain-Wise Summary.pdf
PDF
MBA _Common_ 2nd year Syllabus _2021-22_.pdf
PDF
Hazard Identification & Risk Assessment .pdf
PDF
David L Page_DCI Research Study Journey_how Methodology can inform one's prac...
FORM 1 BIOLOGY MIND MAPS and their schemes
Chinmaya Tiranga quiz Grand Finale.pdf
20th Century Theater, Methods, History.pptx
Soft-furnishing-By-Architect-A.F.M.Mohiuddin-Akhand.doc
Vision Prelims GS PYQ Analysis 2011-2022 www.upscpdf.com.pdf
What if we spent less time fighting change, and more time building what’s rig...
advance database management system book.pdf
BP 704 T. NOVEL DRUG DELIVERY SYSTEMS (UNIT 1)
202450812 BayCHI UCSC-SV 20250812 v17.pptx
My India Quiz Book_20210205121199924.pdf
Complications of Minimal Access-Surgery.pdf
Practical Manual AGRO-233 Principles and Practices of Natural Farming
Weekly quiz Compilation Jan -July 25.pdf
1.3 FINAL REVISED K-10 PE and Health CG 2023 Grades 4-10 (1).pdf
Share_Module_2_Power_conflict_and_negotiation.pptx
Empowerment Technology for Senior High School Guide
CISA (Certified Information Systems Auditor) Domain-Wise Summary.pdf
MBA _Common_ 2nd year Syllabus _2021-22_.pdf
Hazard Identification & Risk Assessment .pdf
David L Page_DCI Research Study Journey_how Methodology can inform one's prac...

Mobile Fest 2018. Yonatan Levin. WTF with Android Background Restrictions