I have recently stared to get issues as my FusedLocationProviderClient doesn't call the onLocationResult() method of LocationCallback when the device location is already enabled but has no problems to do so when I ask user to enable the location himself first (disabled at first). Below I am posting my code (I do not show how I obtain location permission beforehand) called from onCreate():
public void onReady() {
LocationRequest locReq = LocationRequest.create();
LocationSettingsRequest request = new LocationSettingsRequest.Builder()
.addLocationRequest(locReq)
.build();
LocationServices.getSettingsClient(this)
.checkLocationSettings(request)
.addOnCompleteListener(this::handleSettingsResponse);
}
private void handleSettingsResponse(Task<LocationSettingsResponse> task) {
try {
LocationSettingsResponse response = task.getResult(ApiException.class);
if (response != null) {
LocationSettingsStates states = response.getLocationSettingsStates();
if (states.isLocationPresent() && states.isLocationUsable()) {
findLocation();
} else {
failure()
}
}
} catch (ApiException e) {
copeWithFailure(e);
}
}
private void copeWithFailure(Exception e) {
if (e instanceof ResolvableApiException) {
try {
((ResolvableApiException) e).startResolutionForResult(this, REQUEST_RESOLUTION);//I call findLocation() if successful
} catch (IntentSender.SendIntentException e1) {
failure()
}
}
}
private void findLocation() {
FusedLocationProviderClient client =
LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
startingLatitude = location.getLatitude();
startingLongitude = location.getLongitude();
}}
LocationRequest locaReq = LocationRequest()
.setNumUpdates(1)
.setExpirationDuration(5500)
.setInterval(5000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
client.requestLocationUpdates(locaReq,
mLocationCallback, Looper.getMainLooper())
.addOnFailureListener(this, e -> {
});
}
This worked without problems before with pre-enabled location.
Related
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());
}
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
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
}
}
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
In my app I have 4 to 5 fragments and all fragment needed GoogleApiCLient object to get current location and to do other related things.
So, I just using GoogleApiClient as below :
First I implementing as :
implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener
Declaration :
private GoogleApiClient mGoogleApiClient;
In side onCreate() of Fragment :
if (!Constant.checkPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)) {
Constant.requestPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION, 101);
} else {
if (Constant.isOnline(mContext)) {
buildGoogleApiClient();
locationUpdate();
} else {
Constant.displayToast(mContext, getResources().getString(R.string.msg_internet));
}
}
Buiding as below :
private synchronized void buildGoogleApiClient() {
if (mGoogleApiClient == null || !mGoogleApiClient.isConnected()) {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(LocationServices.API)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.enableAutoManage(getActivity(), MapFragment.this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
}
onConnected method:
#Override
public void onConnected(#Nullable Bundle bundle) {
try {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
} catch (Exception e) {
e.printStackTrace();
}
}
getLocation() method:
private void getLocation() {
try {
if (ActivityCompat.checkSelfPermission((Activity) mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission((Activity) mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
} else {
mLocationManager = (LocationManager) mContext
.getSystemService(LOCATION_SERVICE);
// getting GPS status
boolean isGPSEnabled = mLocationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
// getting network status
boolean isNetworkEnabled = mLocationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) {
// no network provider is enabled
} else {
if (Prefrences.checkPref(mContext, ZIPCODE)) {
getLatLongFromZipCode();
} else {
if (isNetworkEnabled) {
if (!Prefrences.checkPref(mContext, NEAR_ME_SEARCH)) {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
0,
0, this);
if (mLocationManager != null) {
mLocation = mLocationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (mLocation != null) {
mCurrentLatitude = mLocation.getLatitude();
mCurrentLongitude = mLocation.getLongitude();
} else if (mLastLocation != null) {
mCurrentLatitude = mLastLocation.getLatitude();
mCurrentLongitude = mLastLocation.getLongitude();
} else {
Constant.displayToast(mContext, "Location not fetched. Try again.");
}
}
}
} else if (isGPSEnabled) {
if (!Prefrences.checkPref(mContext, NEAR_ME_SEARCH)) {
if (mLocation == null) {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0,
0, this);
if (mLocationManager != null) {
mLocation = mLocationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (mLocation != null) {
mCurrentLatitude = mLocation.getLatitude();
mCurrentLongitude = mLocation.getLongitude();
} else if (mLastLocation != null) {
mCurrentLatitude = mLastLocation.getLatitude();
mCurrentLongitude = mLastLocation.getLongitude();
} else {
Constant.displayToast(mContext, "Location not fetched. Try again.");
}
}
}
}
}
loadServiceData();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
locationUpdate() method, in which getLocation() method is calling :
private void locationUpdate() {
try {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5 * 1000);
mLocationRequest.setFastestInterval(1 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
// **************************
builder.setAlwaysShow(true); // this is the key ingredient
// **************************
if (mGoogleApiClient != null) {
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi
.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result
.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can
// initialize location
// requests here.
try {
if (Constant.isOnline(mContext)) {
getLocation();
} else
Constant.displayToast(mContext, mContext.getResources().getString(R.string.msg_internet));
} catch (Exception e) {
e.printStackTrace();
}
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be
// fixed by showing the user
// a dialog.
try {
status.startResolutionForResult((Activity) mContext, LOCATION_GET_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have
// no way to fix the
// settings so we won't show the dialog.
Constant.displayToast(mContext, "Location change issue.");
break;
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
onActivityResult() is also as below :
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LOCATION_GET_CODE) {
switch (resultCode) {
case Activity.RESULT_OK:
try {
getLocation();
} catch (Exception e) {
e.printStackTrace();
}
break;
case Activity.RESULT_CANCELED:
// The user was asked to change settings, but chose not to
Toast.makeText(mContext, "Please, turn on GPS and try again", Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
Runtime.getRuntime().gc();
}
onStop() method :
#Override
public void onStop() {
try {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.stopAutoManage(getActivity());
mGoogleApiClient.disconnect();
}
super.onStop();
} catch (Exception e) {
e.printStackTrace();
}
}
onStart() method :
#Override
public void onStart() {
try {
super.onStart();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
onDestroy() method :
#Override
public void onDestroy() {
try {
super.onDestroy();
if (mGoogleApiClient != null) {
mGoogleApiClient.stopAutoManage(getActivity());
mGoogleApiClient.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Now, The issue is when I am navigating from one fragment to another Fragment my app stucks or hang for 2 to 3 seconds.
What might be the issue ?
Thanks.
This is happening Because in each fragment you are doing the same thing again and again. you are connecting in onStart() and disconnecting in onStop(). The onStart() of the second fragment called before onStop() of the first fragment.
Instead of using GoogleApiClient in each fragment, move it to a single class and Connect and disconnect from your Activity.
I have implemented LocationUpdater for my own purpose. Look at the code, if you think it is good you can use it.
LocationFinder.class
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.maps.model.LatLng;
/**
* Created by Bhuvanesh on 8/21/2017.
*/
#SuppressWarnings("MissingPermission")
public class LocationFinder implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public static final String TAG = "LocationFinder";
private static final String BROADCAST_GPS_REQ = "LocationFinder.GPS_REQ";
private static final String KEY_GPS_REQ = "key.gps.req";
private static final int GPS_REQUEST = 2301;
private FragmentActivity activity;
private FinderType finderType;
private GoogleApiClient googleApiClient;
private LocationRequest locationRequest;
private long updateInterval;
private long fastestInterval;
private GpsRequestListener gpsRequestListener;
private LocationUpdateListener locationUpdateListener;
public LocationFinder(FragmentActivity activity, FinderType finderType) {
this.activity = activity;
this.finderType = finderType;
}
private void connectGoogleApiClient() {
googleApiClient = new GoogleApiClient.Builder(activity)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
googleApiClient.connect();
}
private void createLocationRequest() {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(updateInterval);
locationRequest.setFastestInterval(fastestInterval);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int intExtra = intent.getIntExtra(KEY_GPS_REQ, 0);
switch (intExtra) {
case Activity.RESULT_OK:
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, LocationFinder.this);
gpsRequestListener.gpsTurnedOn();
break;
case Activity.RESULT_CANCELED:
gpsRequestListener.gpsNotTurnedOn();
}
}
};
public void gpsRequestCallback(GpsRequestListener gpsRequestListener) {
this.gpsRequestListener = gpsRequestListener;
LocalBroadcastManager.getInstance(activity).registerReceiver(receiver, new IntentFilter(BROADCAST_GPS_REQ));
}
public void find(LocationUpdateListener listener) {
this.locationUpdateListener = listener;
createLocationRequest();
connectGoogleApiClient();
}
private void find() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(#NonNull LocationSettingsResult locationSettingsResult) {
Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, LocationFinder.this);
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
status.startResolutionForResult(activity, GPS_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.d(TAG, "No GPS Hardware");
break;
}
}
});
}
public void stopFinder() {
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
activity.unregisterReceiver(receiver);
googleApiClient.disconnect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "GoogleApiClient: Connected");
find();
}
#Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "GoogleApiClient: onConnectionSuspended")
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d(TAG, "GoogleApiClient: onConnectionFailed")
}
#Override
public void onLocationChanged(Location location) {
if (finderType != FinderType.TRACK)
stopFinder();
locationUpdateListener.onLocationUpdate(new LatLng(location.getLatitude(), location.getLongitude()));
}
public void setGpsRequestListener(GpsRequestListener gpsRequestListener) {
this.gpsRequestListener = gpsRequestListener;
}
public static void onRequestResult(Activity activity, int requestCode, int resultCode) {
if (requestCode == GPS_REQUEST) {
Intent intent = new Intent(BROADCAST_GPS_REQ);
intent.putExtra(KEY_GPS_REQ, resultCode);
LocalBroadcastManager.getInstance(activity).sendBroadcast(intent);
}
}
public enum FinderType {
// It will update the current GPS location once.
GPS,
//It will update the user location continuously.
TRACK
}
interface LocationUpdateListener {
void onLocationUpdate(LatLng latLng);
}
interface GpsRequestListener {
void gpsTurnedOn();
void gpsNotTurnedOn();
}
}
In your Activity:
LocationFinder finder = new LocationFinder((FragmentActivity) getActivity(), LocationFinder.FinderType.TRACK);
finder.config(5000, 5000);
finder.find(this);
You Should implement LocationFinder.LocationUpdateListener in your fragment. You will get location update in the callback method.
void onLocationUpdate(LatLng latLng);
If you want to Turn on Gps and get a callback after the process you have to do like this.
finder.gpsRequestCallback(new GpsRequestListener() {
#Override
public void gpsTurnedOn() {
}
#Override
public void gpsNotTurnedOn() {
}
});
In your activity onActivityResult() should be like this.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
LocationFinder.onRequestResult(this, requestCode, resultCode);
}
Note: you have to get Location Permission before you use this.