Android Google Maps API OnLocationChanged only called once

I'm trying to update my camera whenever my location changes. However, onLocationChanged is only called once. When I send a new location afterwards in my emulator, onLocationChanged is not called.

I've been trying for hours now and I can't seem to fix it.

public class RouteActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { private GoogleMap mMap; ArrayList<LatLng> MarkerPoints; GoogleApiClient mGoogleApiClient; Location mLastLocation; Marker mCurrLocationMarker; LocationRequest mLocationRequest; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.route); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkLocationPermission(); } // Initializing MarkerPoints = new ArrayList<LatLng>(); // 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; //Initialize Google Play Services if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { buildGoogleApiClient(); mMap.setMyLocationEnabled(true); } } else { buildGoogleApiClient(); mMap.setMyLocationEnabled(true); } // Setting onclick event listener for the map mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng point) { // Already two locations if (MarkerPoints.size() > 1) { MarkerPoints.clear(); mMap.clear(); } // Adding new item to the ArrayList MarkerPoints.add(point); // Creating MarkerOptions MarkerOptions options = new MarkerOptions(); // Setting the position of the marker options.position(point); /** * For the start location, the color of marker is GREEN and * for the end location, the color of marker is RED. */ if (MarkerPoints.size() == 1) { options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); } else if (MarkerPoints.size() == 2) { options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)); } // Add new marker to the Google Map Android API V2 mMap.addMarker(options); // Checks, whether start and end locations are captured if (MarkerPoints.size() >= 2) { LatLng origin = MarkerPoints.get(0); LatLng dest = MarkerPoints.get(1); // Getting URL to the Google Directions API String url = getUrl(origin, dest); Log.d("onMapClick", url.toString()); FetchUrl FetchUrl = new FetchUrl(); // Start downloading json data from Google Directions API FetchUrl.execute(url); //move map camera mMap.moveCamera(CameraUpdateFactory.newLatLng(origin)); mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); } } }); } private String getUrl(LatLng origin, LatLng dest) { // Origin of route String str_origin = "origin=" + origin.latitude + "," + origin.longitude; // Destination of route String str_dest = "destination=" + dest.latitude + "," + dest.longitude; // Sensor enabled String sensor = "sensor=false"; // Building the parameters to the web service String parameters = str_origin + "&" + str_dest + "&" + sensor; // Output format String output = "json"; // Building the url to the web service String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters; return url; } /** * A method to download json data from url */ private String downloadUrl(String strUrl) throws IOException { String data = ""; InputStream iStream = null; HttpURLConnection urlConnection = null; try { URL url = new URL(strUrl); // Creating an http connection to communicate with url urlConnection = (HttpURLConnection) url.openConnection(); // Connecting to url urlConnection.connect(); // Reading data from url iStream = urlConnection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(iStream)); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } data = sb.toString(); Log.d("downloadUrl", data.toString()); br.close(); } catch (Exception e) { Log.d("Exception", e.toString()); } finally { iStream.close(); urlConnection.disconnect(); } return data; } // Fetches data from url passed private class FetchUrl extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... url) { // For storing data from web service String data = ""; try { // Fetching the data from web service data = downloadUrl(url[0]); Log.d("Background Task data", data.toString()); } catch (Exception e) { Log.d("Background Task", e.toString()); } return data; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); ParserTask parserTask = new ParserTask(); // Invokes the thread for parsing the JSON data parserTask.execute(result); } } /** * A class to parse the Google Places in JSON format */ private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> { // Parsing the data in non-ui thread @Override protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) { JSONObject jObject; List<List<HashMap<String, String>>> routes = null; try { jObject = new JSONObject(jsonData[0]); Log.d("ParserTask",jsonData[0].toString()); DataParser parser = new DataParser(); Log.d("ParserTask", parser.toString()); // Starts parsing data routes = parser.parse(jObject); Log.d("ParserTask","Executing routes"); Log.d("ParserTask",routes.toString()); } catch (Exception e) { Log.d("ParserTask",e.toString()); e.printStackTrace(); } return routes; } // Executes in UI thread, after the parsing process @Override protected void onPostExecute(List<List<HashMap<String, String>>> result) { ArrayList<LatLng> points; PolylineOptions lineOptions = null; // Traversing through all the routes for (int i = 0; i < result.size(); i++) { points = new ArrayList<LatLng>(); lineOptions = new PolylineOptions(); // Fetching i-th route List<HashMap<String, String>> path = result.get(i); // Fetching all the points in i-th route for (int j = 0; j < path.size(); j++) { HashMap<String, String> point = path.get(j); double lat = Double.parseDouble(point.get("lat")); double lng = Double.parseDouble(point.get("lng")); LatLng position = new LatLng(lat, lng); points.add(position); } // Adding all the points in the route to LineOptions lineOptions.addAll(points); lineOptions.width(10); lineOptions.color(Color.BLUE); Log.d("onPostExecute","onPostExecute lineoptions decoded"); } // Drawing polyline in the Google Map for the i-th route if(lineOptions != null) { mMap.addPolyline(lineOptions); } else { Log.d("onPostExecute","without Polylines drawn"); } } } protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); mGoogleApiClient.connect(); } @Override public void onConnected(Bundle bundle) { Log.i("LOCATION", "Connected!"); mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(1000); mLocationRequest.setFastestInterval(1000); mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); Log.i("LOCATION", "Request location updates are running"); } else { Log.e("LOCATION", "Request location updates are NOT running!!! - No permissions gained"); } } @Override public void onConnectionSuspended(int i) { Log.i("LOCATION", "Connection suspended!"); } @Override public void onLocationChanged(Location location) { Log.i("LOCATION", "Location changed"); mLastLocation = location; if (mCurrLocationMarker != null) { mCurrLocationMarker.remove(); } //Place current location marker LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); //move map camera mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); //stop location updates if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); } } @Override public void onConnectionFailed(ConnectionResult connectionResult) { Log.i("LOCATION", "Connection failed"); } public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99; public boolean checkLocationPermission(){ if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Asking user if explanation is needed if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. //Prompt the user once explanation has been shown ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } return false; } else { return true; } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_LOCATION: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted. Do the // contacts-related task you need to do. if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (mGoogleApiClient == null) { buildGoogleApiClient(); } mMap.setMyLocationEnabled(true); } } else { // Permission denied, Disable the functionality that depends on this permission. Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show(); } return; } // other 'case' lines to check for other permissions this app might request. // You can add here other case statements according to your requirement. } }}

Debug output: <img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/KI7nc.png" alt="Logs">


I think you need to use the Location Manager. There is a good tutorial here.

What is say's on the website is that you need to add the following:

LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 2000, 10, this);

the first parameters is the provider you are using (in this case the GPS Provider). The second parameter (2000) is the minimum time in milliseconds between each update. The third parameter (10) is the minimum distance. The last parameters is your LocationListener (this).

It is also a good idea to implement onProviderDisabled in case the user has his GPS turned off.


  • clicking in ballon in mapview should start another activity
  • Why are my overlays on a mapview not shown?
  • How to Hide Navigation bar back button title globally in xamarin.ios
  • Absolutely positioned pseudo element inside table cell does not cover parent in IE9/10
  • How to get the position of a click event relative to its layer in KineticJS?
  • Is the listview recycling early? Or is Universal ImageLoader canceling in error? Or is my Logic wron
  • After converting my FBX file to a .gltf, the model is incredibly small, why?
  • Getting data from database using HQL
  • Nested not working on slide
  • Remove item from the listview in Android
  • PDF using WCF Restful Services
  • jParallax trouble
  • Javascript: Looping through an array to create listeners, issue with call by reference and value?
  • How to define an array of floats in Shader properties?
  • Serve file to user over http via php
  • @tailrec why does this method not compile with 'contains a recursive call not in tail position&
  • Changing a global variable in C
  • Making header act like google chrome mobile app address bar
  • Receive mouse move even cursor is outside control
  • Rodeo UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 0: ordinal
  • CSS bleed-through with cfinput type=“datefield”
  • Dynamically switching connect in Modelica
  • Clarification on min distance on LocationManager.requestLocationUpdates method, min Distance paramet
  • Validate child input components on submit with Vee-Validate and vue js 2
  • GridView breaks while scrolling
  • Blackberry - Custom EditField Cursor
  • Body moving without any force applied? (Box2d)
  • Debugging ASP.NET on a built-in web server suddenly stops
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • javaw.exe and eclipse startup problems
  • Properly structure and highlight a GtkPopoverMenu using PyGObject
  • using conditional logic : check if record exists; if it does, update it, if not, create it
  • python regex in pyparsing
  • How can I get HTML syntax highlighting in my editor for CakePHP?
  • JTable with a ScrollPane misbehaving
  • Angular 2 constructor injection vs direct access
  • Java static initializers and reflection
  • Android Google Maps API OnLocationChanged only called once
  • UserPrincipal.Current returns apppool on IIS
  • How can I use threading to 'tick' a timer to be accessed by other threads?