android LocationManager 部分设备无法获取定位信息怎么办?

目前采用LocationManager 的方式获取定位,在部分设备上(比如Redmi K30, MIUI 13.0.6)授权+开启了GPS的情况下会获取不到定位信息,其他设备都正常,但这导致我小米应用市场无法上架应用。

请问主流的获取GPS定位的方式是怎样的?该如何解决上述部分设备获取不到定位的问题?

我GPS定位的代码如下(核心思路是遍历定位提供者,网络、GPS等受支持的提供者,监听位置变化,间隔2秒获取一次定位信息,获取不到反复5次,之后失败。期间获取到就成功):

    @SuppressLint("MissingPermission")
    private static CompletableFuture<Location> requestLocation(Activity activity) {
        CompletableFuture<Location> future = new CompletableFuture<>();
        future.exceptionally(throwable -> {
            LogUtil.throwException(throwable, true, activity);
            return null;
        });
        LocationManager locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
        List<String> providers = locationManager.getProviders(true);
        AtomicReference<Location> bestLocationAtomic = new AtomicReference<>();
        LocationListener locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(@NonNull Location location) {
                Location bestLocation = bestLocationAtomic.get();
                // getAccacy - 返回精确度(误差范围,以米为单位,值越小越精确)
                if (bestLocation == null || location.getAccuracy() < bestLocation.getAccuracy()) {
                    // 如果当前位置更准确,则使用当前位置
                    bestLocationAtomic.set(location);
                }
                // 当获取到为止变更的时候移除位置监听器
                locationManager.removeUpdates(this);
            }
            /**
             * ************************************************
             * api level 24 设备需要实现这个方法 否则会报错
             * ************************************************
             */
            @Deprecated
            @Override
            @SuppressWarnings("deprecation")
            public void onStatusChanged(String provider, int status, Bundle extras) {

            }

            @Override
            public void onProviderDisabled(@NonNull String provider) {

            }

            @Override
            public void onProviderEnabled(@NonNull String provider) {
                
            }
        };
        for (String provider : providers) {
            /*
              locationManager.requestLocationUpdates(provider, 0, 0, locationListener)是用于注册位置监听器的方法。它有四个参数:
              provider:要注册监听器的位置提供者。可以是LocationManager.GPS_PROVIDER、LocationManager.NETWORK_PROVIDER等。
              minTime:位置更新的最小时间间隔(以毫秒为单位)。设置为0表示尽可能频繁地接收位置更新。
              minDistance:位置更新的最小距离间隔(以米为单位)。设置为0表示无论移动多远都接收位置更新。
              locationListener:位置监听器对象,用于接收位置更新的回调。
             */
            locationManager.requestLocationUpdates(provider, 0, 0, locationListener);
        }
        // 等待两秒
        getResult(bestLocationAtomic, future, 0);
        return future;
    }

    private static void getResult(AtomicReference<Location> locationAtomic, CompletableFuture<Location> future, int retryCount) {
        ThreadCommon.delay(() -> {
            Location location = locationAtomic.get();
            if (location == null && retryCount < 10) {
                getResult(locationAtomic, future, retryCount + 1);
            } else {
                ThreadCommon.runOnUiThread(() -> future.complete(location));
            }
        }, 1000);
    }
阅读 530
1 个回答

我将你的代码进行了优化,结合了AGPS和网络定位,并增加了权限检查。以下是修复后的代码:

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

public class LocationUtil {

    private static final int REQUEST_LOCATION_PERMISSION = 1;

    @SuppressLint("MissingPermission")
    public static CompletableFuture<Location> requestLocation(Activity activity) {
        CompletableFuture<Location> future = new CompletableFuture<>();
        future.exceptionally(throwable -> {
            LogUtil.throwException(throwable, true, activity);
            return null;
        });

        if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
            return future;
        }

        LocationManager locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
        List<String> providers = locationManager.getProviders(true);
        AtomicReference<Location> bestLocationAtomic = new AtomicReference<>();
        LocationListener locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(@NonNull Location location) {
                Location bestLocation = bestLocationAtomic.get();
                if (bestLocation == null || location.getAccuracy() < bestLocation.getAccuracy()) {
                    bestLocationAtomic.set(location);
                }
                locationManager.removeUpdates(this);
            }

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

            @Override
            public void onProviderDisabled(@NonNull String provider) {}

            @Override
            public void onProviderEnabled(@NonNull String provider) {}
        };

        for (String provider : providers) {
            locationManager.requestLocationUpdates(provider, 5000, 10, locationListener);
        }

        getResult(bestLocationAtomic, future, 0);
        return future;
    }

    private static void getResult(AtomicReference<Location> locationAtomic, CompletableFuture<Location> future, int retryCount) {
        ThreadCommon.delay(() -> {
            Location location = locationAtomic.get();
            if (location == null && retryCount < 10) {
                getResult(locationAtomic, future, retryCount + 1);
            } else {
                ThreadCommon.runOnUiThread(() -> future.complete(location));
            }
        }, 1000);
    }
}

主要改动

1.权限检查:在请求定位之前,检查并请求必要的权限。
2.使用AGPS和网络定位:在遍历提供者时,增加了网络定位的支持。
3.优化定位参数:增加了定位更新的时间间隔和距离间隔,以减少设备负担并提高定位成功率。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏