Android Fused Location API. Location Always null

D-D picture D-D · Dec 27, 2014 · Viewed 10.2k times · Source

I am trying to implement fused location for getting the current location. I am doing it with the help of this link

My googleAPiCLient is connected. But location is always null

In my Manifest file I have put this

   <meta-data android:name="com.google.android.gms.version"
        android:value="5089000" />

I created a seperate Fusionclass.

MY fusion class--

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;

import com.XXX.constants.LogConstants;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

public class FusedLocation implements 
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {



private static final long INTERVAL = 1000 * 30;
    private static final long FASTEST_INTERVAL = 1000 * 5;
    private static final long ONE_MIN = 1000 * 60;
    private static final long REFRESH_TIME = ONE_MIN * 5;
//  private static final float MINIMUM_ACCURACY = 50.0f;
    Activity LauncherActivity; 
    private LocationRequest locationRequest;
    private GoogleApiClient googleApiClient;
    private Location location;
    private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
public FusedLocation(Activity LauncherActivity) {
    locationRequest = LocationRequest.create();
//  locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(INTERVAL);
    locationRequest.setFastestInterval(FASTEST_INTERVAL);
    this.LauncherActivity = LauncherActivity;

    googleApiClient = new GoogleApiClient.Builder(LauncherActivity)
            .addApi(LocationServices.API).addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this).build();

    if (googleApiClient != null) {
         Log.i(LogConstants.INFO_LOG, "googleApiClient is not null");
  //the console prints this
        googleApiClient.connect();

    }
}

@Override
public void onConnected(Bundle connectionHint) {
     Log.i(LogConstants.INFO_LOG, "GoogleApiClient connected");
    Location currentLocation = fusedLocationProviderApi.getLastLocation(googleApiClient);
    if (currentLocation != null && currentLocation.getTime() > REFRESH_TIME) {
        location = currentLocation;
    } else {
          fusedLocationProviderApi.requestLocationUpdates(googleApiClient,locationRequest, locListen);
        // Schedule a Thread to unregister location listeners
        Executors.newScheduledThreadPool(1).schedule(new Runnable() {
            @Override
            public void run() {
                fusedLocationProviderApi.removeLocationUpdates(googleApiClient, locListen);
            }
        }, ONE_MIN, TimeUnit.MILLISECONDS);
    }
}




 com.google.android.gms.location.LocationListener locListen=new           com.google.android.gms.location.LocationListener() {

    @Override
    public void onLocationChanged(Location location) {

         Log.i(LogConstants.INFO_LOG, "75location::"+location);



    }
};

public Location getLocation() {
    return this.location;
}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

}

}

My activity class I am calling the FusedLOcation class from the oncreate

 //show error dialog if GoolglePlayServices not available
    if (!isGooglePlayServicesAvailable()) {
        finish();
    }
    fusedLocation = new FusedLocation(this);
    Location location = fusedLocation.getLocation();
    String locationResult = "";
    if (null != location) {
        Log.i(LogConstants.INFO_LOG, location.toString());
        double latitude = location.getLatitude();
        double longitude = location.getLongitude();
        Log.i(LogConstants.INFO_LOG, "longitude::!"+longitude);
        float accuracy = location.getAccuracy();
        /*double elapsedTimeSecs = (double) location.getElapsedRealtimeNanos()
                / 1000000000.0;*/
        String provider = location.getProvider();
        double altitude = location.getAltitude();
        locationResult = "Latitude: " + latitude + "\n" +
                "Longitude: " + longitude + "\n" +
                "Altitude: " + altitude + "\n" +
                "Accuracy: " + accuracy + "\n" +
                "Elapsed Time: "  + " secs" + "\n" +
                "Provider: " + provider + "\n";
    } else {
        locationResult = "Location Not Available!";
        Log.i(LogConstants.INFO_LOG, "Location Not Available!");
    }

 private boolean isGooglePlayServicesAvailable() {
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        Log.i(LogConstants.INFO_LOG, "status:"+status);
        if (ConnectionResult.SUCCESS == status) {
            return true;
        } else {
            GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
            return false;
        }
    }

Location is always null. The listeners do not seem to be working.

Answer

aldebaran-ms picture aldebaran-ms · Jan 24, 2015

First of all, if you're using the emulator you have to set the position manually doing:

telnet localhost 5554

when connected run the command

geo fix <longitude> <latitude>

as decribed here Using the emulator #geo or here how-to-emulate-gps-location-in-the-android-emulator. I suggest you to do so at soon as the emulator is booting and obviously before you're app start.

Second thing, your FusedLocation isn't implementing LocationListener as it is in the example you have posted. You have to implement that interface and then implement the method onLocationChanged inside your FusedLocation. Anyway, I think that you are trying to load the location as soon as the app is started, right? Well the example you posted doesn't work in this way but it's the user that ask for location through a visible botton. If you want to load the location at the beginning you can modify the example code like this:

the FusedLocationService is your FusedLocation class

import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
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.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class FusedLocationService implements
        LocationListener,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    private static final String TAG = "FusedLocationService";

    private static final long INTERVAL = 1000 * 30;
    private static final long FASTEST_INTERVAL = 1000 * 5;
    private static final long ONE_MIN = 1000 * 60;
    private static final long REFRESH_TIME = ONE_MIN * 5;
    private static final float MINIMUM_ACCURACY = 50.0f;
    Activity locationActivity;
    private LocationRequest locationRequest;
    private GoogleApiClient googleApiClient;
    private Location location;
    private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;

    FusedLocationReceiver locationReceiver = null;

    public FusedLocationService(Activity locationActivity, FusedLocationReceiver locationReceiver) {
        this.locationReceiver = locationReceiver;
        locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(INTERVAL);
        locationRequest.setFastestInterval(FASTEST_INTERVAL);
        this.locationActivity = locationActivity;

        googleApiClient = new GoogleApiClient.Builder(locationActivity)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

        if (googleApiClient != null) {
            googleApiClient.connect();
        }
    }

    @Override
    public void onConnected(Bundle connectionHint) {
        Log.i(TAG, "I'm connected now");
        Location currentLocation = fusedLocationProviderApi.getLastLocation(googleApiClient);
        if (currentLocation != null && currentLocation.getTime() > REFRESH_TIME) {
            location = currentLocation;
        } else {
            fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);
            // Schedule a Thread to unregister location listeners
            Executors.newScheduledThreadPool(1).schedule(new Runnable() {
                @Override
                public void run() {
                    fusedLocationProviderApi.removeLocationUpdates(googleApiClient,
                            FusedLocationService.this);
                }
            }, ONE_MIN, TimeUnit.MILLISECONDS);
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.i(TAG, "Location is changed!");
        //if the existing location is empty or
        //the current location accuracy is greater than existing accuracy
        //then store the current location
        if (null == this.location || location.getAccuracy() < this.location.getAccuracy()) {
            this.location = location;
// let's inform my client class through the receiver
            locationReceiver.onLocationChanged();
            //if the accuracy is not better, remove all location updates for this listener
            if (this.location.getAccuracy() < MINIMUM_ACCURACY) {
                fusedLocationProviderApi.removeLocationUpdates(googleApiClient, this);
            }
        }
    }

    public Location getLocation() {
        return this.location;
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }

}

This is the receiver

public abstract class FusedLocationReceiver {
    public abstract void onLocationChanged();
}

and this is the activity

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;

public class MainActivity extends Activity {

    private static final String TAG = "MyActivity";
    Button btnFusedLocation;
    TextView tvLocation;
    FusedLocationService fusedLocationService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //show error dialog if GoolglePlayServices not available
        if (!isGooglePlayServicesAvailable()) {
            finish();
        }

        setContentView(R.layout.activity_main);
        tvLocation = (TextView) findViewById(R.id.tvLocation);

        fusedLocationService = new FusedLocationService(this, new FusedLocationReceiver(){

            @Override
            public void onLocationChanged() {
                Log.i(TAG, "I'm the receiver, let's do my job!");
                updateUI();
            }
        });

        btnFusedLocation = (Button) findViewById(R.id.btnGPSShowLocation);
        btnFusedLocation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                updateUI();
            }
        });
    }

    private void updateUI() {
        Location location = fusedLocationService.getLocation();
        String locationResult = "";
        if (null != location) {
            Log.i(TAG, location.toString());
            double latitude = location.getLatitude();
            double longitude = location.getLongitude();
            float accuracy = location.getAccuracy();
            double elapsedTimeSecs = (double) location.getElapsedRealtimeNanos()
                    / 1000000000.0;
            String provider = location.getProvider();
            double altitude = location.getAltitude();
            locationResult = "Latitude: " + latitude + "\n" +
                    "Longitude: " + longitude + "\n" +
                    "Altitude: " + altitude + "\n" +
                    "Accuracy: " + accuracy + "\n" +
                    "Elapsed Time: " + elapsedTimeSecs + " secs" + "\n" +
                    "Provider: " + provider + "\n";
        } else {
            Log.i(TAG, "Location Not Available!");
            locationResult = "Location Not Available!";
        }
        tvLocation.setText(locationResult);
    }


    private boolean isGooglePlayServicesAvailable() {
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (ConnectionResult.SUCCESS == status) {
            return true;
        } else {
            GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
            return false;
        }
    }
}

Essentially when you instantiate a FusedLocationService you give it an object (the receiver) that will be called by the FusedLocationService when the location is ready. Warning: this will give you the location only once.