123

In my android app i want to get user current location every few minute interval and update in to my center server using web service. Currently i am using Fused Location Provide for get user current location, See link

now i want to know what is the best way to get user location frequently and call web service.

below is my code which gives me user current location: -

     locationrequest = LocationRequest.create();
     locationrequest.setInterval(10000);
     locationclient.requestLocationUpdates(locationrequest,new com.google.android.gms.location.LocationListener() {

        @Override
        public void onLocationChanged(Location location) {
              Log.i(TAG, "Last Known Location :" + location.getLatitude() + "," + location.getLongitude());
        }
    });

now from where i have to call this code. Can i use this in a background service or some where else.

Please provide your idea.

TIA.

Ravi Bhandari
  • 4,682
  • 8
  • 40
  • 68

13 Answers13

46

None of the rest of the answers use:

com.google.android.gms.location.FusedLocationProviderClient

Which is the Fused Location Provider and the main entry point for interacting with the fused location provider by Google, and it is very hard to find a good example. This was released mid 2017 by Google.

Google Play services location APIs are preferred over the Android framework location APIs (android.location)

If you are currently using the Android framework location APIs, you are strongly encouraged to switch to the Google Play services location APIs as soon as possible.

For you to use the Google Location API, first add this to your build.gradle

compile 'com.google.android.gms:play-services:11.0.0'

Then you can use this class Wherebouts.java:

import android.location.Location;
import android.os.Looper;
import android.util.Log;

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;

/**
 * Uses Google Play API for obtaining device locations
 * Created by alejandro.tkachuk 
 * alejandro@calculistik.com
 * www.calculistik.com Mobile Development
 */

public class Wherebouts {

    private static final Wherebouts instance = new Wherebouts();

    private static final String TAG = Wherebouts.class.getSimpleName();

    private FusedLocationProviderClient mFusedLocationClient;
    private LocationCallback locationCallback;
    private LocationRequest locationRequest;
    private LocationSettingsRequest locationSettingsRequest;

    private Workable<GPSPoint> workable;

    private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
    private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 1000;

    private Wherebouts() {
        this.locationRequest = new LocationRequest();
        this.locationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
        this.locationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
        this.locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
        builder.addLocationRequest(this.locationRequest);
        this.locationSettingsRequest = builder.build();

        this.locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult); // why? This is ridiculous, Android!
                Location currentLocation = locationResult.getLastLocation();

                GPSPoint gpsPoint = new GPSPoint(currentLocation.getLatitude(), currentLocation.getLongitude());
                Log.i(TAG, "Location Callback results: " + gpsPoint);
                if (null != workable)
                    workable.work(gpsPoint);
            }
        };

        this.mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainApplication.getAppContext());
        this.mFusedLocationClient.requestLocationUpdates(this.locationRequest,
                this.locationCallback, Looper.myLooper());
    }

    public static Wherebouts instance() {
        return instance;
    }

    public void onChange(Workable<GPSPoint> workable) {
        this.workable = workable;
    }

    public LocationSettingsRequest getLocationSettingsRequest() {
        return this.locationSettingsRequest;
    }

    public void stop() {
        Log.i(TAG, "stop() Stopping location tracking");
        this.mFusedLocationClient.removeLocationUpdates(this.locationCallback);
    }

}

From your Activity, you can use it like this, by passing a Workable object. A Workable object is nothing more than a custom Callback alike object.

 Wherebouts.instance().onChange(workable);

By using a callback like Workable, you will write UI related code in your Activity and leave the hustle of working with GPS to a helper class, like Wherebouts.

    new Workable<GPSPoint>() {
        @Override
        public void work(GPSPoint gpsPoint) {
            // draw something in the UI with this new data
        }
    };

Of course, you would need to ask for the corresponding permissions to the Android OS for your App to use. You can read the following documentation for more info about that.

Jeff Schaller
  • 2,352
  • 5
  • 23
  • 38
  • Alejandro, you suggest to use `FusedLocationProviderClient`, but this is only available with Play Services version 11.0, which has been released not so long ago. This means that If I release an app with Play Services version 11.0 all my users will need to update their Play Services, right? Are all android SDKs eligible to use Play Services 11.0 ? I also can't make it work on emulator `Google Play services out of date. Requires 11011000 but found 10298480`. Are you testing it using an emulator? – Rafael Oliveira Jun 21 '17 at 20:51
  • 1
    @RafaelOliveira you are right, the users will need to update their Play Services to the latest. About the Android SDKs eligible: Android version 2.2 (API level 8) or later is good. Yes, this code (with some business modifications) was tested on an emulator and on a real LG Nexus 5x. – Alejandro Pablo Tkachuk Jun 22 '17 at 22:10
  • 1
    Thanks. I was having some issues to run the code and found a way to update Google Play on Android Studio emulator: https://stackoverflow.com/a/44614316/297632 – Rafael Oliveira Jun 22 '17 at 22:35
  • how to deal with location settings (enable/disable) in this scenario? – Akash Bisariya Aug 31 '17 at 04:59
  • @RafaelOliveira do you mean if the user turns off location in the operating system? – Alejandro Pablo Tkachuk Sep 01 '17 at 12:42
  • 1
    @AlejandroPabloTkachuk yep, im looking for handlers for onNeedLocationChange, etc.. thanks for the code =) – Tarcisio Wensing Dec 04 '17 at 17:30
  • 41
    Your answer is correct but Question is about to get location in background. – Umesh Mar 15 '18 at 09:17
  • 3
    Yeah, this is foreground not background location tracking. – Jørgen Svennevik Notland Mar 22 '18 at 21:48
  • i just tested the code it works only in foreground not working in the background – Mudassir Jan 22 '20 at 09:15
  • instance() has static reference so it will create memory leak problem. – Arpit Patel Jul 27 '20 at 15:58
  • is it work without having googleplayService? beacause some of my devices dosen't have google play service. – Amir133 Jan 28 '21 at 09:52
  • 1
    @Amir133, no it doesn't. WIthout services android.location.LocationManager stuff should be used. You can implement both of them and check in runtime if user have google play services – Maxdestroyer Mar 11 '21 at 12:11
  • 1
    Still pausing location stats when minimized – deFreitas Nov 07 '21 at 18:36
  • LocationRequest.create() is `deprecated`, copy & paste this instead: `locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_IN_MILLISECONDS) .setWaitForAccurateLocation(false) .setMinUpdateIntervalMillis(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS) // .setMaxUpdateDelayMillis(locationMaxWaitTime) .build()` – Iglesias Leonardo Feb 16 '23 at 21:23
23

Download the source code from here (Get Current Location Using Background Service)

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="servicetutorial.service">

    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:theme="@android:style/Theme.Translucent.NoTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".GoogleService"></service>
    </application>

</manifest>

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ffffff"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#3F51B5"
        android:text="Location using service"
        android:textColor="#ffffff"
        android:textSize="20dp"
        android:gravity="center"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"

        android:orientation="vertical">



    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_height="50dp">

        <TextView
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:text="Latitude"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:textColor="#000000"
            android:textSize="20dp"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:id="@+id/tv_latitude"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:textColor="#000000"
            android:textSize="20dp"/>


    </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">

            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:text="Longitude"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_longitude"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>


        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">

            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:text="Address"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_address"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>


        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">

            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:text="Area"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_area"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>


        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">

            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:text="Locality"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_locality"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>


        </LinearLayout>

    </LinearLayout>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_start"
        android:text="Get Location"
        android:layout_alignParentBottom="true"/>



</RelativeLayout>

MainActivity.java

package servicetutorial.service;

import android.*;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.preference.PreferenceManager;
import android.renderscript.Double2;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

public class MainActivity extends Activity {
    Button btn_start;
    private static final int REQUEST_PERMISSIONS = 100;
    boolean boolean_permission;
    TextView tv_latitude, tv_longitude, tv_address,tv_area,tv_locality;
    SharedPreferences mPref;
    SharedPreferences.Editor medit;
    Double latitude,longitude;
    Geocoder geocoder;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_start = (Button) findViewById(R.id.btn_start);
        tv_address = (TextView) findViewById(R.id.tv_address);
        tv_latitude = (TextView) findViewById(R.id.tv_latitude);
        tv_longitude = (TextView) findViewById(R.id.tv_longitude);
        tv_area = (TextView)findViewById(R.id.tv_area);
        tv_locality = (TextView)findViewById(R.id.tv_locality);
        geocoder = new Geocoder(this, Locale.getDefault());
        mPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        medit = mPref.edit();


        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (boolean_permission) {

                    if (mPref.getString("service", "").matches("")) {
                        medit.putString("service", "service").commit();

                        Intent intent = new Intent(getApplicationContext(), GoogleService.class);
                        startService(intent);

                    } else {
                        Toast.makeText(getApplicationContext(), "Service is already running", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "Please enable the gps", Toast.LENGTH_SHORT).show();
                }

            }
        });

        fn_permission();
    }

    private void fn_permission() {
        if ((ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {

            if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION))) {


            } else {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION

                        },
                        REQUEST_PERMISSIONS);

            }
        } else {
            boolean_permission = true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            case REQUEST_PERMISSIONS: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    boolean_permission = true;

                } else {
                    Toast.makeText(getApplicationContext(), "Please allow the permission", Toast.LENGTH_LONG).show();

                }
            }
        }
    }

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            latitude = Double.valueOf(intent.getStringExtra("latutide"));
            longitude = Double.valueOf(intent.getStringExtra("longitude"));

            List<Address> addresses = null;

            try {
                addresses = geocoder.getFromLocation(latitude, longitude, 1);
                String cityName = addresses.get(0).getAddressLine(0);
                String stateName = addresses.get(0).getAddressLine(1);
                String countryName = addresses.get(0).getAddressLine(2);

                tv_area.setText(addresses.get(0).getAdminArea());
                tv_locality.setText(stateName);
                tv_address.setText(countryName);



            } catch (IOException e1) {
                e1.printStackTrace();
            }


            tv_latitude.setText(latitude+"");
            tv_longitude.setText(longitude+"");
            tv_address.getText();


        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(broadcastReceiver, new IntentFilter(GoogleService.str_receiver));

    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(broadcastReceiver);
    }


}

GoogleService.java

package servicetutorial.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by deepshikha on 24/11/16.
 */

public class GoogleService extends Service implements LocationListener{

    boolean isGPSEnable = false;
    boolean isNetworkEnable = false;
    double latitude,longitude;
    LocationManager locationManager;
    Location location;
    private Handler mHandler = new Handler();
    private Timer mTimer = null;
    long notify_interval = 1000;
    public static String str_receiver = "servicetutorial.service.receiver";
    Intent intent;




    public GoogleService() {

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mTimer = new Timer();
        mTimer.schedule(new TimerTaskToGetLocation(),5,notify_interval);
        intent = new Intent(str_receiver);
//        fn_getlocation();
    }

    @Override
    public void onLocationChanged(Location location) {

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    private void fn_getlocation(){
        locationManager = (LocationManager)getApplicationContext().getSystemService(LOCATION_SERVICE);
        isGPSEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        isNetworkEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!isGPSEnable && !isNetworkEnable){

        }else {

            if (isNetworkEnable){
                location = null;
                locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,1000,0,this);
                if (locationManager!=null){
                    location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                    if (location!=null){

                        Log.e("latitude",location.getLatitude()+"");
                        Log.e("longitude",location.getLongitude()+"");

                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                        fn_update(location);
                    }
                }

            }


            if (isGPSEnable){
                location = null;
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000,0,this);
                if (locationManager!=null){
                    location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                    if (location!=null){
                        Log.e("latitude",location.getLatitude()+"");
                        Log.e("longitude",location.getLongitude()+"");
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                        fn_update(location);
                    }
                }
            }


        }

    }

    private class TimerTaskToGetLocation extends TimerTask{
        @Override
        public void run() {

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    fn_getlocation();
                }
            });

        }
    }

    private void fn_update(Location location){

        intent.putExtra("latutide",location.getLatitude()+"");
        intent.putExtra("longitude",location.getLongitude()+"");
        sendBroadcast(intent);
    }


}

Add this dependency

compile 'com.google.android.gms:play-services:9.4.0'
Gowthaman M
  • 8,057
  • 8
  • 35
  • 54
Deepshikha Puri
  • 2,104
  • 22
  • 23
  • 1
    i use your code. but one problem in this. If my device is not move current location changed again and again. – Navjot.jassal May 12 '17 at 07:25
  • Yes because I am using service class and in this service class I had used the timer. that time show the user current location on every 1 sec. – Deepshikha Puri May 12 '17 at 07:41
  • i am creating a project in which user register with current location and current location saved in sql database, how can i update users current location in database.,, – Navjot.jassal May 12 '17 at 08:04
  • For this you can use the onlocationchangelistener() method. and On this method you can update the latitude and longitude in database. You want you update the database in background also..? – Deepshikha Puri May 12 '17 at 10:43
  • after registeration i get the lat long of all users and show into a listview .. after that click on listivew item and open googlemap for show the location of that user.. thats why i want to update database ,,have any idea for this.. – Navjot.jassal May 12 '17 at 10:49
  • For this you just need to save the latitude and longitude of user in db. Show that list items from db. When user clicked on listitem then just pass that latitude and longitude to google map – Deepshikha Puri May 12 '17 at 11:18
  • suppose users first lat long are save in db.then user change our location can his current lat long automatically save in db again. and replace with old latlong – Navjot.jassal May 12 '17 at 11:31
  • i use this code when i click on submit but always show latitude and longitude null then again click Service is already running.. – Navjot.jassal May 13 '17 at 07:38
  • Code:- if (boolean_permission) { if (mPref.getString("service", "").matches("")) { medit.putString("service", "service").commit(); Intent intent = new Intent(getApplicationContext(), GoogleService.class); startService(intent); Toast.makeText(Register.this, ""+getlatitude+""+getlongitude, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getApplicationContext(), "Service is already running", Toast.LENGTH_SHORT).show(); } } – Navjot.jassal May 13 '17 at 07:39
  • what happens if the intent from the service is fired while the activity is destroyed or not in foreground? – jack_the_beast Nov 08 '17 at 09:04
  • @Puri theoretically why does `requestLocationUpdates` only request for update once and you call it with a `timer.schedule` to get updates repeatedly? – Hosein Hamedi Nov 21 '17 at 07:35
  • Good Example for a quick fix – other Tall guy Jul 20 '18 at 06:12
  • Thank you very much for this solution, I faced a problem and I found this solution: https://github.com/evollu/react-native-fcm/issues/998#issuecomment-404736950 – Haya Akkad Jun 05 '19 at 06:39
  • Won't this miss the locations if the app is in the background? – behelit Dec 17 '19 at 00:13
16

Grant required permission ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION after start service

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.location.Location;
import android.location.LocationListener;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.location.SettingsClient;
import com.google.android.gms.tasks.OnCanceledListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;

import java.util.concurrent.TimeUnit;

/**
 * Created by Ketan Ramani on 05/11/18.
 */

public class BackgroundLocationUpdateService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    /* Declare in manifest
    <service android:name=".BackgroundLocationUpdateService"/>
    */

    private final String TAG = "BackgroundLocationUpdateService";
    private final String TAG_LOCATION = "TAG_LOCATION";
    private Context context;
    private boolean stopService = false;

    /* For Google Fused API */
    protected GoogleApiClient mGoogleApiClient;
    protected LocationSettingsRequest mLocationSettingsRequest;
    private String latitude = "0.0", longitude = "0.0";
    private FusedLocationProviderClient mFusedLocationClient;
    private SettingsClient mSettingsClient;
    private LocationCallback mLocationCallback;
    private LocationRequest mLocationRequest;
    private Location mCurrentLocation;
    /* For Google Fused API */

    @Override
    public void onCreate() {
        super.onCreate();
        context = this;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        StartForeground();
        final Handler handler = new Handler();
        final Runnable runnable = new Runnable() {

            @Override
            public void run() {
                try {
                    if (!stopService) {
                        //Perform your task here
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (!stopService) {
                        handler.postDelayed(this, TimeUnit.SECONDS.toMillis(10));
                    }
                }
            }
        };
        handler.postDelayed(runnable, 2000);

        buildGoogleApiClient();

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "Service Stopped");
        stopService = true;
        if (mFusedLocationClient != null) {
            mFusedLocationClient.removeLocationUpdates(mLocationCallback);
            Log.e(TAG_LOCATION, "Location Update Callback Removed");
        }
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void StartForeground() {
        Intent intent = new Intent(context, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT);

        String CHANNEL_ID = "channel_location";
        String CHANNEL_NAME = "channel_location";

        NotificationCompat.Builder builder = null;
        NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
            channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
            notificationManager.createNotificationChannel(channel);
            builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
            builder.setChannelId(CHANNEL_ID);
            builder.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE);
        } else {
            builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
        }

        builder.setContentTitle("Your title");
        builder.setContentText("You are now online");
        Uri notificationSound = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION);
        builder.setSound(notificationSound);
        builder.setAutoCancel(true);
        builder.setSmallIcon(R.drawable.ic_logo);
        builder.setContentIntent(pendingIntent);
        Notification notification = builder.build();
        startForeground(101, notification);
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.e(TAG_LOCATION, "Location Changed Latitude : " + location.getLatitude() + "\tLongitude : " + location.getLongitude());

        latitude = String.valueOf(location.getLatitude());
        longitude = String.valueOf(location.getLongitude());

        if (latitude.equalsIgnoreCase("0.0") && longitude.equalsIgnoreCase("0.0")) {
            requestLocationUpdate();
        } else {
            Log.e(TAG_LOCATION, "Latitude : " + location.getLatitude() + "\tLongitude : " + location.getLongitude());
        }
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10 * 1000);
        mLocationRequest.setFastestInterval(5 * 1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
        builder.addLocationRequest(mLocationRequest);
        builder.setAlwaysShow(true);
        mLocationSettingsRequest = builder.build();

        mSettingsClient
                .checkLocationSettings(mLocationSettingsRequest)
                .addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
                    @Override
                    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
                        Log.e(TAG_LOCATION, "GPS Success");
                        requestLocationUpdate();
                    }
                }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                int statusCode = ((ApiException) e).getStatusCode();
                switch (statusCode) {
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        try {
                            int REQUEST_CHECK_SETTINGS = 214;
                            ResolvableApiException rae = (ResolvableApiException) e;
                            rae.startResolutionForResult((AppCompatActivity) context, REQUEST_CHECK_SETTINGS);
                        } catch (IntentSender.SendIntentException sie) {
                            Log.e(TAG_LOCATION, "Unable to execute request.");
                        }
                        break;
                    case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        Log.e(TAG_LOCATION, "Location settings are inadequate, and cannot be fixed here. Fix in Settings.");
                }
            }
        }).addOnCanceledListener(new OnCanceledListener() {
            @Override
            public void onCanceled() {
                Log.e(TAG_LOCATION, "checkLocationSettings -> onCanceled");
            }
        });
    }

    @Override
    public void onConnectionSuspended(int i) {
        connectGoogleClient();
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        buildGoogleApiClient();
    }

    protected synchronized void buildGoogleApiClient() {
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
        mSettingsClient = LocationServices.getSettingsClient(context);

        mGoogleApiClient = new GoogleApiClient.Builder(context)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

        connectGoogleClient();

        mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
                Log.e(TAG_LOCATION, "Location Received");
                mCurrentLocation = locationResult.getLastLocation();
                onLocationChanged(mCurrentLocation);
            }
        };
    }

    private void connectGoogleClient() {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        int resultCode = googleAPI.isGooglePlayServicesAvailable(context);
        if (resultCode == ConnectionResult.SUCCESS) {
            mGoogleApiClient.connect();
        }
    }

    @SuppressLint("MissingPermission")
    private void requestLocationUpdate() {
        mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
    }
}

In Activity

Start Service : startService(new Intent(this, BackgroundLocationUpdateService.class));

Stop Service : stopService(new Intent(this, BackgroundLocationUpdateService.class));

In Fragment

Start Service : getActivity().startService(new Intent(getActivity().getBaseContext(), BackgroundLocationUpdateService.class));

Stop Service : getActivity().stopService(new Intent(getActivity(), BackgroundLocationUpdateService.class));

Ketan Ramani
  • 4,874
  • 37
  • 42
10

Use : GCM Network Manager

Run this to start a periodic task that will be ran even after re-boot:

PeriodicTask task = new PeriodicTask.Builder()
    .setService(MyLocationService.class)
    .setTag("periodic")
    .setPeriod(30L)
    .setPersisted(true)
    .build();
mGcmNetworkManager.schedule(task);

then in onRunTask() get current location and use it (in this example, event is submitted at the end to let UI know that location was found):

    public void getLastKnownLocation() {
    Location lastKnownGPSLocation;
    Location lastKnownNetworkLocation;
    String gpsLocationProvider = LocationManager.GPS_PROVIDER;
    String networkLocationProvider = LocationManager.NETWORK_PROVIDER;

    try {
        locationManager = (LocationManager) App.get().getSystemService(Context.LOCATION_SERVICE);

        lastKnownNetworkLocation = locationManager.getLastKnownLocation(networkLocationProvider);
        lastKnownGPSLocation = locationManager.getLastKnownLocation(gpsLocationProvider);

        if (lastKnownGPSLocation != null) {
            Log.i(TAG, "lastKnownGPSLocation is used.");
            this.mCurrentLocation = lastKnownGPSLocation;
        } else if (lastKnownNetworkLocation != null) {
            Log.i(TAG, "lastKnownNetworkLocation is used.");
            this.mCurrentLocation = lastKnownNetworkLocation;
        } else {
            Log.e(TAG, "lastLocation is not known.");
            return;
        }

        LocationChangedEvent event = new LocationChangedEvent();
        event.setLocation(mCurrentLocation);
        EventHelper.publishEvent(event);

    } catch (SecurityException sex) {
        Log.e(TAG, "Location permission is not granted!");
    }

    return;
}

The MyLocationService in whole:

public class MyLocationService extends GcmTaskService {
private static final String TAG = MyLocationService.class.getSimpleName();

private LocationManager locationManager;
private Location mCurrentLocation;

public static final String TASK_GET_LOCATION_ONCE="location_oneoff_task";
public static final String TASK_GET_LOCATION_PERIODIC="location_periodic_task";


private static final int RC_PLAY_SERVICES = 123;

@Override
public void onInitializeTasks() {
    // When your package is removed or updated, all of its network tasks are cleared by
    // the GcmNetworkManager. You can override this method to reschedule them in the case of
    // an updated package. This is not called when your application is first installed.
    //
    // This is called on your application's main thread.
    startPeriodicLocationTask(TASK_GET_LOCATION_PERIODIC,
            30L, null);
}

@Override
public int onRunTask(TaskParams taskParams) {
    Log.d(TAG, "onRunTask: " + taskParams.getTag());

    String tag = taskParams.getTag();
    Bundle extras = taskParams.getExtras();
    // Default result is success.
    int result = GcmNetworkManager.RESULT_SUCCESS;

    switch (tag) {
        case TASK_GET_LOCATION_ONCE:
            getLastKnownLocation();
            break;

        case TASK_GET_LOCATION_PERIODIC:
            getLastKnownLocation();
            break;

    }

    return result;
}


public void getLastKnownLocation() {
    Location lastKnownGPSLocation;
    Location lastKnownNetworkLocation;
    String gpsLocationProvider = LocationManager.GPS_PROVIDER;
    String networkLocationProvider = LocationManager.NETWORK_PROVIDER;

    try {
        locationManager = (LocationManager) App.get().getSystemService(Context.LOCATION_SERVICE);

        lastKnownNetworkLocation = locationManager.getLastKnownLocation(networkLocationProvider);
        lastKnownGPSLocation = locationManager.getLastKnownLocation(gpsLocationProvider);

        if (lastKnownGPSLocation != null) {
            Log.i(TAG, "lastKnownGPSLocation is used.");
            this.mCurrentLocation = lastKnownGPSLocation;
        } else if (lastKnownNetworkLocation != null) {
            Log.i(TAG, "lastKnownNetworkLocation is used.");
            this.mCurrentLocation = lastKnownNetworkLocation;
        } else {
            Log.e(TAG, "lastLocation is not known.");
            return;
        }

        LocationChangedEvent event = new LocationChangedEvent();
        event.setLocation(mCurrentLocation);
        EventHelper.publishEvent(event);

    } catch (SecurityException sex) {
        Log.e(TAG, "Location permission is not granted!");
    }

    return;
}

public static void startOneOffLocationTask(String tag, Bundle extras) {
    Log.d(TAG, "startOneOffLocationTask");

    GcmNetworkManager mGcmNetworkManager = GcmNetworkManager.getInstance(App.get());
    OneoffTask.Builder taskBuilder = new OneoffTask.Builder()
            .setService(MyLocationService.class)
            .setTag(tag);

    if (extras != null) taskBuilder.setExtras(extras);

    OneoffTask task = taskBuilder.build();
    mGcmNetworkManager.schedule(task);
}

public static void startPeriodicLocationTask(String tag, Long period, Bundle extras) {
    Log.d(TAG, "startPeriodicLocationTask");

    GcmNetworkManager mGcmNetworkManager = GcmNetworkManager.getInstance(App.get());
    PeriodicTask.Builder taskBuilder = new PeriodicTask.Builder()
            .setService(MyLocationService.class)
            .setTag(tag)
            .setPeriod(period)
            .setPersisted(true)
            .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED);

    if (extras != null) taskBuilder.setExtras(extras);

    PeriodicTask task = taskBuilder.build();
    mGcmNetworkManager.schedule(task);
}




public static boolean checkPlayServicesAvailable(Activity activity) {
    GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
    int resultCode = availability.isGooglePlayServicesAvailable(App.get());

    if (resultCode != ConnectionResult.SUCCESS) {
        if (availability.isUserResolvableError(resultCode)) {
            // Show dialog to resolve the error.
            availability.getErrorDialog(activity, resultCode, RC_PLAY_SERVICES).show();
        }
        return false;
    } else {
        return true;
    }
}

Also add these 2 to the AndroidManifest.xml:

 <manifest...
 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

 <application...
 <service
        android:name=".api.location.MyLocationService"
        android:exported="true"
        android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
        <intent-filter>
            <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
        </intent-filter>
    </service>
dorsz
  • 905
  • 10
  • 20
7

You have to create service.That service should implement LocationListener. Then You have to use AlarmManager for calling service repeatedly with certain time limit.

I hope this one will help to you :)

Pei
  • 11,452
  • 5
  • 41
  • 45
user3515851
  • 469
  • 1
  • 4
  • 14
5

I have try to my code and got success try this

package com.mobeyosoft.latitudelongitude;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

/**
 * Created by 5943 6417 on 14-09-2016.
 */
public class LocationService extends Service
{
    public static final String BROADCAST_ACTION = "Hello World";
    private static final int TWO_MINUTES = 1000 * 60 * 1;
    public LocationManager locationManager;
    public MyLocationListener listener;
    public Location previousBestLocation = null;

    Context context;

    Intent intent;
    int counter = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        intent = new Intent(BROADCAST_ACTION);
        context=this;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        listener = new MyLocationListener();
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 4000, 0, listener);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 4000, 0, listener);
    }

    @Override
    public IBinder onBind(Intent intent){
        return null;
    }

    protected boolean isBetterLocation(Location location, Location currentBestLocation) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }

        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
        boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
        boolean isNewer = timeDelta > 0;

        // If it's been more than two minutes since the current location, use the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return true;
            // If the new location is more than two minutes older, it must be worse
        } else if (isSignificantlyOlder) {
            return false;
        }

        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;

        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());

        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }



    /** Checks whether two providers are the same */
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
            return provider2 == null;
        }
        return provider1.equals(provider2);
    }



    @Override
    public void onDestroy() {
        // handler.removeCallbacks(sendUpdatesToUI);
        super.onDestroy();
        Log.v("STOP_SERVICE", "DONE");
        locationManager.removeUpdates(listener);
    }

    public static Thread performOnBackgroundThread(final Runnable runnable) {
        final Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    runnable.run();
                } finally {

                }
            }
        };
        t.start();
        return t;
    }




    public class MyLocationListener implements LocationListener{

        public void onLocationChanged(final Location loc)
        {
            Log.i("**********", "Location changed");
            if(isBetterLocation(loc, previousBestLocation)) {
                loc.getLatitude();
                loc.getLongitude();
                Toast.makeText(context, "Latitude" + loc.getLatitude() + "\nLongitude"+loc.getLongitude(),Toast.LENGTH_SHORT).show();
                intent.putExtra("Latitude", loc.getLatitude());
                intent.putExtra("Longitude", loc.getLongitude());
                intent.putExtra("Provider", loc.getProvider());
                sendBroadcast(intent);

            }
        }

        public void onProviderDisabled(String provider)
        {
            Toast.makeText( getApplicationContext(), "Gps Disabled", Toast.LENGTH_SHORT ).show();
        }


        public void onProviderEnabled(String provider)
        {
            Toast.makeText( getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show();
        }


        public void onStatusChanged(String provider, int status, Bundle extras)
        {

        }

    }
}
MukeshThakur
  • 452
  • 4
  • 14
4

With the help of GoogleApiClient's LocationServices API we can get the current location of the user/device in specific time interval. This can be added into a background service which updates the Activity when onLocationChanged callbacks

The background service will keep running as long as the application exists in the memory and sticks to the notification drawer. The service handles the following functionalities,

  • Connecting to Google LocationServices API
  • Getting the current location
  • Sharing the result to the Activity

Service With Location Listener

 public class LocationMonitoringService extends Service implements
    GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
    LocationListener {
    ...
    ...
    ...
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    mLocationClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

    mLocationRequest.setInterval(10000); //10 secs
    mLocationRequest.setFastestInterval(5000); //5 secs


    int priority = LocationRequest.PRIORITY_HIGH_ACCURACY; //by default
    //PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER, PRIORITY_NO_POWER are the other priority modes


    mLocationRequest.setPriority(priority);
    mLocationClient.connect();

    //Make it stick to the notification panel so it is less prone to get cancelled by the Operating System.
    return START_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /*
    * LOCATION CALLBACKS
    */
    @Override
    public void onConnected(Bundle dataBundle) {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.

        Log.d(TAG, "== Error On onConnected() Permission not granted");
        //Permission not granted by user so cancel the further execution.
        return;
    }
    LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, mLocationRequest, this);

     Log.d(TAG, "Connected to Google API");
     }

    /*
     * Called by Location Services if the connection to the
     * location client drops because of an error.
     */
     @Override
     public void onConnectionSuspended(int i) {
       Log.d(TAG, "Connection suspended");
     }

     @Override
     public void onConnectionFailed(ConnectionResult connectionResult) {
       Log.d(TAG, "Failed to connect to Google API");
     }

     //to get the location change
     @Override
     public void onLocationChanged(Location location) {
       Log.d(TAG, "Location changed");

       if (location != null) {               

           //Do something with the location details,             
           if (location != null) {
           //call your API
             callAPI(String.valueOf(location.getLatitude()), String.valueOf(location.getLongitude()));
           }
        
      }
     }
    }
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Jayakrishnan
  • 4,457
  • 29
  • 29
  • This is excellent, thanks for posting! Works perfectly in my app that needs location across multiple Activities. It might be worth adding the check for whether Location is enabled on the device. Permissions are one thing, whether Location is actually on is another - https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient – WallyHale Nov 23 '17 at 14:13
2
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.GeomagneticField;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.widget.Toast;


public class LocationService extends Service {
    private static final int MINUTES = 1000 * 60 * 2;
    public LocationManager locationManager;
    public MyLocationListener listener;
    public Location previousBestLocation = null;
    Context mContext;
    private boolean isGpsEnabled = false;
    private boolean isNetworkEnabled = false;

    private GeomagneticField geoField;
    private double latitude = 0.0;
    private double longitude = 0.0;


    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
        if (locationManager == null) {
            locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
        }
        getCurrentLocation();
    }

    private void getCurrentLocation() {
        try {
            assert locationManager != null;
            isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        if (!isGpsEnabled && !isNetworkEnabled) {
            showSettingsAlert();
        }
        listener = new MyLocationListener();

        try {
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 0, listener);
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 0, listener);
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private void showSettingsAlert() {
        Toast.makeText(mContext, "GPS is disabled in your device. Please Enable it ?", Toast.LENGTH_LONG).show();
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    protected boolean isBetterLocation(Location location, Location currentBestLocation) {
        if (currentBestLocation == null) {
            return true;
        }
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > MINUTES;
        boolean isSignificantlyOlder = timeDelta < -MINUTES;
        boolean isNewer = timeDelta > 0;

        if (isSignificantlyNewer) {
            return true;
        } else if (isSignificantlyOlder) {
            return false;
        }

        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;
        boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider());
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }


    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
            return provider2 == null;
        }
        return provider1.equals(provider2);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        locationManager.removeUpdates(listener);
    }

    private void setupFinalLocationData(Location mLocation) {
        if (mLocation != null) {
            geoField = new GeomagneticField(
                    Double.valueOf(mLocation.getLatitude()).floatValue(),
                    Double.valueOf(mLocation.getLongitude()).floatValue(),
                    Double.valueOf(mLocation.getAltitude()).floatValue(),
                    System.currentTimeMillis()
            );

            latitude = mLocation.getLatitude();
            longitude = mLocation.getLongitude();
            //Update latitude and longtitude in SharedPreference...
        }
    }

    public class MyLocationListener implements LocationListener {
        public void onLocationChanged(final Location loc) {
            if (isBetterLocation(loc, previousBestLocation)) {
                setupFinalLocationData(loc);
            }
        }

        public void onProviderDisabled(String provider) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    }
}
Coldfin Lab
  • 361
  • 3
  • 8
2

--Kotlin Version

package com.ps.salestrackingapp.Services

import android.app.Service
import android.content.Context
import android.content.Intent
import android.location.Location
import android.location.LocationManager
import android.os.Bundle
import android.os.IBinder
import android.util.Log

 class LocationService : Service() {
    private var mLocationManager: LocationManager? = null

    var mLocationListeners = arrayOf(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))

     class LocationListener(provider: String) : android.location.LocationListener {
        internal var mLastLocation: Location

        init {
            Log.e(TAG, "LocationListener $provider")
            mLastLocation = Location(provider)
        }

        override fun onLocationChanged(location: Location) {
            Log.e(TAG, "onLocationChanged: $location")
            mLastLocation.set(location)
            Log.v("LastLocation", mLastLocation.latitude.toString() +"  " + mLastLocation.longitude.toString())
        }

        override fun onProviderDisabled(provider: String) {
            Log.e(TAG, "onProviderDisabled: $provider")
        }

        override fun onProviderEnabled(provider: String) {
            Log.e(TAG, "onProviderEnabled: $provider")
        }

        override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
            Log.e(TAG, "onStatusChanged: $provider")
        }
    }

    override fun onBind(arg0: Intent): IBinder? {
        return null
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.e(TAG, "onStartCommand")
        super.onStartCommand(intent, flags, startId)
        return Service.START_STICKY
    }

    override fun onCreate() {
        Log.e(TAG, "onCreate")
        initializeLocationManager()
        try {
            mLocationManager!!.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL.toLong(), LOCATION_DISTANCE,
                    mLocationListeners[1])
        } catch (ex: java.lang.SecurityException) {
            Log.i(TAG, "fail to request location update, ignore", ex)
        } catch (ex: IllegalArgumentException) {
            Log.d(TAG, "network provider does not exist, " + ex.message)
        }

        try {
            mLocationManager!!.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, LOCATION_INTERVAL.toLong(), LOCATION_DISTANCE,
                    mLocationListeners[0])
        } catch (ex: java.lang.SecurityException) {
            Log.i(TAG, "fail to request location update, ignore", ex)
        } catch (ex: IllegalArgumentException) {
            Log.d(TAG, "gps provider does not exist " + ex.message)
        }

    }

    override fun onDestroy() {
        Log.e(TAG, "onDestroy")
        super.onDestroy()
        if (mLocationManager != null) {
            for (i in mLocationListeners.indices) {
                try {
                    mLocationManager!!.removeUpdates(mLocationListeners[i])
                } catch (ex: Exception) {
                    Log.i(TAG, "fail to remove location listners, ignore", ex)
                }

            }
        }
    }

    private fun initializeLocationManager() {
        Log.e(TAG, "initializeLocationManager")
        if (mLocationManager == null) {
            mLocationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        }
    }

    companion object {
        private val TAG = "BOOMBOOMTESTGPS"
        private val LOCATION_INTERVAL = 1000
        private val LOCATION_DISTANCE = 0f
    }
}
Syed Hamza Hassan
  • 710
  • 1
  • 11
  • 24
0

You can archive it with a Service and Alarm Manager, but be careful with this, because if you setup a high priority you gonna drain the battery of the phone, in other hand, you really need notify the location every minute? This is because the only way to see a considerably change of the user location, it's traveling in a car or train. I only ask, because that gonna depend of you app and the requirement of the tracking.

f3rn4nd000
  • 434
  • 3
  • 7
  • yes,When user click on a button then app will get his location frequently and after a few time user will stop it.And my app is for getting driver location. – Ravi Bhandari Feb 16 '15 at 07:01
  • OK, so the user can't be affected for the requests and the service running in background, you only program the alarm every minute to launch a Intent to the Serbice, and the service take care of get and send the location. Your button only register and unregister the pending intent on your alarm manager. – f3rn4nd000 Feb 16 '15 at 07:09
0

Well Create a class extending Service ,this service will contain your Location listener class(Fused Location Provider) purpose of this service is to get location periodically , something like this

  public class LocationGetter extends Service {


    ......

    public class MyLocationListener implements GooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener, com.google.android.gms.location.LocationListener {

   //your fused Location provider code

    }

    ......

}

Then create a class extending Broadcast Receiver , such that the purpose of this broadcast Receiver is to check whether service is alive if not restart service even during phone ON/OFF ....

register receiver in ur activity , listen for broadcasts , unregeister receiver depending ur need...

-1

To get callback on LocationChange

Define an interface

public interface LocationCallback {
public void locationChanged(Location location);
}

Callback in your Activity

public static LocationCallback callback;
public void getUserLocation() {

    callback = new LocationCallback() {
        @Override
        public void locationChanged(Location location) {
            Toast.makeText(getApplicationContext(), location.getLatitude() + "," + location.getLongitude(), Toast.LENGTH_SHORT).show();
        }
    };

    Intent service_intent = new Intent(this, GPSService.class);
    startService(service_intent);

}

Change onLocationChange Method to

@Override
    public void onLocationChanged(Location location) {
        Log.e(TAG, "onLocationChanged: " + location);
        MapsActivity.callback.locationChanged(location);
        mLastLocation.set(location);
    }
Ali Akram
  • 4,803
  • 3
  • 29
  • 38
-2

For Track the location every 10 mins(based on requirement) please follow this link it is working fine without any issues

https://github.com/safetysystemtechnology/location-tracker-background

Kishore Reddy
  • 2,394
  • 1
  • 19
  • 15
  • 3
    Please include all relevant code in your post and don't just include a link to github. Your post should stand alone from any other resource; consider what would happen if github went down in the future! (It would be _terrible_, we know.) – DaniEll Jun 16 '17 at 07:21