繁体   English   中英

在我使用 Fused Location Client 的 android 应用程序中,为什么在使用此代码时会出现过时的 GPS

[英]In my android app using Fused Location Client, Why am I getting stale GPS when using this code

我的应用程序显示导航图表,如果当前 GPS 位置可用,它也会显示。 我在一艘沿着已知路线移动的船上进行了测试。 有时会显示正确的位置。 有时我会得到一个旧的 GPS 位置,即使在要求重新阅读时也是如此。 有时它似乎卡在旧位置进行多次读取。 当这种情况发生时,我运行了谷歌地图,它似乎清除了错误,我又开始获得一个新的位置。

// try to look at GPS....
        status1 = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
        if (status1 != PackageManager.PERMISSION_GRANTED)
        {   requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},10);
        }
        status2 = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
        Object cancellationToken = null;
        if (status2 == PackageManager.PERMISSION_GRANTED)
            fusedLocationClient.getCurrentLocation(PRIORITY_HIGH_ACCURACY, (CancellationToken) cancellationToken)
                    .addOnSuccessListener(this, location -> // using lambda expression...

                    {   if (location != null)
                    {   GPSLatitude = location.getLatitude();
                        GPSLongitude = location.getLongitude();
                        gotGPS = true;
                        //if we have a location, and it is on chart, draw the blue dot....

谷歌地图比我更擅长阅读 GPS。 我是否应该考虑另一种方法。

欢迎来到遭受谷歌FusedLocationProvider之手的人的FusedLocationProvider ,我建议您改用带有 GPS 提供程序的LocationManager 可用于在您的Activity请求位置作为

fun getLocation() {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
        ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
         // do proper permissions handling
         return
    }
    val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
    val gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
    if (gpsEnabled) {
        // Register for location updates
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0.0f, locationListener)
            
        // Or get last known location
        val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
    }
}

private val locationListener = LocationListener {
        // Do something with the location
}

有时FusedLocationProvider可以提供不准确的位置

在某些情况下,我发现FusedLocationProvider相当不准确,在最近的一次与您没有什么不同的经历中,我无法在我的应用程序中使用FusedLocationProvider获得 GPS 锁定,当我打开谷歌地图时,GPS 锁定销立即出现。 所以我做了一些研究,果然我发现了FusedLocationProvider的错误,我最终使用了LocationManger ,至于为什么它会这样表现,我遇到的一些问题是

  1. 它的Fused ,这意味着它使用多个来源(WiFi、网络、GPS 等),它将选择它认为合适的一个,或者在决定位置时选择所有来源
  2. FusedLocationProvider的最大卖点是它针对电池使用进行了优化,因此只要它可以为您提供位置(通常是准确的,并非总是如此),如果它确定调用会给您带来不必要的负载,它就不会影响硬件电池
  3. 它似乎也在做位置缓存,这可能是位置修复过时的原因, 在这个问题的评论中,用户分享了他们在这种情况下的经验

一些由FusedLocationProvider引起的问题的链接

FusedLocationProvider如何影响早期使用LocationManger的数据收集应用程序的位置准确性

FusedLocationProvider由于缓存而导致问题

为什么LocationManager提供更准确的位置

FusedLocationProvider在某些情况下如何表现不佳

FusedLocationProvider如何提供不准确的结果,请参阅投票第二高的答案

问题是您没有对跟踪资产位置的应用程序使用推荐的方法。 并且您已尝试通过getCurrentLocation方法手动更新位置。 事实上,当您不需要不断更新位置时,将使用getCurrentLocation方法。 例如,您只需要一个用户的新位置,用于注册、附近搜索等。

当您需要不断跟踪资产时,您应该通过requestLocationUpdates方法监听位置更新。 根据官方推荐

适当使用位置信息对您的应用程序用户有益。 例如,如果您的应用帮助用户在步行或开车时找到方向,或者您的应用跟踪资产位置,则需要定期获取设备的位置。

在这里我实现了一个完整的例子

package com.example.locationtracker;

import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.Looper;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.example.locationtracker.databinding.ActivityMainBinding;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.material.snackbar.Snackbar;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {


    private boolean isTracking = false;
    private FusedLocationProviderClient fusedLocationClient;
    private LocationCallback locationCallback;
    private LocationRequest locationRequest;
    private LocationRecycleViewAdapter locationRecycleViewAdapter;
    private final ArrayList<String> locations = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        com.example.locationtracker.databinding.ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        binding.location.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
        locationRecycleViewAdapter = new LocationRecycleViewAdapter(getApplicationContext(), locations);
        binding.location.setAdapter(locationRecycleViewAdapter);
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(12000);
        locationRequest.setFastestInterval(2000);
        locationRequest.setWaitForAccurateLocation(true);
        locationRequest.setSmallestDisplacement(0);

        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                for (Location location : locationResult.getLocations()) {
                    System.out.println("New Location Received");
                    String loc = String.format("lat: %s, lon: %s", location.getLatitude(), location.getLongitude());
                    locations.add(loc);
                    locationRecycleViewAdapter.notifyDataSetChanged();
                    /*locationRecycleViewAdapter = new LocationRecycleViewAdapter(getApplicationContext(), locations);
                    binding.location.setAdapter(locationRecycleViewAdapter);*/
                }
            }
        };
        binding.fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!isTracking) {
                    Snackbar.make(view, "Starting Location Tracking", Snackbar.LENGTH_LONG)
                            .show();
                    startLocationUpdates();

                } else {
                    Snackbar.make(view, "Stopping Location Tracking", Snackbar.LENGTH_LONG)
                            .show();
                    stopLocationUpdates();
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (isTracking) {
            startLocationUpdates();
        }
    }

    private static final int PERMISSION_REQUEST_CODE = 200;

    private void startLocationUpdates() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_CODE);
            return;
        }
        fusedLocationClient.requestLocationUpdates(locationRequest,
                locationCallback,
                Looper.getMainLooper());
        isTracking = true;
    }

    private void stopLocationUpdates() {
        fusedLocationClient.removeLocationUpdates(locationCallback);
        isTracking = false;
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.locationtracker">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.LocationTracker">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.LocationTracker.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

输出

在此处输入图片说明

重要笔记

确保您同时拥有FINECOARSE位置权限

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

如果您想以最快的时间间隔检索资产的位置,则COARSE LocationPRIORITY_HIGH_ACCURACY非常重要 以下设置也非常重要。

locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(12000);
locationRequest.setFastestInterval(2000);
locationRequest.setWaitForAccurateLocation(true);
locationRequest.setSmallestDisplacement(0); 

我建议尝试以间隔更新当前

        if (ActivityCompat.checkSelfPermission(mActivity, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0, new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
             log.w("Get locations:: "+ location.getLatitude());
                newLocation(location);
//                locationManager.removeUpdates(this);
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {

            }

            @Override
            public void onProviderEnabled(String provider) {

            }

            @Override
            public void onProviderDisabled(String provider) {

            }
        });

这是我现在正在使用的 Java 代码。

locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);


// try to look at GPS....
        status1 = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
        if (status1 != PackageManager.PERMISSION_GRANTED)
        {   requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},10);
        }
        status2 = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
        if (status2 == PackageManager.PERMISSION_GRANTED)
        {   gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            if (gpsEnabled) // Register for location updates, each minute (60,000 milliseconds)
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0.0f, locationListenerGPS);
LocationListener locationListenerGPS=new LocationListener() {
        @Override
        public void onLocationChanged(android.location.Location location) {
            GPSLatitude = location.getLatitude();
            GPSLongitude = location.getLongitude();
            gotGPS = true;

            reDraw();

            //String msg="New Latitude: "+latitude + "New Longitude: "+longitude;
            //Toast.makeText(mContext,msg,Toast.LENGTH_LONG).show();
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    };
///

based on Kotlin code from WOZ, it works well 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM