Searock Searock - 6 months ago 46
Android Question

How do I access GPS from Android Service?

I'm trying to get location from a background service. I'm starting the service from an Activity using the following code.

Intent serviceIntent = new Intent(this, LocationService.class);
startService(serviceIntent);


And here is my Service code.

public class LocationService extends Service {

private Thread t;
Looper threadLooper = null;

public int onStartCommand(Intent intent, int flags, int startId){

Log.i("Imp", "Inside service.");

new LooperThread().start();

return Service.START_NOT_STICKY;
}

private void logLocation(String lat, String lng){

//write to database.
}

class LooperThread extends Thread {


public void run() {
Log.i("Imp", "inside thread");
Looper.prepare();

Context context = getApplicationContext();
String svcName = Context.LOCATION_SERVICE;
LocationManager locationManager = (LocationManager) context.getSystemService(svcName);

Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setSpeedRequired(false);
criteria.setCostAllowed(false);

Log.i("Imp", "Regestring event.");
locationManager.requestSingleUpdate(criteria, locationListener, Looper.myLooper());
Log.i("Imp", "event reg.");

Looper.loop();
stopSelf();


}
}

final LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
Log.i("Imp", "Inside event");
if(location != null){
String lat = Double.toString(location.getLatitude());
String lng = Double.toString(location.getLongitude());
Log.i("Imp", "Lat " + lat);
Log.i("Imp", "lng " + lng);

logLocation(lat, lng);
}
}

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

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onProviderDisabled(String provider) {

}
};
}


Initially I use to get errors as I had passed null parameter for Looper object. But after passing the looper object I don't get any errors but I even don't get any coordinates.

I get
event reg.
message every time I run the code but for some reason it never calls the listner.

PS : I'm running the code on my phone and not on an emulator.

Answer

The recommended method is to use Location API from Google Play service.

Add the google play service dependency.

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

And the following code.

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

public class FusedLocationProvider implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        com.google.android.gms.location.LocationListener,
        ArchitectViewHolderInterface.ILocationProvider {

    private LocationRequest mLocationRequest;
    private GoogleApiClient mGoogleApiClient;
    private LocationListener listener;
    private String TAG = "FusedLocationProvider";

    public FusedLocationProvider(Context ctx, LocationListener locationListener){

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

        mGoogleApiClient.connect();

        Log.i(TAG, "Connecting...");

        this.listener = locationListener;
    }

    @Override
    public void onConnected(Bundle bundle) {

        Log.i(TAG, "onConnected");

        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(1000); // Update location every second

        try{
            if(mGoogleApiClient.isConnected()) {

                Log.i(TAG, "requestLocationUpdates");
                LocationServices.FusedLocationApi.requestLocationUpdates(
                        mGoogleApiClient, mLocationRequest, this);
            }
        }catch (SecurityException se){
            Log.i(TAG, se.toString());
        }catch (Exception e){
            Log.i(TAG, e.toString());
        }

    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(TAG, "onConnectionSuspended");
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i(TAG, "onConnectionFailed");
    }

    @Override
    public void onLocationChanged(Location recentLoc) {
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

        StrictMode.setThreadPolicy(policy);

        Log.i(TAG, Double.toString(recentLoc.getLongitude()));

        listener.onLocationChanged(recentLoc);
    }


    public void onPause() {
        Log.i(TAG, "onPause");
        if(mGoogleApiClient.isConnected()) {

            Log.i(TAG, "removeLocationUpdates");
            LocationServices.FusedLocationApi.removeLocationUpdates(
                    mGoogleApiClient, this);
        }
    }

    @Override
    public void onResume() {
        Log.i(TAG, "onResume");
        try{
            if(mGoogleApiClient.isConnected()){

                Log.i(TAG, "requestLocationUpdates");
                LocationServices.FusedLocationApi.requestLocationUpdates(
                        mGoogleApiClient, mLocationRequest, this);
            }

        }catch (SecurityException se){
            Log.i(TAG, se.toString());
        }catch (Exception e){
            Log.i(TAG, e.toString());
        }
    }


    public void onStop(){
        Log.i(TAG, "onStop");
        if(mGoogleApiClient.isConnected()) {

            Log.i(TAG, "disconnect");
            mGoogleApiClient.disconnect();
        }
    }
}

And the following the permissions in the android manifest file.

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