My question is how custom it is to isolate certain functionality required by an activity into a hidden fragment, in this case Location Services.
My initial thought was to pass the boilerplate callbacks that are related to Location Services into a separate plain Java utility class, and only keep the listener for onLocationChangedin the Activity. This would be much cleaner.
The problem is that this results in circular dependencies, because the pojo would require a reference to the activity context for certain calls, and the Activity would have a reference to the utility class resulting in a circular dependency, which results in tight coupling.
Therefore my thought was to make a hidden fragment and store the code there; this would keep the code in the main activity clean.
What is the usual way to do this?
The current code that I use:
public class HomeActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener{
private static final String TAG = "HOME_ACTIVITY"; // Logging
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationManager mLocationManager;
private LocationRequest mLocationRequest;
private com.google.android.gms.location.LocationListener listener;
private double mLatCurLoc;
private double mLngCurLoc;
private float MIN_DISTANCE = 200.0f;
private long UPDATE_INTERVAL = 2 * 1000; /* 10 secs */
private long FASTEST_INTERVAL = 2000; /* 2 sec */
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationManager = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
}
#Override
protected void onResume(){
super.onResume();
}
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
#Override
public void onConnected(Bundle bundle) {
// Android Studio complains that we should check the permissions before getting last location
// However, we have already checked permissions in the previous activity
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
startLocationUpdates();
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation == null){
startLocationUpdates();
}
if (mLocation != null) {
} else {
Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
}
#Override
protected void onStart() {
super.onStart();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
protected void startLocationUpdates() {
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setSmallestDisplacement(MIN_DISTANCE)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
mLatCurLoc = location.getLatitude();
mLngCurLoc = location.getLongitude();
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.i("LOCATION_CHANGED", msg);
}
}
I think that's the beauty of inheritance in OOP. You'd just have an activity which will deal with location services, and make your other activities who want to deal with locations extend e.g. LocationAwareActivity. The moment one of those activities is not interested in locations you'd just change the parent class, and vice versa, the moment one of your activities would like to be aware of locations - it will extend LocationAwareActivity.
Related
I am using googleAPIClient to get the current lat long values using Location. I am getting the values of both my current lat and long in a separate class. I need to pass these current lat and long values inside my MapsActivity ( GoogleMap Activity), Since I have already created the object for the another class, from which I need to get the values, I don't know how to pass the values to this activity from the class.
Here's what I have tried. This is the class which I have created to get the current lat long values:
CurrentValues.java:
public class CurrentValues implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final String TAG = CurrentValues.class.getSimpleName();
private Context context;
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationManager mLocationManager;
private LocationRequest mLocationRequest;
private long UPDATE_INTERVAL = 2 * 1000; /* 10 secs */
private long FASTEST_INTERVAL = 2000; /* 2 sec */
public CurrentValues( Context context){
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
checkLocation();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
startLocationUpdates();
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation == null){
startLocationUpdates();
}
if (mLocation != null) {
// mLatitudeTextView.setText(String.valueOf(mLocation.getLatitude()));
//mLongitudeTextView.setText(String.valueOf(mLocation.getLongitude()));
} else {
Toast.makeText(context, "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
}
#Override
public void onLocationChanged(Location location) {
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
}
private boolean checkLocation() {
if(!isLocationEnabled())
showAlert();
return isLocationEnabled();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
private boolean isLocationEnabled() {
mLocationManager = (LocationManager)context. getSystemService(Context.LOCATION_SERVICE);
return mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
private void showAlert() {
final AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle("Enable Location")
.setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " +
"use this app")
.setPositiveButton("Location Settings", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
context.startActivity(myIntent);
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
}
});
dialog.show();
}
protected void startLocationUpdates() {
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, (com.google.android.gms.location.LocationListener) context);
Log.d("reque", "--->>>>");
}
}
Now I need to pass the lat long values I got from this class to MapsActivity. Since I had already created object for the currentvalues class here in this activity, I don't know how to pass the value from there to here.
Here's my MapActivity (GoogleMap Activity)
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private CurrentValues currentValues;
private Location location;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// // Add a marker in Sydney and move the camera
// LatLng sydney = new LatLng(-34, 151);
// mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
//
// LatLng chennai = new LatLng(13.06,80);
// mMap.addMarker(new MarkerOptions().position(chennai).title("Marker in Chennai"));
LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
googleMap.addMarker(new MarkerOptions().position(latLng));
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 8f));
// creating object for currentValues class
CurrentValues currentValues = new CurrentValues(this);
}
}
I don't know how to proceed after this to pass the lat long values here. How can I proceed?
I'm trying to get the current location using this code and it works when launching the app and when bringing it to the foreground. The toasts show up in both cases, but otherwise they don't. Can anybody tell me where I messed up?
public class LocationFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
double oldLon,oldLat;
private static final String TAG = MainActivity.class.getSimpleName(); // LogCat tag
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private static final int MY_PERMISSIONS_REQUEST_FINE_LOCATION = 100;
private Location mLastLocation;
private GoogleApiClient mGoogleApiClient;
private FusedLocationProviderClient mFusedLocationClient;
private LocationRequest mLocationRequest;
// Location updates intervals in sec
private static int UPDATE_INTERVAL = 10000; // 10 sec
private static int FATEST_INTERVAL = 5000; // 5 sec
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// First we need to check availability of play services
if (checkPlayServices()) {
buildGoogleApiClient();
createLocationRequest();
}
}
#Override
public void onDetach() {
mCallback = null; // => avoid leaking
super.onDetach();
}
public interface InterfaceTextClicked {
public void sendText(String text);
}
private boolean checkPermission(){
if(ActivityCompat.checkSelfPermission(getContext(),
ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
System.out.println("We have been granted.");
return true;}
else return false;
}
private void requestPermission(){
ActivityCompat.requestPermissions(getActivity(),new String[]
{ACCESS_FINE_LOCATION},MY_PERMISSIONS_REQUEST_FINE_LOCATION);
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_FINE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay!
System.out.println("Permission Granted!");
} else {
// permission denied, boo!
System.out.println("Permission Denied!");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)){
new AlertDialog.Builder(getActivity())
.setMessage("Permission needed to access your location.")
.setPositiveButton("OK", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog,int which){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
requestPermissions(new String[]{ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_FINE_LOCATION);
}
}
})
.setNegativeButton("Cancel", null)
.create()
.show();
return;
}
}
}
// return;
}
}
}
private void displayLocation(){
System.out.println("Inside displayLocation");
requestPermission();
if(checkPermission()){
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
}
if (mLastLocation != null) {
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
System.out.println("Location1: "+latitude+" "+longitude);
if(Double.compare(oldLat,latitude)==0 || Double.compare(oldLon,longitude)==0){
Toast.makeText(getContext(), "Location didn't change! "+latitude+ " "+ longitude,
Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getContext(), "Location changed! NEW: "+latitude+ " "+ longitude+" OLD: "+oldLat+ " "+oldLon,
Toast.LENGTH_LONG).show();
}
// mCallback.sendText(latitude+" "+longitude);
oldLon = longitude;
oldLat = latitude;
} else {
System.out.println("Couldn't get coordinates");
if(mGoogleApiClient.isConnected()){
System.out.println("Client connected");
}else{
System.out.println("Client NOT connected");
}
}
}
/**
* Creating google api client object
* */
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
/**
* Method to verify google play services on the device
* */
private boolean checkPlayServices() {
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int resultCode = googleAPI.isGooglePlayServicesAvailable(getContext());
if (resultCode != ConnectionResult.SUCCESS) {
if(googleAPI.isUserResolvableError(resultCode)){
googleAPI.getErrorDialog(getActivity(),resultCode,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Toast.makeText(getContext(),
"This device is not supported.", Toast.LENGTH_LONG)
.show();
getActivity().finish();
}
return false;
}
return true;
}
#Override
public void onStart() {
super.onStart();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
#Override
public void onResume() {
super.onResume();
if (mGoogleApiClient != null && !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
checkPlayServices();
}
#Override
public void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
/**
* Creating location request object
* */
protected void createLocationRequest() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); }
/**
* Starting the location updates
* */
protected void startLocationUpdates() {
System.out.println("Inside startLocationUpdates");
requestPermission();
if(checkPermission()){
if ((mGoogleApiClient != null) && (mGoogleApiClient.isConnected())){
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
}
}
/**
* Google api callback methods
*/
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
}
#Override
public void onConnected(Bundle arg0){
startLocationUpdates();
// Once connected with google api, get the location
displayLocation();
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
}
#Override
public void onPause() {
super.onPause();
stopLocationUpdates();
}
/**
* Stopping location updates
*/
protected void stopLocationUpdates() {
if ((mGoogleApiClient != null) && (mGoogleApiClient.isConnected())) {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
}
#Override
public void onLocationChanged(Location location) {
// Assign the new location
mLastLocation = location;
Toast.makeText(getContext(), "******Location changed!",
Toast.LENGTH_SHORT).show();
// Displaying the new location on UI
displayLocation();
}
}
Sorry to put so much code up there, I thought my mistake could be anywhere so didn't want to cut out anything.
The Log shows the following:
10-14 01:10:27.408 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: Inside startLocationUpdates
10-14 01:10:27.536 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: We have been granted.
10-14 01:10:27.610 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: Inside displayLocation
10-14 01:10:27.617 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: We have been granted.
10-14 01:10:27.641 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: Location1: 40.4868602 -74.4388156
I don't see anything obviously wrong with your code, though it is making its API calls through the deprecated versions of the location APIs rather than the new FusedLocationProviderClient interface.
While you declare a new-style FusedLocationProviderClient:
private FusedLocationProviderClient mFusedLocationClient;
you never initialize it or use it at runtime; rather you call through FusedLocationApi (the old method):
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
You might try using the new API, which has a slightly more robust interface, to shed some light on your problem. You can get the new API interface with:
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
Then you'll just need to tweak your class to add an onLocationAvailability callback as per the documentation before attaching your listener:
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback,
null /* Looper */);
I want to discuss if there is possibility of getting real time current location update as we move, I tried with FusedLocationProviderClient to request for current location update every 2 minutes
What can we do to achieve this, implement detectActivity for walk and request current location update every 2 minutes or less in it?
or there is on location change listener thing in FusedLocationProviderClient? so that we can listen for if there is change in location and get latlng in real time and display in textview in application? the location change listener is available on GoogleMap object but isn't recommended to use now, am I right?
or should i stick to requestupdate of FusedLocationProviderClient?
Thanks beforehand
Also tell me if i move my phone from one room to another, will there be change in latlng?
You can use this class that i created :
public class LocationFetcher implements com.google.android.gms.location.LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public GoogleApiClient googleApiClient;
Context context;
private LocationRequest locationRequest;
public LocationFetcher(Context context) {
this.context = context;
googleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
locationRequest = new LocationRequest();
}
public void connectGps() {
googleApiClient.connect();
}
public void requestLocationUpdate() {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 100);
} else {
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//Getting location every 3 seconds. You can change this.
locationRequest.setInterval(3000);
locationRequest.setFastestInterval(3000);
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
}
public boolean isConnected() {
return googleApiClient.isConnected();
}
#Override
public void onLocationChanged(Location location) {
//You will get location updates here.
}
#Override
public void onConnected(#Nullable Bundle bundle) {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
if (result != null) {
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
requestLocationUpdate();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
if (status.hasResolution()) {
status.startResolutionForResult((Activity) context, 1000);
}
} catch (IntentSender.SendIntentException e) {
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
});
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
DialogPopup.getInstance().showLocationSettingsAlert(context);
}
public void removeLocationUpdates() {
if (googleApiClient.isConnected()){
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
}
}
public void disconnectGps() {
googleApiClient.disconnect();
}
}
In onStart of your activity call this :
LocationFetcher locationFetcher = new LocationFetcher(this);
locationFetcher.connectGps();
And in onStop use this:
locationFetcher.disconnectGps();
You will get the location updates in the onLocationChangedMethod of the class.
You have to add this dependency too:
compile 'com.google.android.gms:play-services-location:10.2.1'
Hope this helps.
I'm having some trouble and could with some help. I've got a MapsActivity and a LocationHelper class but when loading the MapsActivity I get presented with the errors listed below.
MapsActivity -
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private static final int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
private static final int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 2;
private GoogleMap mMap;
private LocationHelper locationHelper;
private LatLng location;
private boolean onCreateFinished = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onCreateFinished = true;
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
//instantiates LocationHelper for use in this activity
locationHelper = new LocationHelper(this);
//runs startConnection from LocationHelper class
locationHelper.startConnection();
//starts map
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
//mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
//sets map markers
public void setMapMarkers(){
//runs checkLocation from LocationHelper class
locationHelper.checkLocation();
location = new LatLng(locationHelper.mLatitude, locationHelper.mLongitude);
LatLng currentLocation = new LatLng(location.latitude, location.longitude);
mMap.addMarker(new MarkerOptions().position(currentLocation).title("Your Location"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(currentLocation));
}
#Override
protected void onStart() {
locationHelper.mGoogleApiClient.connect();
super.onStart();
}
#Override
protected void onResume() {
super.onResume();
if(onCreateFinished == true){
setMapMarkers();
}else{
Toast.makeText(this, "onCreate not finished..", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onStop() {
locationHelper.mGoogleApiClient.disconnect();
//LocationManager.removeUpdates();
super.onStop();
}
LocationHelper class -
public class LocationHelper extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
//private static final int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
//private static final int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 2;
GoogleApiClient mGoogleApiClient;
private LocationManager mLocationManager;
//private Location mLastLocation;
private LocationListener mLocationListener;
public double mLatitude;
public double mLongitude;
private Context context;
//constructor
public LocationHelper(Context context) {
//saves the context received from activity that instantiates LocationHelper into a local variable
this.context = context;
}
public void startConnection() {
// Create an instance of GoogleAPIClient.
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
public void checkLocation(){
//gets system service from LocationManager
mLocationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
//checks permissions
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
return;
}
mLocationListener = new LocationListener(){
#Override
public void onLocationChanged(Location location) {
//checks if GPS is enabled
if(mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
if(mLocationListener != null){
if(ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
return;
}
if (mLocationManager != null) {
location = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(location != null){
mLatitude = location.getLatitude();
mLongitude = location.getLongitude();
Toast.makeText(getApplicationContext(), "GPS - " + String.valueOf(mLatitude) + "," + String.valueOf(mLongitude), Toast.LENGTH_SHORT).show();
}
}
}
}
//checks if internet is enabled
else if(mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){
if(mLocationManager != null){
location = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(location != null){
mLatitude = location.getLatitude();
mLongitude = location.getLongitude();
Toast.makeText(getApplicationContext(), "NETWORK - " + String.valueOf(mLatitude) + "," + String.valueOf(mLongitude), Toast.LENGTH_SHORT).show();
}
}
}
//method for setting location request parameters
setLocationRequest();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
};
}
#Override
public void onConnected(#Nullable Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
public void setLocationRequest(){
//sets locationrequest parameters
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(3000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}
public double getLatitudeForNote() {
return mLatitude;
}
public double getLongitudeForNote(){
return mLongitude;
}
}
Error -
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.a8460p.locationotes, PID: 1715
java.lang.RuntimeException: Unable to resume activity {com.example.a8460p.locationotes/com.example.a8460p.locationotes.MapsActivity}: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3160)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3191)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2529)
at android.app.ActivityThread.access$900(ActivityThread.java:154)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1391)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:234)
at android.app.ActivityThread.main(ActivityThread.java:5526)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:5300)
at com.example.a8460p.locationotes.LocationHelper.checkLocation(LocationHelper.java:66)
at com.example.a8460p.locationotes.MapsActivity.setMapMarkers(MapsActivity.java:71)
at com.example.a8460p.locationotes.MapsActivity.onResume(MapsActivity.java:88)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1259)
at android.app.Activity.performResume(Activity.java:6361)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3149)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3191)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2529)
at android.app.ActivityThread.access$900(ActivityThread.java:154)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1391)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:234)
at android.app.ActivityThread.main(ActivityThread.java:5526)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Thanks in advance for any help!
Step #1: Delete extends Activity from LocationHelper. This is not an activity.
Step #2: Use the context for your call to getSystemService() inside of LocationHelper.
Step #3: Decide whether you are going to use Android's LocationManager or LocationRequest from the Play Services SDK, and get rid of all the code associated with the one that you are not going to use.
You need to initialize your LocationHelper instance after onCreate completed. You can move related code into onMapReady() method.
I'm trying to request location updates from google play services on my android app. So far I'm able to get last location if i start google maps first, but not able to get any updates.
public class Inbox extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
com.google.android.gms.location.LocationListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int r = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
if(r != 0){
System.out.println(r);
Dialog d = GoogleApiAvailability.getInstance().getErrorDialog(this,r,1);
d.show();
}
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.addApi(AppIndex.API).build();
}
mGoogleApiClient.connect();
super.onStart();
}
#Override
public void onConnected(Bundle bundle) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
System.out.println("Problem with rights");
}
else{
Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
LocationRequest mLocationRequest = new LocationRequest();
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
if(mLastLocation != null){
System.out.println(mLastLocation.toString());
}
else {
System.out.println("No location cached");
}
LocationAvailability a = LocationServices.FusedLocationApi.getLocationAvailability(mGoogleApiClient);
System.out.println(a);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
System.out.println(location.toString());
}
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
Action viewAction = Action.newAction(...);
AppIndex.AppIndexApi.start(mGoogleApiClient, viewAction);
}
#Override
public void onStop() {
super.onStop();
Action viewAction = Action.newAction(...);
AppIndex.AppIndexApi.end(mGoogleApiClient, viewAction);
mGoogleApiClient.disconnect();
}
}
When i start the app after using google maps, i get the last cached location from:
LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
But right after, i print out that location services are unavailable with this:
LocationAvailability a = LocationServices.FusedLocationApi.getLocationAvailability(mGoogleApiClient);
System.out.println(a);
onLocationChanged/onConnectionFailed/onConnectionSuspended are never called.
I'm running my app on a virtual Nexus 6 with android 5.1.0 on Genymotion.
I think you missed a few things here. In you onCennected callback, you have to first check if you can get last known location. If it is not available then you have to request location updates. Refactor your onConnected as shown below and it should work fine
#Override
public void onConnected(Bundle bundle) {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
System.out.println("Problem with rights");
} else {
Location lastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (lastLocation != null) {
//you have a location. use that here. no need to request for location
// updates
mGoogleApiClient.disconnect();
} else {
//you have to request for location
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(2000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setSmallestDisplacement(50);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi
.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
}
And in your locationChanged callback do the following
#Override
public void onLocationChanged(Location location) {
//now that we got the initial location. it is time to stop the api client
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
// use your newly obtained location here
}
Note : If you try this on GenyMotion. Make sure it can receive location by enabling GPS on the GM emulator