如何在 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 有效并将其添加到您的清单 &lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&gt;

这是我的地图活动。其中可能有一些冗余信息,因为它来自我创建的一个更大的项目。

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)?

Android Marshmallow:使用 Espresso 测试权限?

如何从 Android 版本 Marshmallow 开始请求从 Android 拨打电话的权限?