Android FusedLocationProviderClient doesn't always work - android

I tested this code with three phones. It works with two of them, but doesn't work with the third one, Huawei y9 2019. What's the problem? , And Why is it show (?) and (*) sign ??
My code is:
mFusedLocationProviderClient = new FusedLocationProviderClient(this);
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(500);
mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mFusedLocationProviderClient.requestLocationUpdates(
mLocationRequest,
new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if(locationResult != null){
Log.i("Your_Location",locationResult.getLastLocation().toString()+"\n\nrequestLocationUpdates() isCall");
textView.setText(locationResult.getLastLocation().toString());
}
else{
Log.i("Your_Location"," requestLocationUpdates() isCall Please Give Permission and On Location");
textView.setText("Please Give Permission and On Location");
}
super.onLocationResult(locationResult);
}
},
getMainLooper()
);

I have checked with Huawei previous version and others phone it's working fine for me. But i have not Huawei y9 2019. So you may check with this code.
//Request location through FusedLocationApi
public void registerRequestUpdate(final LocationListener listener) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
localStorageInterval=sm.getLocalStorageInterval().get("localStorageInterval")*1000;
mLocationRequest.setInterval(NOTIFY_INTERVAL/2); // every second
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
try {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, listener);
} catch (SecurityException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
if (!isGoogleApiClientConnected()) {
mGoogleApiClient.connect();
}
registerRequestUpdate(listener);
// saveLocationAndSync();
}
}
}, NOTIFY_INTERVAL);
}
// get updated location from this method
#Override
public void onLocationChanged(Location location) {
try {
string lat = location.getLatitude();
string long = location.getLongitude();
}
}catch (Exception ex){
//exception
}
}

Related

Location : LocationCallback() is never triggered

I am making an app using fusedLocationProviderClient to locate the user.
First, I try to retrieve last known location and then, if it isn't available I am making a request location.
Here is the issue, when I run the app, it doesn't trigger onLocationResult() method from the Callback.
So here's the logic of the code :
I tried to get the last known location, if it returns null, the method "checkIfCurrentLocationSettingsSatisfied" is summoned.
This method verifies if the phone's location is enabled, if not an other activity is launched and asks the user to allow location. The result code is checked on the "onActivityResult" method.
Furthermore, the location request is initiated. After that, the location Callback is also initiated.
Last of all, the fusedLocationProviderClient variable is set with the location request and the callback.
When the phone has a last known location, there is no problem. It's only when it tries to get a location.
In the manifest, I gave the " android.permission.ACCESS_FINE_LOCATION " permission. I found a topic that has an issue like mine but I tried every solutions proposed and it hasn't resolving my issue. Here is the topic : LocationCallback not getting called
Here is the code :
#Override
public void onMapReady(GoogleMap googleMap) {
this.googleMap = googleMap;
googleMap.setMyLocationEnabled(true);
googleMap.setOnMapLoadedCallback(this);
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
googleMap.setOnMarkerClickListener(this);
getDeviceLocation();
}
private void getDeviceLocation(){
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getContext());
try{
if(mLocationPermissionGranted){
Task location = fusedLocationProviderClient.getLastLocation();
location.addOnCompleteListener(task -> {
if(task.isSuccessful()){
Location currentLocation = (Location) task.getResult();
if(currentLocation == null){
builder = new LocationSettingsRequest.Builder();
checkIfCurrentLocationSettingsSatisfied();
}else{
moveCamera(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()));
}
}else{
Toast.makeText(getContext(), R.string.couldnt_get_location, Toast.LENGTH_SHORT).show();
}
});
}
}catch (SecurityException e){
e.printStackTrace();
}
}
private void moveCamera(LatLng latLng){
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, DEFAULT_ZOOM));
}
public void checkIfCurrentLocationSettingsSatisfied(){
SettingsClient client = LocationServices.getSettingsClient(getActivity());
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(locationSettingsResponse -> {
createLocationRequest();
});
task.addOnFailureListener(getActivity(), e -> {
if (e instanceof ResolvableApiException) {
try {
ResolvableApiException resolvable = (ResolvableApiException) e;
startIntentSenderForResult(resolvable.getResolution().getIntentSender(), REQUEST_CHECK_SETTINGS, null, 0, 0, 0, null);
} catch (IntentSender.SendIntentException sendEx) {
sendEx.printStackTrace();
}
}
});
}
private void createLocationRequest() {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(2000);
initializeLocationCallback();
}
private void initializeLocationCallback() {
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
Toast.makeText(getContext(), R.string.couldnt_get_location, Toast.LENGTH_SHORT).show();
return;
}
for (Location location : locationResult.getLocations()) {
// It never gets here
moveCamera(new LatLng(location.getLatitude(),location.getLongitude()));
}
}
};
startLocationUpdates();
}
private void startLocationUpdates() {
fusedLocationProviderClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper());
}

Why the permission Manifest.permission.ACCESS_FINE_LOCATION not active the "Location" option?

I have a code that makes location requests for the user, everything works fine as long as the user is already in the "location" mode is active, however, if the "location" mode is not activated in the device notification bar location returns null, I know that when we disable the option the cache of locations is cleared, how could I ask the user to activate the option for q then I request the getLastLocation?
fusedLocationProviderClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
localidade = task.getResult();
if(localidade != null){
try {
locFromLatLon = new Geocoder(AddAnuncioActivity.this, Locale.getDefault());
List<Address> addresses = locFromLatLon.getFromLocation(localidade.getLatitude(), localidade.getLongitude(), 1);
Log.i("VALORZAS", addresses.get(0).getCountryName());
} catch (IOException e) {
e.printStackTrace();
}
}else{
// Put some here whenlocation is null -- this happens when the Location option in notification bar of // user is unabled
}
}
});
This only work if the option from the image is enabled, if this option is off, the getResult returns null.
My onResume function:
#Override
protected void onResume() {
super.onResume();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(60000);
locationRequest.setFastestInterval(5000);
LocationCallback locationCallback = new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
Toast.makeText(getApplicationContext(), "Localidade ainda vazia", Toast.LENGTH_LONG).show();
return;
}
for (Location location : locationResult.getLocations()) {
}
}
};
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, null);
}
You can try with LocationManager:
final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
//Call Alert or use android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS
}
Refer the Documentation

request location updates never called onLocationResult

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);
}

FusedLocationProviderClient when and how to stop Looper?

I used to use FusedLocationApi until I learned that it is deprecated (see references below). It was simple to implement. As the documentation says you need to use it in conjunction with GoogleApiClient
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient,
locationRequest, this);
I recently changed to FusedLocationProviderClient (see reference below) Following a tutorial I was able to successfully get FusedLocationProviderClient working
Tutorial: https://github.com/codepath/android_guides/wiki/Retrieving-Location-with-LocationServices-API
// new Google API SDK v11 uses getFusedLocationProviderClient(this)
getFusedLocationProviderClient(this).requestLocationUpdates(mLocationRequest, new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
// do work here
onLocationChanged(locationResult.getLastLocation();
}
},
Looper.myLooper());
The issue I am running into is the Looper thread. Even with the application in the background, the Looper thread continues to run. I would like to pause location updates when the application is in the background and then resume location updates when the application is in the foreground. How can I achieve this?
References:
https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi
https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient
You just need to call mFusedLocationClient.removeLocationUpdates(mLocationCallback) in onPause() of your Activity. However, there is a bit more to it than just that.
Use member variables for the FusedLocationProviderClient and LocationRequest in your main activity:
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;
public class MainActivity extends AppCompatActivity
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
FusedLocationProviderClient mFusedLocationClient;
LocationRequest mLocationRequest;
//..........
Use a member variable for the LocationCallback as well:
LocationCallback mLocationCallback = new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
Log.i("MainActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());
}
};
};
Then, assign mFusedLocationClient in onCreate() :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
requestLocationUpdates();
//...............
}
Then in onResume(), if theFusedLocationProviderClient is set up, then use it.
#Override
public void onResume() {
if (mFusedLocationClient != null) {
requestLocationUpdates();
}
}
public void requestLocationUpdates() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(120000); // two minute interval
mLocationRequest.setFastestInterval(120000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
}
And finally, in onPause(), call removeLocationUpdates():
#Override
public void onPause() {
super.onPause();
if (mFusedLocationClient != null) {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
}
After getting location just remove mFusedLocationClient.removeLocationUpdates as he mentioned in above answers.
if (mFusedLocationClient != null)
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
Looper will be called requestLocationUpdates until you remove it.
In my problem, I did as I mention above. Below is my code.
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// GPS location can be null if GPS is switched off
if (location != null) {
mLocation = location;
if (mFusedLocationClient != null) {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
} else {
startLocationUpdates();
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(HomeActivity.this, "Error trying to get last GPS location", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
});
and below is my requestLocationUpdates so I will get a request until the location is available.
private void startLocationUpdates() {
mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "All location settings are satisfied.");
getPackageManager().checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, getPackageName());
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
getLastLocationNewMethod();
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Attempting to upgrade " +
"location settings ");
try {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(HomeActivity.this, 0x1);
} catch (IntentSender.SendIntentException sie) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
String errorMessage = "Location settings are inadequate, and cannot be " +
"fixed here. Fix in Settings.";
Log.e(TAG, errorMessage);
Toast.makeText(HomeActivity.this, errorMessage, Toast.LENGTH_LONG).show();
// mRequestingLocationUpdates = false;
}
getLastLocationNewMethod(); // this method is where I can get location. It is calling above method.
}
});
}
Note: For more information here is GitHub Repo LINK

How to optimise battery with FUSED LOCATION API - Android

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%.

Categories

Resources