1

I am trying to get Google Maps to show the user's current location and update every 15 seconds or so. I've implemented the API using the new FusedLocationProviderClient but the camera does not centre on the user location nor does it respond to changes in latitude and longitude.

I have set up the Android Manifest and Gradle dependencies. I know that FusedLocationProviderClient.getLastLocation() is null because there has been no location provided previously. So I've tried implementing LocationCallback and requestLocationUpdates to try update the location but this is not working either.

I had a thought that this whole problem may be due to the Android Virtual Emulator unable to simulate user location although I'm not sure how to work with this.

I am using Nexus 5x API 26 emulator. The code is below.

Thanks

public class ExploreActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    FusedLocationProviderClient fusedLocationClient;
    LocationRequest locationRequest;
    LocationCallback locationCallback;
    static final int LOCATION_PERMISSION_REQUEST = 101;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_explore);

        if (Build.VERSION.SDK_INT >= 23) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                Log.i("onCreate", "requesting permission");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST);
            } else {
                initMap();
            }
        }

        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        locationRequest = new LocationRequest();
        locationRequest.setInterval(15000); //interval between updates
        locationRequest.setFastestInterval(5000); //if there is another app updating more often, then simply take that location
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        //setup location call back
        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
                Log.i("callback", "working");
                for (Location location : locationResult.getLocations()) {
                    LatLng userLocation = new LatLng(location.getLatitude(), location.getLongitude());
                    Log.i("lat", Double.toString(userLocation.latitude));
                    Log.i("long", Double.toString(userLocation.longitude));

                }
            }
        };
    }

    private void initMap() {
        // 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) {
        Toast.makeText(this, "Map is ready", Toast.LENGTH_SHORT).show();
        mMap = googleMap;

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            Log.i("onMapReady", "permission has been granted");
            mMap.setMyLocationEnabled(true);
            fusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
                @Override
                public void onSuccess(Location location) {
                    if (location != null) {
                        Log.i("onSuccess", "success");
                        LatLng userLocation = new LatLng(location.getLatitude(), location.getLongitude());
                        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 13));
                    } else {
                        Log.i("onSuccess", "failed");
                        //location is null possibly due last location not being initialized
                    }
                }
            });
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case LOCATION_PERMISSION_REQUEST:
                if (grantResults.length > 0) {
                    for (int i = 0; i < grantResults.length; i++) {
                        if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "This app requires location permissions for the map to show!", Toast.LENGTH_SHORT).show();
                            return;
                        }
                    }
                    initMap();
                } else {
                    Toast.makeText(this, "This app requires location permissions for the map to show!", Toast.LENGTH_SHORT).show();
                }
        }
    }

    //run after onCreate method
    @Override
    protected void onResume() {
        super.onResume();
        startLocationUpdates();
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopLocationUpdate();
    }

    private void stopLocationUpdate() {
        fusedLocationClient.removeLocationUpdates(locationCallback);
    }

    private void startLocationUpdates() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);
            Log.i("startLocationUpdates", "started");
            //looper at null ensures it calls on this thread
        } else{
            //request permissions again (for safety)
            if (Build.VERSION.SDK_INT >= 23) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
            }
        }
    }

}
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131
Jayyunit
  • 55
  • 1
  • 1
  • 9
  • From my experience, it's difficult to get an emulator to simulate GPS unless you manually plug-in coordinates. I suggest plugging a real android device into your computer through USB (and make sure it's in developer mode). Real devices usually can handle Google Maps better. – zuko May 23 '18 at 18:53
  • Interesting. It works that way. Thanks! Do you know why it doesn't work on an emulator though? Because i've watched tutorials and it works on the emulator. – Jayyunit May 23 '18 at 21:13
  • It's not that emulators don't work, it's just that you generally have to add more steps to have it do what you want. I don't like to waste time so I find it easier to just use a real device. If you're curious to use an emulator for future purposes, check out the link. [this discussion covers GPS and emulators pretty well](https://stackoverflow.com/questions/2279647/how-to-emulate-gps-location-in-the-android-emulator?rq=1) – zuko May 24 '18 at 00:07

0 Answers0