Design a Location Sharing Android Application
27620

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.

  1. Bandwidth Consumption
  2. Battery Consumption
  3. Persistance
  4. Resilience
  5. Device Support / Api
  6. Memory Usage

So in this case, the following questions needs to be clarified before starting with the solution.

  1. What is the frequency of posting location ?
  2. Should the location history stored on the device ?
  3. What if the location is not reported due to bad network? Should it be posted after sometime?
  4. Is there any threshold between two location postings? Like the user should move at least 100m or for every 2 minutes ?
  5. Should the app share location even when the device is idle?
  6. What are the supported api levels ?
  7. Can the application assume the availability of play services ?
  8. Should the app post the location when it is running in the background ?

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);
Comments (7)