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" />
Related
I have the following functions that retrive the current position of the device. My problem is that I am unable to run this Service the background(I tried using Service intent but to no avail).
private LocationRequest mLocationRequest;
private long UPDATE_INTERVAL = 10 * 1000; /* 10 secs */
private long FASTEST_INTERVAL = 2000; /* 2 sec */
protected void startLocationUpdates() {
// Create the location request to start receiving updates
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
// Create LocationSettingsRequest object using location request
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
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);
settingsClient.checkLocationSettings(locationSettingsRequest);
if(ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)!=PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
}else{
// locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,locationListener);
}
// new Google API SDK v11 uses getFusedLocationProviderClient(this)
getFusedLocationProviderClient(this).requestLocationUpdates(mLocationRequest, new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
// do work here
Log.d("test",locationResult.getLastLocation().toString());
onLocationChanged(locationResult.getLastLocation());
}
},
Looper.myLooper());
}
public void onLocationChanged(Location location) {
// New location has now been determined
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
// You can now create a LatLng Object for use with maps
}
public void getLastLocation() {
// Get last known recent location using new Google Play Services SDK (v11+)
FusedLocationProviderClient locationClient = getFusedLocationProviderClient(this);
if(ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)!=PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
}else{
// locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,locationListener);
}
locationClient.getLastLocation()
.addOnSuccessListener(new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// GPS location can be null if GPS is switched off
if (location != null) {
onLocationChanged(location);
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("MapDemoActivity", "Error trying to get last GPS location");
e.printStackTrace();
}
});
}
at the moment I start the location update Service trough the startLocationUpdates(); function. I am open to any suggestions as long as they retain the current functionality of the Service. Sorry if the question seems stupid but I am very new to android.
Use like this
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
Intent ServiceG = new Intent(context, ClipboardService.class);
context.startService(ServiceG);
} else {
Intent ServiceG = new Intent(context, ClipboardJobService.class);
//context.startService(ServiceG);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(ServiceG);
}else {
context.startService(ServiceG);
}
}
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
Hi I am facing below issue/problem with location API in android
Battery consumption is high as 30% - 40%, which is causing lot of battery drain.
Location icon in status bar is always ON even when app is closed and when app is uninstalled it goes off automatically.
Requirement:
Need user location when app is opened.
I need to have users location even when app is not opened or not in use based on distance - need user location in background.
Approach:
with GPS
API used FUSED LOCATION API with pending intent.
LocationManager - to check state of GPS On/Off.
Code walkthru:
in OnCreate i m getting location manager instance - getting instance of location manager.
checking is GPS enabled or is network state available else show dialog to enable location: CODE: -
// get GPS state.
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (isGPSLocationEnabled(locationManager)) {
buildGooleLocationApiClient();
} else if (isNetworkLocationEnabled(locationManager)) {
buildGooleLocationApiClient();
} else {
showAlert();
}
Code for goolgeLocationAPiClient: In this method I am checking android version, requesting permission and enabling services
private void buildGooleLocationApiClient() {
if (Build.VERSION.SDK_INT >= 23) {
int isFineLocationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
int isCoarseLocationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (isFineLocationPermission == PackageManager.PERMISSION_DENIED || isCoarseLocationPermission == PackageManager.PERMISSION_DENIED) {
requestPermission();
} else {
checkGoogleLocationApiClient();
}
} else {
checkGoogleLocationApiClient();
}
}
Building GoogleAPI Client:
private void checkGoogleLocationApiClient() {
try {
if (mGoogleApiClient != null) {
if (mGoogleApiClient.isConnected()) {
getMyLocationCampaigns();
} else {
mGoogleApiClient.connect();
}
} else {
buildGoogleApiClient();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getMyLocationCampaigns() {
if (mCurrentLocation != null) {
getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
} else {
try {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
} catch (SecurityException ex) {
ex.printStackTrace();
getData("","");
}
}
}
private synchronized void buildGoogleApiClient() {
try {
Log.i(TAG, "activity Building GoogleApiClient===");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
} catch (Exception e) {
e.printStackTrace();
getData("","");
}
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(60 * 60 * 1000);
mLocationRequest.setFastestInterval(60 * 1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(100);
connectGoogleApiClient();
}
private void connectGoogleApiClient() {
if (mGoogleApiClient != null) {
if (!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
}
}
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (mCurrentLocation == null) {
try {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation != null) {
// MyAPICALL getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
} else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest, this);
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation == null) {
if (locationManager != null) {
String provider = Utils.getUserLastLocation(locationManager);
if (provider != null) {
try {
Location location = locationManager.getLastKnownLocation(provider);
if (location != null) {
getData(location.getLatitude() + "", location.getLongitude() + "");
} else {
getData("", "");
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
} else {
getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
}
}
} catch (SecurityException ex) {
ex.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
getData("","");
}
}
}
Method to getlocation in background with pending intent
private void startLocationUpdates() {
try {
Intent receiverIntentService = new Intent(this, LocationIntentService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 1, receiverIntentService, 0);
if (mGoogleApiClient != null) {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, pendingIntent);
}
}
} catch (SecurityException se) {
se.printStackTrace();
}
}
BroadCastReceiver: In case if device is restarted:
public class LocationBroadcastReceiver extends BroadcastReceiver implements
GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener, LocationListener {
Context context;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
protected Location mCurrentLocation;
public static Boolean mRequestingLocationUpdates = false;
SharedPreferences checkUserStatus;
public LocationBroadcastReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
try {
this.context = context;
checkUserStatus = context.getSharedPreferences(Params.LOGIN_DETAILS_PREFERENCE, 0);
String isUserLogedIn = checkUserStatus.getString(Params.TOKEN,"");
// if user is still logged in then only trigger background service
if (!isUserLogedIn.equals("")) {
buildGoogleApiClient();
if (mGoogleApiClient != null) {
if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
startLocationUpdates();
} else {
buildGoogleApiClient();
}
} else {
buildGoogleApiClient();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i("Broadcast receiver", "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
}
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(60 * 60 * 1000);
mLocationRequest.setFastestInterval(60 * 1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(100);
}
protected void startLocationUpdates() {
try {
Intent receiverIntentService = new Intent(context,LocationIntentService.class);
PendingIntent pendingIntent = PendingIntent.getService(context,1,receiverIntentService,0);
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, pendingIntent);
}catch (SecurityException se) {
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
My intent service class: to get user updated location and make an API call
public class LocationIntentService extends IntentService {
Context context;
Bitmap myBitmap;
URL url;
SharedPreferences.Editor mMyLastLocationHolder;
SharedPreferences mMyLastLocation;
SharedPreferences checkUserStatus;
public LocationIntentService() {
super("LocationIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Location location = bundle.getParcelable("com.google.android.location.LOCATION");
if (location != null) {
context = getApplicationContext();
// API call to server
updateAPI(location.getLatitude()+"",location.getLongitude()+"");
Log.v("TAG LOCATION ", " ==== " + location.getLatitude() + " - " + location.getLongitude() + " ==== ");
Log.v("TAG LOCATION ", " ==== calling my-campaigns near me ========");
}
}
}
}
/**
* Handle action Foo in the provided background thread with the provided
* parameters.
*/
private void handleActionFoo(String param1, String param2) {
// TODO: Handle action Foo
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Handle action Baz in the provided background thread with the provided
* parameters.
*/
private void handleActionBaz(String param1, String param2) {
// TODO: Handle action Baz
throw new UnsupportedOperationException("Not yet implemented");
}
}
I hope this could help you finding the best solution/approach.
Personally prefer to use GoogleApiClient and LocationRequest with a certain priority and interval.
Write a service that implements the following interfaces:
GoogleApiClient.ConnectionCallbacks
GoogleApiClient.OnConnectionFailedListener
LocationListener
public class PositionService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {}
Use GoogleApiClient and LocationRequest classes.
Into the onCreate() instantiate a GoogleApiClient object, a LocationRequest object and make mGoogleApiClient connect.
public void onCreate() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
.setInterval(mInterval).setFastestInterval(mFastInterval);
mGoogleApiClient.connect();
}
Into the onDestroy() method make the mGoogleApiClient disconnect
#Override
public void onDestroy() {
mGoogleApiClient.disconnect();
}
Now implement the interfaces
#Override
public void onLocationChanged(Location location) {
Log.d("NewLocation", location.toString());
}
#Override
public void onConnected(#Nullable Bundle bundle) throws SecurityException {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
Now GoogleApiClient, based on the settings of the LocationRequest, will inform you of the position calling the onLocationChanged() callback
Your business logic should be placed into the onLocationChanged() method. Just pick a good interval timings and priority for the LocationRequest. (see documentation)
Please refer to the official documentation about location strategies, my solution is based on that.
I'm used to get the service started in Foreground to prevent unexpected behaviour by the operating system (e.g. service being killed)
This will only explain you the better logic
Instead of long running service or IntentService Just use Firebase JobDispatcher or Any 3rd Party lib Jobscheduler API such that you move all your location update code to Jobscheduler (https://github.com/googlesamples/android-JobScheduler/blob/master/Application/src/main/java/com/example/android/jobscheduler/service/MyJobService.java)
Start the Job as per your location update interval, configure or alter the Job as per your requirement !! it's really a better solution compare to long running service !!!(You can use eventBus or RxBus for location update in Activity or fragment !!)
Tips: every time Job starts with firing location update before Job closes setup up some system delay of 3seconds or more because some times Googleapiclient takes some more time to update the new updated GPS time after the delay you can close Googleapiclient all unwanted call backs with the running JobService. control the Job configuration smartly with Google Awareness Api or Google Fit API by detecting the User Activity!
All in one Job Jobscheduler Lib: https://github.com/evernote/android-job
P.S: code will be updated very soon
The documentation states
Activities should strongly consider removing all location request when
entering the background (for example at onPause()), or at least swap
the request to a larger interval and lower quality.
therefore what I did when I faced a similar issue was:
I created two location requests, the first had a priority of PRIORITY_HIGH_ACCURACY and an interval of 1 min while the second one had a priority of PRIORITY_LOW_POWER with an internal of 1 hour and a smallest displacement of 1km
When the app is launched I use the first location request (high priority) to get more frequent and accurate location updates
When the app enters the background I swap to the second location request (low priority) to eliminate the battery usage while getting less frequent location updates
(Optional) You can also get the battery percentage when the app is launched and choose according to a limit (eg. 15%) which location request you might want to use when the app is in the foreground
These steps helped me reduce the battery usage of my app from >30% to <3%.
I have developed an application using the Fused location provider. In the onConnected() method, I am requesting for location updates and the application logic will be initiated and onLocationChanged() is called.
Problem : onLocationChanged() method is not called in devices in US . This code works perfectly fine on devices in INDIA but does not work on US. By does not work, I mean that locationClient gets connected but onLocationChanged() is never called.
Code Below:
public class LocationReceiver extends BroadcastReceiver
implements
// GooglePlayServicesClient.ConnectionCallbacks,
// GooglePlayServicesClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
// LocationClient locationclient = null;
GoogleApiClient locationclient = null;
Context contxt;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
#Override
public void onReceive(Context context, Intent intent) {
contxt = context;
// Log.i("locationreciever", "in location rec");,
Log.i("fused", "in location rec");
int resp = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(context);
if (resp == ConnectionResult.SUCCESS) {
// locationclient = new LocationClient(context, this, this);
locationclient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)// (mConnectionCallbacks)
.addOnConnectionFailedListener(this)// (mOnConnectionFailedListener)
.build();
locationclient.connect();
} else {
Log.i("fused", "loc client Google Play Service Error");
}
}
public void updateTransientLocation(Context context, Location loc) {
// Log.i("updateTransientLocation", "in fn");
float lat = (float) loc.getLatitude();
float lon = (float) loc.getLongitude();
float acc = loc.getAccuracy();
float alt = (float) loc.getAltitude();
if (lat > 0 && lon > 0) {
PreferenceForApp prefs = new PreferenceForApp(contxt);
prefs.setTransientLatitude(lat);
prefs.setTransientLongitude(lon);
prefs.setTransientAccuracy(acc);
prefs.setTransientAltitude(alt);
}
}
#Override
public void onLocationChanged(Location location) {
Log.i("fused",
" onLocationChanged Location Request :"
+ location.getLatitude() + ","
+ location.getLongitude() + " acc "
+ location.getAccuracy()+" alt "+location.getAltitude());
//TODO wait for some time to get location
updateTransientLocation(contxt, location);
if (locationclient != null) {
if (locationclient.isConnected()) {
// locationclient.removeLocationUpdates(this);
LocationServices.FusedLocationApi.removeLocationUpdates(
locationclient, this);
locationclient.disconnect();
}
}
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
PreferenceForApp prefs = new PreferenceForApp(contxt);
// if (arg0.hasResolution()) {
// try {
// // Start an Activity that tries to resolve the error
// arg0.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
// } catch (IntentSender.SendIntentException e) {
// e.printStackTrace();
// }}else{
Log.i("fused", "loc client connection failed");
prefs.setGooglePlayServiceErrorCode(arg0.getErrorCode());
}
//}
#Override
public void onConnected(Bundle arg0) {
PreferenceForApp prefs = new PreferenceForApp(contxt);
prefs.setGooglePlayServiceErrorCode(0);
Log.i("fused", "loc client onConnected");
LocationRequest locationrequest = new LocationRequest();
locationrequest
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// PRIORITY_BALANCED_POWER_ACCURACY
// locationclient.requestLocationUpdates(locationrequest, this);
LocationServices.FusedLocationApi.requestLocationUpdates(
locationclient, locationrequest, this); // mLocationListener);
}
// #Override
// public void onDisconnected() {
// Log.i("fused", "loc client disconnected");
// }
#Override
public void onConnectionSuspended(int arg0) {
Log.i("fused", "loc client onConnectionSuspended");
}
}
Can anyone help me out with this issue? Is there something I am missing here?
Maybe it's the fact that the phone can't connect with the service provider?
try using the gps.
String locationProvider = LocationManager.GPS_PROVIDER;
// Or, use GPS location data:
// String locationProvider = LocationManager.NETWORK_PROVIDER;
I think you are using NETWORK_PROVIDER to access/get the location update.
Try to use GPS_PROVIDER or use PASSIVE_PROVIDER to get location from either NETWORK_PROVIDER or GPS_PROVIDER.
Make sure you have permission in manifest to access NETWORK and GPS locations.
If you are using FusedLocationProviderApi, you have the option of using the SettingsApi to check if a device has the location settings required by an application. The SettingsApi and optionally provides a location dialog to update the device's location settings if they are found to be inadequate. You can look at an example. Run the sample with the location turned off in Settings, and you should see the dialog. Your app may be failing because it doesn't have sufficient permissions, and the location dialog could help.
I want to save battery by changing the interval of updates using the Fused Location API. As far from some location, bigger should be the interval.
public class service extends Service implements GooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {
private LocationRequest locationrequest;
private LocationClient locationclient;
#Override
public void onCreate() {
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resp == ConnectionResult.SUCCESS) {
locationclient = new LocationClient(this, this, this);
locationclient.connect();
} else {
Toast.makeText(this, "Google Play Service Error " + resp, Toast.LENGTH_LONG).show();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if(locationclient!=null)
locationclient.disconnect();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "onConnected");
if (locationclient != null && locationclient.isConnected()) {
locationrequest = LocationRequest.create();
locationrequest.setInterval(5000);
locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationclient.requestLocationUpdates(locationrequest, this);
}
}
#Override
public void onDisconnected() {
Log.i(TAG, "onDisconnected");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "onConnectionFailed");
}
#Override
public void onLocationChanged(Location location) {
if(location!=null){
double Lat=-34.922611;
double Lng = 138.596161;
Location Loc = new Location("");
Loc.setLatitude(Lat);
Loc.setLongitude(Lng);
Float dist=location.distanceTo(Loc);
String distance = Float.toString(dist);
if (dist>100){
Log.i("distance",distance);
locationclient.removeLocationUpdates(this);
locationrequest.setInterval(30000);
locationrequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
locationclient.requestLocationUpdates(locationrequest, this);
}
Log.i(TAG, "Location Request :" + location.getLatitude() + "," + location.getLongitude());
}
}
}
Unfortunately this is not working.. somebody knows why? or is there a better way to do that?
thanks
EDIT 1:
What I am getting as output is a locationrequest that behaves in the same way before the change. If I call locationrequest.getInterval , the new interval will be show but the locationrequest will give me updates with the first interval.
Using the Fused Location API you can do something like:
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
Then when an event is triggered in your app and you want to change the intervals, you would call the same piece of code but just change the INTERVAL and FASTEST_INTERVAL values.
After you change them do no forget to update the Location Updates like so:
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
Use removeLocationUpdates before changing the interval
with addOnCompleteListener to make sure you unregistered the previous request, and re-init the LocationRequest object:
LocationServices.FusedLocationApi.removeLocationUpdates(mLocationCallback).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
});
The problem is most likely that you have another process that requests locations, and that your app just listenes along. The setInterval means only what your app requires, not what it gets. So if another process has a faster interval you will get faster location updates.
Check for example if you have a GoogleMap with the MyLocation layer enabled. The map will request its own locations.
Finally, the LocationClient is deprecated. Check the documentation for FusedLocationApi to implement the correct current practice.