2

I've developed a simple weather app, but there is too much code in my WeatherActivity and two responsibilities for one class(handling weather JSON, and retrieving location info using googleapiclient). I tried to get the code that handles location out of the WeatherActivity class, but as I try to get any location in the onCreate method, it usually results in null, probably because it's not enough time to be updated. Is there any way to get users location outside of the activity? Or if you have another suggestion that might help in that situation?

  • Please post some code. It's not clear what's the problem, theoretically it should definitely be possible. – Egor Jul 11 '15 at 20:42
  • Unfortunately, I can't at the moment. But the problem is that LocationManager(my custom class which implement googleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener) is not updated fast enough. My WeatherActivity calls LocationManager.getLocation before the location get updated, therefore getting null. – Evgeny Goldin Jul 12 '15 at 07:27
  • It is not the complete solution to your problem, but might give you some ideas: http://stackoverflow.com/questions/31734567/separating-the-concerns-of-activity-and-googleapiclient – JP Ventura Jul 30 '15 at 21:44

1 Answers1

4

I have been looking for a solution to have an object to handle the current location but I didn't find anything. So I did it this way but it's a little bit tricky. Hope it helps you.

import android.Manifest;
import android.app.Activity;

import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

/**
 * This class uses GoogleApiClient to track location changes.
 * In order to connect the GoogleApiClient correctly, this class must be instanciated in onCreate callback.
 */
public class Locator implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    private static final String TAG = "Locator";
    private Activity activity;
    private GoogleApiClient googleApiClient;
    private LocationRequest locationRequest;
    private static final long UPDATE_INTERVAL = 60 * 1000;
    private static final long FASTEST_UPDATE_INTERVAL = 10 * 1000;
    private static final int LOCATION_REQUEST = 1;
    private static boolean locationPermissionRequested = false;
    private static boolean locationPermissionGranted = false;
    private Location location;

    /**
     * Default constructor. Ex. Locator locator = new Locator(getActivity());
     *
     * @param activity The activity to instanciate from.
     */
    public Locator(Activity activity) {
        this.activity = activity;
        if (activity != null) {
            googleApiClient = new GoogleApiClient.Builder(activity)
                    .addApi(LocationServices.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this).build();
            locationRequest = new LocationRequest();
            locationRequest.setInterval(UPDATE_INTERVAL);
            locationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL);
            locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
            googleApiClient.connect();
        }
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        requestLocation();
    }

    @Override
    public void onConnectionSuspended(int i) {
    }

    @Override
    public void onLocationChanged(Location location) {
        this.location = location;
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    }

    /**
     * Requests the current location to the GoogleApiClient.
     * NB: If device os is Marshmallow or higher, il will also ask permission to acces location services.
     */
    private void requestLocation() {
        if (googleApiClient.isConnected()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                locationPermissionGranted = ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
                if (!locationPermissionGranted) {
                    if (!locationPermissionRequested) {
                        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_REQUEST);
                        locationPermissionRequested = true;
                        requestLocation();
                    }
                }
            } else {
                locationPermissionGranted = true;
            }
            if (locationPermissionGranted) {
                LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
            } else {
            }
        }
    }

    /**
     * Requests the current location et gets.
     *
     * @return The location.
     */
    public Location getLocation() {
        requestLocation();
        return location;
    }

    /**
     * Stops updating the location. (save battery power).
     */
    public void removeUpdates() {
        LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
    }
}
Shkelzen
  • 178
  • 1
  • 11