【问题标题】:How to get current Location in GoogleMap using FusedLocationProviderClient如何使用 FusedLocationProviderClient 在 GoogleMap 中获取当前位置
【发布时间】:2017-12-13 00:07:59
【问题描述】:

我想获得定期(比如每 2 分钟)的当前位置更新我正在关注官方文档,我编写了这段代码,但即使在我传递的 LocationRequest 对象中指定,它也没有每两分钟提供一次当前位置更新在 requestLocationUpdates() 中,代码如下:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
    GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{

private FusedLocationProviderClient FusedLocationClient;
private GoogleApiClient mGoogleApiClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

 SupportMapFragment map = 
  getSupportFragmentManager().findFragmentById(R.id.map));

  map.getMapAsync(this);

  FusedLocationClient LocationServices.getFusedLocationProviderClient(this);
}


@Override
public void onConnected(Bundle bundle) {
    FusedLocationClient.getLastLocation()
            .addOnSuccessListener(this, new OnSuccessListener<Location>() {
                @Override
                public void onSuccess(Location location) {

                    if (location != null) {
                        Log.i("MainActivity ", "" + location.getLongitude()) 
                    }
                }
            });
FusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
FusedLocationClient.requestLocationUpdates(requestLocation(), 
new LocationCallback(){
        @Override
        public void onLocationResult(LocationResult locationResult) {
            for (Location location : locationResult.getLocations()) {
               Log.i("MainActivity ", "" + location.getLongitude());
               //not getting current location updates every 2 minutes
            }
        };

    },null);

}

@Override
public void onConnectionSuspended(int i) {}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {}

【问题讨论】:

    标签: java android google-maps-android-api-2 android-fusedlocation


    【解决方案1】:

    这类似于我的other answer here,更新为使用最近引入的FusedLocationProviderClient 类。

    为了将 FusedLocationProviderClient 与 Google 地图结合使用:

    1. 等到 Google 地图准备就绪

    2. 如果需要,在运行时请求位置权限

    3. 在授予权限后请求位置更新

    4. 获取用户位置后更新谷歌地图

    首先确保您使用的是至少版本 11 的 Google Play 服务,因为旧版本没有 FusedLocationProviderClient 类(新版本也可以使用):

    dependencies {
          implementation 'com.google.android.gms:play-services-maps:17.0.0'
          implementation 'com.google.android.gms:play-services-location:17.0.0'
        //........
    }
    

    请注意,FusedLocationProviderClient 存在于版本 11.0.2 中,但由于初始实现中的错误,建议您仅在 11.6.0 及更高版本上使用此类。 来自文档:

    注意:建议使用 Google Play 服务版本 11.6.0 或 更高,其中包括针对此类的错误修复。

    在 AndroidManifest.xml 文件中,manifest 标签内和application 标签外添加位置权限:

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    

    将 API 密钥添加到 application 标签内的 AndroidManifest.xml:

        <meta-data
                android:name="com.google.android.geo.API_KEY"
                android:value="AIza___YOUR_KEY_HERE______"/>
    

    科特林

    这是 Kotlin 中完整的 Activity 类:

    class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
    
        lateinit var mGoogleMap: GoogleMap
        var mapFrag: SupportMapFragment? = null
        lateinit var mLocationRequest: LocationRequest
        var mLastLocation: Location? = null
        internal var mCurrLocationMarker: Marker? = null
        internal var mFusedLocationClient: FusedLocationProviderClient? = null
    
        internal var mLocationCallback: LocationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                val locationList = locationResult.locations
                if (locationList.isNotEmpty()) {
                    //The last location in the list is the newest
                    val location = locationList.last()
                    Log.i("MapsActivity", "Location: " + location.getLatitude() + " " + location.getLongitude())
                    mLastLocation = location
                    if (mCurrLocationMarker != null) {
                        mCurrLocationMarker?.remove()
                    }
    
                    //Place current location marker
                    val latLng = LatLng(location.latitude, location.longitude)
                    val markerOptions = 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.0F))
                }
            }
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_maps)
    
            supportActionBar?.title = "Map Location Activity"
    
            mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    
            mapFrag = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
            mapFrag?.getMapAsync(this)
        }
    
        public override fun onPause() {
            super.onPause()
    
            //stop location updates when Activity is no longer active
            mFusedLocationClient?.removeLocationUpdates(mLocationCallback)
        }
    
        override fun onMapReady(googleMap: GoogleMap) {
            mGoogleMap = googleMap
            mGoogleMap.mapType = GoogleMap.MAP_TYPE_HYBRID
    
            mLocationRequest = LocationRequest()
            mLocationRequest.interval = 120000 // two minute interval
            mLocationRequest.fastestInterval = 120000
            mLocationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (ContextCompat.checkSelfPermission(
                        this,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    ) == PackageManager.PERMISSION_GRANTED
                ) {
                    //Location Permission already granted
                    mFusedLocationClient?.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper())
                    mGoogleMap.isMyLocationEnabled = true
                } else {
                    //Request Location Permission
                    checkLocationPermission()
                }
            } else {
                mFusedLocationClient?.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper())
                mGoogleMap.isMyLocationEnabled = true
            }
        }
    
        private fun checkLocationPermission() {
            if (ActivityCompat.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.
                    AlertDialog.Builder(this)
                        .setTitle("Location Permission Needed")
                        .setMessage("This app needs the Location permission, please accept to use location functionality")
                        .setPositiveButton(
                            "OK"
                        ) { _, _ ->
                            //Prompt the user once explanation has been shown
                            ActivityCompat.requestPermissions(
                                this@MapsActivity,
                                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                                MY_PERMISSIONS_REQUEST_LOCATION
                            )
                        }
                        .create()
                        .show()
    
    
                } else {
                    // No explanation needed, we can request the permission.
                    ActivityCompat.requestPermissions(
                        this,
                        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                        MY_PERMISSIONS_REQUEST_LOCATION
                    )
                }
            }
        }
    
        override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<String>, grantResults: IntArray
        ) {
            when (requestCode) {
                MY_PERMISSIONS_REQUEST_LOCATION -> {
                    // If request is cancelled, the result arrays are empty.
                    if (grantResults.isNotEmpty() && 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
                        ) {
    
                            mFusedLocationClient?.requestLocationUpdates(
                                mLocationRequest,
                                mLocationCallback,
                                Looper.myLooper()
                            )
                            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
        }
    
        companion object {
            val MY_PERMISSIONS_REQUEST_LOCATION = 99
        }
    }
    

    Java

    这是完整的 Java Activity 类:

    public class MapsActivity extends AppCompatActivity
            implements OnMapReadyCallback {
    
        GoogleMap mGoogleMap;
        SupportMapFragment mapFrag;
        LocationRequest mLocationRequest;
        Location mLastLocation;
        Marker mCurrLocationMarker;
        FusedLocationProviderClient mFusedLocationClient;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_maps);
    
            getSupportActionBar().setTitle("Map Location Activity");
    
            mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    
            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 (mFusedLocationClient != null) {
                mFusedLocationClient.removeLocationUpdates(mLocationCallback);
            }
        }
    
        @Override
        public void onMapReady(GoogleMap googleMap) {
            mGoogleMap = googleMap;
            mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
    
            mLocationRequest = new LocationRequest();
            mLocationRequest.setInterval(120000); // two minute interval
            mLocationRequest.setFastestInterval(120000);
            mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    
            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
                    mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
                    mGoogleMap.setMyLocationEnabled(true);
                } else {
                    //Request Location Permission
                    checkLocationPermission();
                }
            }
            else {
                mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
                mGoogleMap.setMyLocationEnabled(true);
            }
        }
    
        LocationCallback mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                List<Location> locationList = locationResult.getLocations();
                if (locationList.size() > 0) {
                    //The last location in the list is the newest
                    Location location = locationList.get(locationList.size() - 1);
                    Log.i("MapsActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());
                    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(MapsActivity.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) {
    
                            mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
                            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_maps.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".map.MapsActivity">
    
        <fragment android:id="@+id/map"
                  xmlns:tools="http://schemas.android.com/tools"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  tools:context=".map.MapsActivity"
                  app:layout_constraintTop_toTopOf="parent"
                  app:layout_constraintStart_toStartOf="parent"
                  app:layout_constraintBottom_toBottomOf="parent"
                  app:layout_constraintEnd_toEndOf="parent"
                  android:name="com.google.android.gms.maps.SupportMapFragment"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    将提示用户接受位置权限:

    位置将在应用启动时更新,每两分钟更新一次:

    关于 AndroidX 的额外说明

    如果您使用的是 AndroidX,请将you might need to add these lines 添加到您的gradle.properties 文件(有关详细信息,请参阅here):

    android.useAndroidX=true
    android.enableJetifier=true
    

    【讨论】:

    • 谢谢,如果我们想每移动 10 步获取设备当前位置,例如我们正在移动并实时获取当前位置更新,该怎么办?
    • 坐标也有细微的变化,比如我第一次得到 25.3767231 和后来的 25.3756256,即使设备位置在得到 2 次更新后也没有改变,延迟正在增加
    • @blackHawk 对于第一条评论,您可以设置更小的时间间隔,并在 LocationRequest 上使用setSmallestDisplacement() 方法:developers.google.com/android/reference/com/google/android/gms/…
    • 什么是'mLocationCallback'?我在变量框内找不到它
    • @DanielNugent 很好的答案和解释
    【解决方案2】:
     mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
                currentLocation = locationResult.getLastLocation();
    
            }
        };
    

    这对我有用。

    【讨论】:

    • 这是什么?放在哪里?
    【解决方案3】:

    获取当前位置。使用下面的代码。

     if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            //Please allow Location Permission
            return;
        }
       
        FusedLocationProviderClient fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
        fusedLocationProviderClient.getCurrentLocation(PRIORITY_HIGH_ACCURACY, new CancellationToken() {
            @Override
            public boolean isCancellationRequested() {
                return false;
            }
    
            @NonNull
            @Override
            public CancellationToken onCanceledRequested(@NonNull OnTokenCanceledListener onTokenCanceledListener) {
                return null;
            }
        }).addOnSuccessListener(location -> {
            currentLocation = location;
            // use this current location
        });
    

    【讨论】:

      【解决方案4】:
          private LocationRequest locationRequest;
      
          public class MapsActivity extends FragmentActivity implements LocationListener{
      
          locationRequest = new LocationRequest();
          locationRequest.setInterval(60 * 1000);
          locationRequest.setFastestInterval(15 * 1000);
          locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
      
      
      @Override
      public void onLocationChanged(Location location) {
      
          latitude = location.getLatitude();
          longitude = location.getLongitude();
      
      }
      

      实现位置更改侦听器,您将能够覆盖 onlocation changed...

      【讨论】:

        【解决方案5】:

        为了简单起见,请尝试使用此库 https://github.com/mrmans0n/smart-location-lib。这将使用 Fused Location Provider。

        你只需输入这段代码

        SmartLocation.with(context).location(new LocationBasedOnActivityProvider(callback))
            .start(new OnLocationUpdatedListener() { ... });
        

        【讨论】:

          猜你喜欢
          • 2021-02-01
          • 2022-10-18
          • 2017-01-22
          • 2019-10-05
          • 2018-06-08
          • 1970-01-01
          • 2018-12-19
          相关资源
          最近更新 更多