Android Background Geolocation Service Without Any Kill | Part 2

Android location services are very popular these days, they provide the location of a device in the form of latitude and longitude coordinates using with we can track the location up to 10 meters of accuracy. Location services provide many other parameters of a device like speed, the direction of movement, human-readable address using Geocoder…

By.

โ€ข

min read

Android location services are very popular these days, they provide the location of a device in the form of latitude and longitude coordinates using with we can track the location up to 10 meters of accuracy. Location services provide many other parameters of a device like speed, the direction of movement, human-readable address using Geocoder service.

 

 

This tutorial is the second part of the previous one, please visit part 1 here before going through this post.

 

Letโ€™s continue on the implementation of Background Geolocation Service in Android Device.

Create a Location BroadcastRecieverย 

Create a new broadcast and name it LocationUpdatesBroadcastReceiver.java,ย in this file, we will onReceive method which will be called and in turn, will call the getLocationUpdates method in Utils class.

The setLocationUpdatesResultย method will change in SharedPreference value to update text having the address and other details when the application is open.

LocationUpdatesBroadcastReceiver.javaย will look as below:

package com.freakyjolly.demobackgroundlocation;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import java.text.DateFormat;
import java.util.Date;


public class LocationUpdatesBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "LUBroadcastReceiver";
    public static final String ACTION_PROCESS_UPDATES =
            "com.freakyjolly.demobackgroundlocation.action" + ".PROCESS_UPDATES";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null) {

            final String action = intent.getAction();
            if (ACTION_PROCESS_UPDATES.equals(action)) {
                Utils.setLocationUpdatesResult(context, DateFormat.getDateTimeInstance().format(new Date()));
                Utils.getLocationUpdates(context,intent,"PROCESS_UPDATES");

            }
        }
    }
}

Next, we will create a SharedPreference Utils class namedย LocationRequestHelper.java.

What is SharedPreference in Android?

If you have a relatively small collection of key-values that youโ€™d like to save, you should use theย <a href="https://developer.android.com/reference/android/content/SharedPreferences.html">SharedPreferences</a>ย APIs. Aย <a href="https://developer.android.com/reference/android/content/SharedPreferences.html">SharedPreferences</a>ย object points to a file containing key-value pairs and provides simple methods to read and write them. Eachย <a href="https://developer.android.com/reference/android/content/SharedPreferences.html">SharedPreferences</a>ย file is managed by the framework and can be private or shared.

This file is having some methods to save and get the different type of data like string, boolean, object etc, we have not used all of them but itโ€™s better to keep all of them

LocationRequestHelper.javaย file will look this

package com.freakyjolly.demobackgroundlocation;

import android.content.Context;
import android.content.SharedPreferences;

public class LocationRequestHelper {


    private static LocationRequestHelper mSharedPreferenceUtils;
    protected Context mContext;
    private SharedPreferences mSharedPreferences;
    private SharedPreferences.Editor mSharedPreferencesEditor;

    private LocationRequestHelper(Context context) {
        mContext = context;
        mSharedPreferences = context.getSharedPreferences("com.freakyjolly.demobackgroundlocation", Context.MODE_PRIVATE);
        mSharedPreferencesEditor = mSharedPreferences.edit();
    }

    public static synchronized LocationRequestHelper getInstance(Context context) {

        if (mSharedPreferenceUtils == null) {
            mSharedPreferenceUtils = new LocationRequestHelper(context.getApplicationContext());
        }
        return mSharedPreferenceUtils;
    }

    /**
     * Stores String value in preference
     */
    public void setValue(String key, String value) {
        mSharedPreferencesEditor.putString(key, value);
        mSharedPreferencesEditor.commit();
    }

    /**
     * Stores int value in preference
     */
    public void setValue(String key, int value) {
        mSharedPreferencesEditor.putInt(key, value);
        mSharedPreferencesEditor.commit();
    }

    /**
     * Stores Double value in String format in preference
     */
    public void setValue(String key, double value) {
        setValue(key, Double.toString(value));
    }

    /**
     * Stores long value in preference
     */
    public void setValue(String key, long value) {
        mSharedPreferencesEditor.putLong(key, value);
        mSharedPreferencesEditor.commit();
    }

    /**
     * Stores boolean value in preference
     */
    public void setValue(String key, boolean value) {
        mSharedPreferencesEditor.putBoolean(key, value);
        mSharedPreferencesEditor.commit();
    }

    /**
     * Retrieves String value from preference
     */
    public String getStringValue(String key, String defaultValue) {
        return mSharedPreferences.getString(key, defaultValue);
    }

    /**
     * Retrieves int value from preference
     */
    public int getIntValue(String key, int defaultValue) {
        return mSharedPreferences.getInt(key, defaultValue);
    }

    /**
     * Retrieves long value from preference
     */
    public long getLongValue(String key, long defaultValue) {
        return mSharedPreferences.getLong(key, defaultValue);
    }

    /**
     * Retrieves boolean value from preference
     */
    public boolean getBoolanValue(String keyFlag, boolean defaultValue) {
        return mSharedPreferences.getBoolean(keyFlag, defaultValue);
    }

    /**
     * Removes key from preference
     *
     * @param key key of preference that is to be deleted
     */
    public void removeKey(String key) {
        if (mSharedPreferencesEditor != null) {
            mSharedPreferencesEditor.remove(key);
            mSharedPreferencesEditor.commit();
        }
    }

    /**
     * Clears all the preferences stored
     */
    public void clear() {
        mSharedPreferencesEditor.clear().commit();
    }

}

Update activity_main.xmlย layout file under res>layout folder in the projectย with the following code

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/activity_main"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/request_updates_button"
        android:layout_width="276dp"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:background="@android:color/holo_green_dark"
        android:onClick="requestLocationUpdates"
        android:text="@string/request_updates"
        android:textColor="@color/startUpdate"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

    <Button
        android:id="@+id/remove_updates_button"
        android:layout_width="276dp"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:background="@android:color/holo_red_light"
        android:onClick="removeLocationUpdates"
        android:text="@string/remove_updates"
        android:textColor="@color/removeUpdate"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />


    <TextView
        android:id="@+id/location_updates_result"
        android:layout_width="325dp"
        android:layout_height="237dp"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="44dp"
        android:paddingLeft="30dp"
        android:paddingTop="10dp"
        android:paddingRight="30dp"
        android:paddingBottom="10dp"
        android:text="test"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.511"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        app:layout_constraintVertical_bias="0.651" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="139dp"
        android:layout_height="125dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/logo" />


</android.support.constraint.ConstraintLayout>

 

 

Finally,ย our project directory structure will look like this

Now run the application in a real device to check if itโ€™s working as expected. Let me know if you face some issue regarding the same.

Find full sample source code on Github here

 

 

13 responses to “Android Background Geolocation Service Without Any Kill | Part 2”

  1. ใ…ˆใ…‡ใ…… Avatar
    ใ…ˆใ…‡ใ……

    โ€ข

    Is it possible get Latiude and Longtiude when turn off the device and then turn on?

  2. Pablo Avatar
    Pablo

    โ€ข

    Good example using the fused location, but the key points (at least for me) – getting the location in real-time without being killed by the OS were berried in too much additional code, with which figuring out where the magic is is quite challenging. More than 75% of this code can be scrapped away and you will still get a perfectly running solution serving its main purpose – report you location in real-time without receiving kills.

    1. Sebastian Avatar
      Sebastian

      โ€ข

      Could you maybe let us know where the magic is happening so?

  3. Eddy Davila Avatar

    Fantastic! I have a small issue..when i close the app updates stop being sent. Is there a reason for this? Thanks

  4. Paijo Tukino Avatar

    I tried this and the apps stop broadcasting my current location after 40-50 minutes on first attempt. On second attempt (I press stop tracking and start again), it only works for about 20 minutes. Any suggestion what’s wrong ? I just cloned and compiled the source from gitHub

    1. Jolly.exe Avatar
      Jolly.exe

      โ€ข

      Hi Paijo, sometimes customized Android os has it’s own optimization features, so you need to enable the “Background Autostart” enable for this application in mobile settings.

      1. Paijo Tukino Avatar

        Thanks for the reply, I will try it and inform you the result..

  5. akshay shahane Avatar
    akshay shahane

    โ€ข

    I only receive 10-15 location updates with this code. My question is there are limitations to location updates every hour how getting location updates through pending intent solves that ?

  6. Sankeerthana Avatar
    Sankeerthana

    โ€ข

    Can I get full source code?

    1. Jolly.exe Avatar
      Jolly.exe

      โ€ข

      Hello Sankeerthana,
      I have added a source code Github link of sample application explained in this tutorial.
      Thanks
      Jolly

      1. Ron Avatar
        Ron

        โ€ข

        There isn’t a license file with the source code. What is the licensing of the source code? Can portions of the source code be used freely in other projects? Any restrictions on it’s usage?

        1. Jolly.exe Avatar
          Jolly.exe

          โ€ข

          Hi Ron, you can use this anyway you like it. If you really appreciate this project then i can add a donation link ๐Ÿ˜๐Ÿ˜€. jusk kidding. But it took two months to make it work phewww ๐Ÿ˜Š๐Ÿ˜‰

  7. Bhushan Shirwalkar Avatar

    awesome tutorial..was looking for it since long time.. Can you please (if possible after starting updates) also add checking if location service is off after starting location updates. It asks to start location service before starting location updates (as usually) but when we switch off device location after starting location updates It doesn’t check if device location is off and continue to receive location (may be) with network or nearby wifi (as FusedLocation api does usually). Thanks.

Leave a Reply to Bhushan Shirwalkar Cancel reply

Your email address will not be published. Required fields are marked *