如何在 Android Marshmallow 上的 Google 地图上显示当前位置?
Posted
技术标签:
【中文标题】如何在 Android Marshmallow 上的 Google 地图上显示当前位置?【英文标题】:How can I show current location on a Google Map on Android Marshmallow? 【发布时间】:2016-04-07 13:08:15 【问题描述】:我希望谷歌地图显示用户的位置。我试过这段代码,但它在 android 6 上不起作用。
private GoogleMap map;
LocationManager lm;
LocationListener ll;
Location l;
LatLng pos;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.start_layout);
lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
ll = new LocationListener()
@Override
public void onLocationChanged(Location location)
l = (Location) location;
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
@Override
public void onProviderEnabled(String provider)
@Override
public void onProviderDisabled(String provider)
;
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.nMap);
mapFragment.getMapAsync(this);
@Override
public void onMapReady(GoogleMap googleMap)
map = googleMap;
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
lm.requestLocationUpdates(lm.NETWORK_PROVIDER, 0, 0, ll);
pos = new LatLng(l.getLatitude(), l.getLongitude());
// Add a marker in Sydney and move the camera
map.setMyLocationEnabled(true);
map.addMarker(new MarkerOptions().position(pos).title("Marker in Sydney"));
map.moveCamera(CameraUpdateFactory.newLatLng(pos));
这是我设置的权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
【问题讨论】:
在什么情况下不起作用?碰撞?位置不对?还要检查你的 logcat 是否有任何错误并将它们发布在这里。 【参考方案1】:将 FusedLocationProviderClient 与 Google Play Services 11 及更高版本一起使用:
请看这里: How to get current Location in GoogleMap using FusedLocationProviderClient
用于使用(现已弃用)FusedLocationProviderApi:
如果您的项目使用 Google Play Services 10 或更低版本,则使用 FusedLocationProviderApi 是最佳选择。
FusedLocationProviderApi 比旧的开源 LocationManager API 提供更少的电池消耗。 此外,如果您已经在使用 Google Play Services for Google Maps,那么没有理由不使用它。
这是一个完整的 Activity 类,它在当前位置放置一个 Marker,并将相机移动到当前位置。
它还会在运行时检查 Android 6 及更高版本(Marshmallow、Nougat、Oreo)的位置权限。
为了正确处理 Android M/Android 6 及更高版本所需的位置权限运行时检查,您需要确保用户在调用mGoogleMap.setMyLocationEnabled(true)
之前以及在请求位置更新之前已授予您的应用程序位置权限。
public class MapLocationActivity extends AppCompatActivity
implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener
GoogleMap mGoogleMap;
SupportMapFragment mapFrag;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().setTitle("Map Location Activity");
mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFrag.getMapAsync(this);
@Override
public void onPause()
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null)
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
@Override
public void onMapReady(GoogleMap googleMap)
mGoogleMap=googleMap;
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//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)
//Location Permission already granted
buildGoogleApiClient();
mGoogleMap.setMyLocationEnabled(true);
else
//Request Location Permission
checkLocationPermission();
else
buildGoogleApiClient();
mGoogleMap.setMyLocationEnabled(true);
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)
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);
@Override
public void onConnectionSuspended(int i)
@Override
public void onConnectionFailed(ConnectionResult connectionResult)
@Override
public void onLocationChanged(Location location)
mLastLocation = location;
if (mCurrLocationMarker != null)
mCurrLocationMarker.remove();
//Place current location marker
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);
//move map camera
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,11));
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
private void checkLocationPermission()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)
// Should we show an explanation?
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.
new AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to use location functionality")
.setPositiveButton("OK", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialogInterface, int i)
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MapLocationActivity.this,
new String[]Manifest.permission.ACCESS_FINE_LOCATION,
MY_PERMISSIONS_REQUEST_LOCATION );
)
.create()
.show();
else
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]Manifest.permission.ACCESS_FINE_LOCATION,
MY_PERMISSIONS_REQUEST_LOCATION );
@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, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED)
if (mGoogleApiClient == null)
buildGoogleApiClient();
mGoogleMap.setMyLocationEnabled(true);
else
// permission denied, boo! 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
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_
android:layout_>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_
android:layout_
android:id="@+id/map"
tools:context=".MapLocationActivity"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
</LinearLayout>
结果:
如果需要,使用 AlertDialog 显示权限说明(如果用户拒绝权限请求,或授予权限然后在设置中撤销它,则会发生这种情况):
通过调用ActivityCompat.requestPermissions()
提示用户位置权限:
在授予位置权限后将相机移动到当前位置并放置标记:
【讨论】:
很棒的答案,在片段上也完美无缺。 LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); - 我尝试了你的解决方案,我被这行代码卡住了,说“无法解析 requestLocationUpdates” @RoCk 确保您的导入是import com.google.android.gms.location.LocationListener;
,请参阅此处了解导入:***.com/a/31448567/4409409
@LalindaSampath 在启用 WiFi 和 GPS 的情况下效果最佳。它可以在关闭 WiFi 并启用 GPS 的情况下工作,但可能需要更长时间才能获得第一次位置更新,因为 GPS 实际上需要使用卫星来定位您。如果您仅使用 GPS 进行测试,请务必到户外走动进行测试。
@lalinda 是的,Geocoder 需要互联网连接才能工作。它可以是 WiFi 或蜂窝网络,但您需要有效的数据连接。【参考方案2】:
抱歉,开销太大(上),短而快,如果你有 MapFragment,你还必须映射,只需执行以下操作:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
googleMap.setMyLocationEnabled(true)
else
// Show rationale and request permission.
代码在 Kotlin 中,希望您不要介意。
玩得开心
顺便说一句,我认为这个是重复的:Show Current Location inside Google Map Fragment
【讨论】:
那么你应该使用googleMap?.isMyLocationEnabled = true
。
这比 Kotlin 早了很久 :) 但是是的,似乎是个好主意
它不会将相机移动到您的位置。它只启用地图上的图标。【参考方案3】:
首先确保您的 API Key 有效并将其添加到您的清单 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
这是我的地图活动。其中可能有一些冗余信息,因为它来自我创建的一个更大的项目。
import android.content.Intent;
import android.content.IntentSender;
import android.location.Location;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
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;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends FragmentActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener
//These variable are initalized here as they need to be used in more than one methid
private double currentLatitude; //lat of user
private double currentLongitude; //long of user
private double latitudeVillageApartmets= 53.385952001750184;
private double longitudeVillageApartments= -6.599087119102478;
public static final String TAG = MapsActivity.class.getSimpleName();
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds
/*These methods all have to do with the map and wht happens if the activity is paused etc*/
//contains lat and lon of another marker
private void setUpMap()
MarkerOptions marker = new MarkerOptions().position(new LatLng(latitudeVillageApartmets, longitudeVillageApartments)).title("1"); //create marker
mMap.addMarker(marker); // adding marker
//contains your lat and lon
private void handleNewLocation(Location location)
Log.d(TAG, location.toString());
currentLatitude = location.getLatitude();
currentLongitude = location.getLongitude();
LatLng latLng = new LatLng(currentLatitude, currentLongitude);
MarkerOptions options = new MarkerOptions()
.position(latLng)
.title("You are here");
mMap.addMarker(options);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom((latLng), 11.0F));
@Override
protected void onResume()
super.onResume();
setUpMapIfNeeded();
mGoogleApiClient.connect();
@Override
protected void onPause()
super.onPause();
if (mGoogleApiClient.isConnected())
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
private void setUpMapIfNeeded()
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null)
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null)
setUpMap();
@Override
public void onConnected(Bundle bundle)
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null)
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
else
handleNewLocation(location);
@Override
public void onConnectionSuspended(int i)
@Override
public void onConnectionFailed(ConnectionResult connectionResult)
if (connectionResult.hasResolution())
try
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
catch (IntentSender.SendIntentException e)
// Log the error
e.printStackTrace();
else
/*
* If no resolution is available, display a dialog to the
* user with the error.
*/
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
@Override
public void onLocationChanged(Location location)
handleNewLocation(location);
这里有很多难以理解的方法,但基本上都是在地图暂停时更新地图等。还有连接超时等。抱歉刚刚发布这个,我试图修复你的代码,但我想不通找出问题所在。
【讨论】:
以上是关于如何在 Android Marshmallow 上的 Google 地图上显示当前位置?的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式打开 Android 6.0 (Marshmallow) 上特定应用的权限屏幕?
如何在 Android Marshmallow 上使用旧版 Apache HTTP 客户端?
如何在 Android 6.0 Marshmallow 中访问相机?
如何在打盹模式下移动设备(Android Preview M / Marshmallow)?