Update : I have written a detailed article about this at https://medium.com/@lokeshloke/preparing-for-an-android-system-design-interview-84991519807a
Statement : Design an android application which shares it's location with a server for tracking.
Breakdown :
Any android application design should consider the following aspects.
So in this case, the following questions needs to be clarified before starting with the solution.
Approach :
Once the above questions are clarified, we get a basic idea of how the app is to be implemented. Please note that some of the above questions are exclusive to android platform.
Location Fetch :
Play Services allow to get user location periodically by specifying the details in the location request. Battery optimisations are taken care by the library.// Refer play services location request docs
locationRequest = new LocationRequest()
.setPriority(LOCATION_PRECISION_CODE)
.setInterval(LOCATION_TIME_THRESHOLD); Incase of unavailability of play services, the app has to use framework provided api to
track the user location. This is very important as many devices in some countries do not have play services installed. locationManager.requestLocationUpdates(LOCATION_PROVIDER,
LOCATION_TIME_THRESHOLD,
LOCATION_DISTANCE_THRESHOLD, locationListener);-> Persistence :
Locations with timestamp are to be stored in the device since the history has to be maintained as well as failed postings have to be repeated. The db structure is as follows id latitude longitude timestamp is_posted-> Loosy Network :
Locations that were not reported because of network failure should be periodically posted to server (Ask for the period). For this we need to schedule a task which runs periodically to query the db and post the locations that were not posted.-> Scheduling Task :
With the background restrictions introduced in Android Oreo, using alarm services is error prone and has a lot of drawbacks. Background Jobs introduced in Android Lollipop would be a good alternative but they are not supported below Android 21. So a combination of Alarm service , GCM network manager and Android Job Schedular should be used for scheduling. Refer Evernote Job Schedular library documentation.
public class LocationSyncJob extends Job {
public static final String TAG = "location_job";
@Override
@NonNull
protected Result onRunJob(Params params) {
// Iterate db
LocationRepository repo = LocationRepository.getRepository(getContext());
TrackerDatabase db = repo.getDb(getContext());
List<LocationModel> locationList = db.locationDao().getNonPostedLocations();
for(LocationModel model: locationList){
LocationRepository.postLocation(model);
}
return Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(LocationSyncJob.TAG)
.setPeriodic(TimeUnit.MINUTES.toMillis(AppConfig.SYNC_TIME), TimeUnit.MINUTES.toMillis(AppConfig.SYNC_GRACE_TIME))
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setUpdateCurrent(true)
.build()
.schedule();
}
}
-> Handling Doze Mode & Background Restrictions of Oreo :
Doze mode introduced in android marshmallow performs battery optimisations by keeping the device in sleep mode and forcing network restrictions on it. Also the background restrictions introduced in android Oreo restrict the background apps to receive background locations only a few times per hour.
To handle both these issues and continuously track user location, app has to appear as a foreground process for the android system.This could be achieved by starting a foreground service in the app.Refer android docs for more information on Foreground services.This way we can bypass both the restrictions and app can continuously receive and post locations.Notification notification = new NotificationCompat.Builder(this,CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.tracking_now))
.setContentIntent(pendingIntent).build();
startForeground(1, notification);