Android Google Maps API OnLocationChanged 仅调用一次
Posted
技术标签:
【中文标题】Android Google Maps API OnLocationChanged 仅调用一次【英文标题】:Android Google Maps API OnLocationChanged only called once 【发布时间】:2017-07-19 12:29:21 【问题描述】:每当我的位置发生变化时,我都会尝试更新我的相机。然而,onLocationChanged 只被调用一次。当我之后在模拟器中发送新位置时,不会调用 onLocationChanged。
我已经尝试了几个小时,但似乎无法修复它。
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.
调试输出:
【问题讨论】:
【参考方案1】:我认为您需要使用位置管理器。有很好的教程here。
网站上说的是你需要添加以下内容:
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER,
2000,
10, this);
第一个参数是您正在使用的提供程序(在本例中为 GPS 提供程序)。第二个参数 (2000) 是每次更新之间的最短时间(以毫秒为单位)。第三个参数(10)是最小距离。最后一个参数是你的 LocationListener (this)。
在用户关闭 GPS 的情况下,实施 onProviderDisabled
也是一个好主意。
【讨论】:
我现在正在尝试这个,但在第 3 步我收到错误:“无法解析方法”。我认为这可能是因为最后一个参数“this”。这很奇怪,因为我正在实现 com.google.android.gms.location.LocationListener。 那么您正在使用 Google Play Services Location API。 所以在我导入 android.location.LocationListener 而不是 com.google.android.gms.location.LocationListener 之后,它就像一个魅力,非常感谢! 非常棒,感谢为我工作。以上是关于Android Google Maps API OnLocationChanged 仅调用一次的主要内容,如果未能解决你的问题,请参考以下文章
Google Geolocation API 和 Google Maps Android SDK
Android:使用 Google API 获取实时方向,还是与 Google Maps 通信?
Android Manifest 未向 Google Maps 提供 API 密钥
为 Google Maps API v2 Android 发布流媒体方向