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.