I am trying to get the location from the user but when I put the following request code for the location:
private void getLocation() {
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
}
}
It crashes because it gets the mLastLocation null
I call the function in the onResume() method but with no success. But if I put it in a button click callback, it gets the location.
Is there any way to get the location once the application has loaded?
First you should check that you have the required permissions to make this request.
You should get user location after you are connected to Google's LocationServices API.
Then you should request location asynchronously using Task returned by FusedLocationProviderClient.getLastLocation()
Here is some code to help you out:
GoogleApiClient mGoogleApiClient;
private void getGoogleApiClient() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(LocationServices.API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.e(getClass().getName(), "Location permission not granted");
return;
}
Task task = mFusedLocationClient.getLastLocation();
task.addOnSuccessListener(getActivity(), new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
}
}
});
}
#Override
public void onConnectionSuspended(int i) {
Log.e(getClass().getName(), "onConnectionSuspended() ");
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(getClass().getName(), "Get location failure : " + connectionResult.getErrorMessage());
}
})
.build();
}
mGoogleApiClient.connect();
}
Simply call the method getGoogleApiClient() when you need location.
Do make sure GPS location is activated on your device.
For more infos on this topic:
https://developer.android.com/training/location/retrieve-current.html
Related
I am using FusedLocationProvider to get the last location of the phone. Unfortunately the returned location is far from being accurate and it is not updating!.
Even When I call requestlocationupdates,the OnlocationResult never being called with PRIORITY_HIGH_ACCURACY. BUT it called ONLY once with PRIORITY_BALANCED_POWER_ACCURACY.
protected void startLocationUpdates() {
// Create the location request to start receiving updates
locationRequest = new LocationRequest();
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(1000);
// Create LocationSettingsRequest object using location request
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Check whether location settings are satisfied
// https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task =settingsClient.checkLocationSettings(locationSettingsRequest);
task.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
Log.i("SRV", "onSuccess: Location settings are satisfied");
}
});
task.addOnFailureListener( new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
Log.i("SRV", "onFailure: ");
}
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// Activity#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 Activity#requestPermissions for more details.
initialized = false;
//return;
}
}
// new Google API SDK v11 uses getFusedLocationProviderClient(this)
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.requestLocationUpdates(locationRequest, new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Log.i("SRV", "onLocationResult is called ");
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
if (location != null) {
Log.i("SRV", "My new location is " + location.getLatitude() + " " + location.getLongitude());
onLocationChanged(location);
}
}
}
#Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
Log.i("SRV", "onLocationAvailability is called ");
}
},
Looper.myLooper());
//get last location
mFusedLocationClient.getLastLocation().addOnSuccessListener(location -> {
if (location != null) {
_phoneLocation = location;
Log.i("SRV", "getLastLocation is called : My position " + location.getLatitude() + " " + location.getLongitude());
}
});
Log.i("SRV", "Startlocation updated was completed succesfully");
}
I expect the OnlocationResult to be called and updated very 5 seconds.
It turns out that it is a stupid thing. We spent too much time on this. I had some issues of checking the permissions and allowing it.
Here I post the final code that works perfectly. Make sure to allow the location permission when it prompts. If you are debugging many times, It is recommended to uninstall the app first to allow the permission again.
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION},
1);
} else if (mMap != null) {
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
}
Hi I am creating an android map application that will get the user location, but when users open their map sometimes the location is not accurate and will slowly pinpoint your location.
I have tried this. But It still calls the handler and the TOASTS won't stop.
private LocationManager locationManager;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps_page);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
handler.postDelayed(runnable,3000);
}
#Override
public void onProviderDisabled(String provider) {
handler.removeCallbacks(runnable);
}
});
private Runnable runnable = new Runnable() {
#Override
public void run() {
getCurrentLocation();
Toast.makeText(mapsPage.this, "GETTING LOCATION", Toast.LENGTH_SHORT).show();
handler.postDelayed(this, 3000);
}
};
private void getCurrentLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
Location location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (location != null) {
longitude = location.getLongitude();
latitude = location.getLatitude();
moveMap();
Integer loc = Math.round(location.getAccuracy());
textings.setText(Integer.toString(loc));
if(loc <= 100)
{
handler.removeCallbacks(runnable);
Toast.makeText(mapsPage.this, "HANDLER STOPPED", Toast.LENGTH_SHORT).show();
}
}
}
//Function to move the map
private void moveMap() {
LatLng latLng = new LatLng(latitude, longitude);
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17));
mMap.addMarker(new MarkerOptions().position(latLng).draggable(false));
}
I have added a handler that will run every 5 seconds checking the users location, and when the getAccuracy data is either equal or lesser than 100 it will stop. How would I do this?
getCurrentLocation may call handler.removeCallbacks(runnable);, but then the runnable will always call handler.postDelayed(this, 3000); right after.
To fix this there has to be some condition for the Runnable to check to see if it should post itself again.
A solution would be to make getCurrentLocation return a boolean indicating if it was successful (enough):
private boolean getCurrentLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return false;
}
Location location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (location != null) {
longitude = location.getLongitude();
latitude = location.getLatitude();
moveMap();
Integer loc = Math.round(location.getAccuracy());
textings.setText(Integer.toString(loc));
if(loc <= 100) {
handler.removeCallbacks(runnable);
Toast.makeText(mapsPage.this, "HANDLER STOPPED", Toast.LENGTH_SHORT).show();
return true;
}
}
return false;
}
Then in your Runnable check if you need to have another run:
#Override
public void run() {
if(!getCurrentLocation()) {
handler.postDelayed(this, 3000);
}
}
However, all of that being said, you should just check the Location in onLocationChanged of your LocationListener and do something if that location is accurate enough. Then you don't need the Runnable at all.
You should definitely accept RobCo's answer as the correct one because it addresses your question directly and also offers an additional key insight (i.e. you don't really need the Runnable at all).
But, I was curious what RobCo's approach would look like, so I created one possible implementation of it.
It turns out that if we avoid the Runnable and rely on Google's callbacks instead, we can get away with using only the newer location provider API (LocatonServices.FusedLocationApi). The older LocationManager API can just be eliminated.
So, in this implementation, I let the Google location service trigger callbacks if/when the location changes (instead of using a periodic poll from the client):
public class MainActivity extends AppCompatActivity implements
ActivityCompat.OnRequestPermissionsResultCallback, GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks,
com.google.android.gms.location.LocationListener {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int PERMISSION_REQUEST_CODE = 10001;
public static final int LOCATION_UPDATE_INTERVAL = 5000; // milliseconds
private GoogleApiClient googleApiClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
googleApiClient = new GoogleApiClient.Builder(this, this, this)
.enableAutoManage(this, this)
.addApi(LocationServices.API)
.build();
googleApiClient.connect();
}
private void requestPermission() {
ActivityCompat.requestPermissions(this,
new String[]{ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_CODE);
}
private void initLocationServices() {
try {
// make initial, synchronous request for current location
Location location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (location != null) {
moveMap(location);
}
// request future location updates which will come in as callbacks later, when available
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(LOCATION_UPDATE_INTERVAL);
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
} catch (SecurityException se) {
Log.w(TAG, "App does not have sufficient permission to request location. " +
"Requesting permission now...");
requestPermission();
}
}
private void moveMap(Location location) {
Log.v(TAG, "moveMap");
// TODO: actual map moving code goes here
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(TAG, "Connection failed:" + connectionResult.getErrorMessage());
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) {
Log.v(TAG, "User granted permission. Will request current location.");
initLocationServices();
} else {
Log.w(TAG, "User did not grant permission. Cannot request location. Cannot proceed.");
}
}
#Override
public void onLocationChanged(Location newLocation) {
Log.v(TAG, "onLocationChanged:" + newLocation.toString());
moveMap(newLocation);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if ((ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED)
&& (ActivityCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED)) {
initLocationServices();
} else {
Log.w(TAG, "onCreate: requesting sufficient permission from user");
requestPermission();
}
}
#Override
public void onConnectionSuspended(int i) {
Log.v(TAG, "onConnectionSuspended");
}
}
A downside of this particular implementation is that the MainActivity implements several interfaces and that adds some confusion (what are all these methods doing here?, etc)
Dunno. Maybe it's useful. In any event, good luck with your app.
I have an app that displays the latitude, longitude, speed, and distance, in a textview above of the map. The first location is displayed but when I move to another location the textview does not update the information. I also don't know if I am calculating the distance correctly. I am not sure if onLocationChanged is called. My code is below.
---EDIT---
As of now I am no longer working on this project anymore. I believe I was able to fix the issues I had, but I not longer have the code for this project anymore. As this post has been down voted 2 times, I don't believe that it has been very helpful to the community and so I would like to close and delete this post if possible, but there needs to be more votes to close and then delete it. Unless there is any other reason for why this post should stay open?
public class MainActivity extends AppCompatActivity
implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
GoogleMap mGoogleMap;
SupportMapFragment mapFrag;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
private ArrayList<Location> locations = new ArrayList<Location>();
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().setTitle("Map");
mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFrag.getMapAsync(this);
}
#Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
#Override
public void onMapReady(GoogleMap googleMap)
{
mGoogleMap=googleMap;
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//Initialize Google Play Services
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
buildGoogleApiClient();
mGoogleMap.setMyLocationEnabled(true);
} else {
//Request Location Permission
checkLocationPermission();
}
}
else {
buildGoogleApiClient();
mGoogleMap.setMyLocationEnabled(true);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onConnectionSuspended(int i) {}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {}
#Override
public void onLocationChanged(Location location)
{
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
double latitude = location.getLatitude();
double longitude = location.getLongitude();
double speed = location.getSpeed();
double distance = 0;
locations.add(location);
for(int i = 0; i < locations.size()-1; i++) {
distance += locations.get(i).distanceTo(locations.get(i +1));
}
StringBuilder stBuilder = new StringBuilder();
stBuilder.append(" Latitude: ");
stBuilder.append(latitude);
stBuilder.append("\n");
stBuilder.append(" Logitude: ");
stBuilder.append(longitude);
stBuilder.append("\n");
stBuilder.append(" Speed: ");
stBuilder.append(speed + " ");
stBuilder.append("Distance: ");
stBuilder.append(distance);
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(stBuilder);
//Place current location marker
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);
//move map camera
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,11));
//optionally, stop location updates if only current location is needed
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
private void checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
new AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to use location functionality")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
})
.create()
.show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
mGoogleMap.setMyLocationEnabled(true);
}
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "permission denied", LENGTH_LONG).show();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
}
In your onLocationChanged() method there is no need to stop the location Service:
Remove this:
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
calling this immediately will stop the location service and so your onLocationChnage() will not be called.
Besides you are adding it in onPause().
#Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
I want to get GPS location using Google API.
My code:
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
#Override
public void onConnected(Bundle bundle) {
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
double lat = mLocation.getLatitude();
double lon = mLocation.getLongitude();
}
I am not getting anything in the lat and lon variables.
How do I solve it?
It doesn't necessary that LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); will always return last object. If it doesn't find last object, it will return null and you will not get location. In such case, it is recommended to request for location using :
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
You also need to implement some interfaces and override method to get location by Google API.
Follow this steps to get location:
First of all, put this in gradle file
compile 'com.google.android.gms:play-services:8.4.0'
then implement necessary interfaces
public class MainActivity extends BaseActivitiy implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener
declare instances
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationManager locationManager;
private LocationRequest mLocationRequest;
put this in onCreate()
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
At last, override necessary methods
#Override
public void onConnected(Bundle bundle) {
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.
return;
}
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation == null){
startLocationUpdates();
}
if (mLocation != null) {
double latitude = mLocation.getLatitude();
double longitude = mLocation.getLongitude();
} else {
// Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
protected void startLocationUpdates() {
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
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.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
Log.d("reque", "--->>>>");
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
}
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
public void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
public void onLocationChanged(Location location) {
}
It works on most devices except Galaxy Note 2. It connects to Google Client, but can't reach onLocationChanged() that implements LocationListener. Anyone has any idea what it causes and why only on this device?
#Override
public void onLocationChanged(Location location) {
mLastLocation = location;
if (mLastLocation != null) {
lat = mLastLocation.getLatitude();
lng = mLastLocation.getLongitude();
Toast.makeText(getApplicationContext(), String.valueOf(lat) + "/" + String.valueOf(lng), Toast.LENGTH_LONG).show();
serverUrl = "http://(my server)/offers?lat=" + String.valueOf(mLastLocation.getLatitude())
+ "&lng=" + String.valueOf(mLastLocation.getLongitude()) + "&distance=1";
// save
makeTag(serverUrl);
// after getting location data - unregister listener
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mFusedLocationCallback);
new GetBackgroundUpdate().execute();
} else {
// get data from server and update GridView
new GetBackgroundUpdate().execute();
Toast.makeText(getApplicationContext(), R.string.no_location_detected, Toast.LENGTH_LONG).show();
}
/**
Location methods
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Provides a simple way of getting a device's location and is well suited for
// applications that do not require a fine-grained location and that do not need location
// updates. Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(500);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mFusedLocationCallback);
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(String.valueOf(result.getErrorCode()))
.setCancelable(false)
.setNegativeButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
dialog.cancel();
}
});
final AlertDialog alert = builder.create();
alert.show();
mResolvingError = true;
}
//new GetBackgroundUpdate().execute();
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
Edit: From the line in your comment where the NullPointerException is happening, just ensure that mLastLocation is not null.
if (mLastLocation != null){
address = server + String.valueOf(mLastLocation.getLatitude()) + "&lng=" + String.valueOf(mLastLocation.getLongitude()) + "&distance=" + distance;
}
Another thing to note is that you should always ensure that mGoogleApiClient is not null and connected before using it.
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()){
//..... use mGoogleApiClient.....
}
See documentation here
You should also add a check to see if Google Play Services are available, as sometimes the version available on the device is below the version that you compile your app with. There is a dialog that you can show if that is the case.
Below is how to check if Google Play Services are available.
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
return false;
}
}
Note that getLastLocation() has a high tendency to return null, so a good approach would be to register a location listener if you get a null value from the first call to getLastLocation().
See this post: LocationClient getLastLocation() return null
Here is a guide for how to register a LocationListener:
Creating a listener:
LocationCallback mFusedLocationCallback = new LocationCallback();
Class definition:
private class LocationCallback implements LocationListener {
public LocationCallback() {
}
#Override
public void onLocationChanged(Location location) {
mLastLocation = location;
lat = String.valueOf(mLastLocation.getLatitude());
lng = String.valueOf(mLastLocation.getLongitude());
}
};
Then just register the LocationListener :
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(minTime);
mLocationRequest.setFastestInterval(fastestTime);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(distanceThreshold);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mFusedLocationCallback);
Edit: You should wait for the API to be connected before you register for location callbacks, it should be something like this:
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Provides a simple way of getting a device's location and is well suited for
// applications that do not require a fine-grained location and that do not need location
// updates. Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
lat = String.valueOf(mLastLocation.getLatitude());
lng = String.valueOf(mLastLocation.getLongitude());
} else {
Toast.makeText(this, R.string.no_location_detected, Toast.LENGTH_LONG).show();
}
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(500);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mFusedLocationCallback);
}
Documentation: for requestLocationUpdates.... and LocationRequest.
One last thing, make sure that you have this in your AndroidManifest.xml inside the application tag:
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />