Tinadm
Tinadm

Reputation: 369

Track user location like Google does

I'm developing an application that must track user location and send it to a remote server. I know there's already a ton of other questions here about this, but I was unable to find exactly what I need.

Basically I'm using FusedLocationProviderApi to receive location updates. It's really useful and easy to use. The problem is that I need to query for locations very often and it's draining the battery real quick (although maybe part of the battery use can be from the network operations to send the location to the server). However, I only need frequent updates while the user is moving.

So what I'm looking for is something like Google does to track Android users (as we can see in LocationHistory). Does anyone know if the locations obtained by Google from the smartphone are available somewhere? Or maybe a strategy to implement something similar?

Upvotes: 1

Views: 1414

Answers (3)

cYrixmorten
cYrixmorten

Reputation: 7108

A suggestion to lower battery consumption, you could use Activity Detection to determine how often you need to determine position. In this regard I can recommend https://github.com/mcharmas/Android-ReactiveLocation to which I contributed with the Activity Detection part. The library also greatly reduces the lines of coded needed to get fused locations.

The library includes a simple example of usage here: https://github.com/mcharmas/Android-ReactiveLocation/blob/master/sample/src/main/java/pl/charmas/android/reactivelocation/sample/MainActivity.java

As you wrote in the comment it is not easy to find good examples of using ActivityDetectionApi. This was also one of the reasons why I added it to the library. In fact, the documentation that was available at the time from google was outdated as they had updated Google Play Services API, but not the tutorials.

I do not have any good pointers to tutorials not using the library, but I can provide a snippet of my code using ReactiveLocation. This code is running in a Service, so it keeps track of current activity regardless of the app being in focus or not:

private void requestFilteredActivityUpdates() {

    ReactiveLocationProvider locationProvider = new ReactiveLocationProvider(getApplicationContext());
    filteredActivitySubscription = locationProvider.getDetectedActivity(0).doOnError(new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            String message = "Error on activitySubscription: " + throwable.getMessage();
            Log.e(TAG, message, throwable);
            Crashlytics.logException(throwable);
        }
    }).onErrorReturn(new Func1<Throwable, ActivityRecognitionResult>() {
        @Override
        public ActivityRecognitionResult call(Throwable throwable) {
            List<DetectedActivity> list = new ArrayList<DetectedActivity>();
            list.add(new DetectedActivity(DetectedActivity.UNKNOWN, 0));
            return new ActivityRecognitionResult(list, System.currentTimeMillis(), SystemClock.elapsedRealtime());
        }
    }).filter(new Func1<ActivityRecognitionResult, Boolean>() {
        @Override
        public Boolean call(ActivityRecognitionResult activityRecognitionResult) {

            DetectedActivity detectedActivity = activityRecognitionResult.getMostProbableActivity();

            boolean highConfidence =  detectedActivity.getConfidence() > 75;


            DetectedActivity previousActivity = ActivityDetectionModule.Recent.getDetectedActivity();
            boolean isNewActivity = detectedActivity.getType() != previousActivity.getType();
            boolean hasHigherConfidence = detectedActivity.getConfidence() > previousActivity.getConfidence();


            return mJustStarted || (highConfidence && (isNewActivity || hasHigherConfidence)); 
        }
    }).subscribe(new Action1<ActivityRecognitionResult>() {
        @Override
        public void call(ActivityRecognitionResult activityRecognitionResult) {

            DetectedActivity detectedActivity = activityRecognitionResult.getMostProbableActivity();

            Log.i(TAG, "Activity changed or increased in confidence:");

            Log.i(TAG, "New: " + ActivityDetectionModule.getNameFromType(detectedActivity.getType()) + " confidence: " + detectedActivity.getConfidence());

        }
    });
}

And in onDestroy() I call

public void unsubscribeActivityUpdates() {
    unsubscribe(filteredActivitySubscription);
}

private void unsubscribe(Subscription subscription) {
    if (subscription != null && !subscription.isUnsubscribed()) {
        Log.i(TAG, "Unsubscribe activity updates");
        try {
            subscription.unsubscribe();
        } catch (Exception e) {
            e.printStackTrace();
        }
        subscription = null;
    }
}

I hope this illustrates well enough how to use the library, otherwise feel free to ask.

Upvotes: 4

tony
tony

Reputation: 216

Instead of querying the current location you can use the FusedLocationProviderApi to notify you of Location Changes.

You probably want to use requestLocationUpdates, particulary this version which is the best suited one to use with a background task. In the LocationRequest you can use setInterval to define the update interval.

Regarding the battery consumption: Clearly constantly opening network sockets (or keeping them open) to send your location data isn't the best solution. Your app should determine when it is actually needed to send an update to your server.

Google doesn't offer an API to pull the LocationHistory directly, that's something they keep for themselves. You could query the kml location file and read it, but that's even less suitable for real-time monitoring.

Upvotes: 0

TheAnimatrix
TheAnimatrix

Reputation: 604

You can use LocationRequest for your need..

LocationRequest location= new LocationRequest();

I'm sure the constructor takes in a value ..check the android documentation.

So with location request you have functions like ,

Set interval , set smallest displacement , which fetch the location every few seconds or meters he moved.

You can also implement a locationlistener for this which gets called every time a new location is fetched .

And all you have to do at the end is request location updates from the fused api and pass the request as a parameter .

Upvotes: 1

Related Questions