You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:如何为FusedLocationClient的requestLocationUpdates添加位置回调?

解决Android 5.1下LocationUpdatesPendingIntent无GPS时无法获取位置及添加获取状态回调的问题

嘿,我刚好碰到过类似的Android版本差异问题!先给你拆解下根源:Android 6.0+的定位框架会自动在GPS不可用时 fallback 到网络定位,但5.1及更早的系统,如果你没明确配置定位优先级,默认可能只依赖GPS提供者。加上你用的是PendingIntent方式接收位置更新,默认没有直接的回调来判断是否获取到有效位置,所以得从两方面入手:适配5.1的定位策略 + 添加自定义回调来检查位置有效性。

下面是一步步的具体实现方案:

1. 先修正LocationRequest的配置,让5.1支持网络定位

首先要确保你的LocationRequest允许使用网络定位,而不是只盯着GPS。把优先级设置为PRIORITY_BALANCED_POWER_ACCURACY或者PRIORITY_LOW_POWER,这样系统会自动尝试网络定位(只要设备开启了网络定位选项):

private void buildLocationRequest() {
    mLocationRequest = LocationRequest.create();
    // 关键:设置支持网络定位的优先级,适配5.1
    mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    mLocationRequest.setInterval(10000); // 10秒一次更新,按需调整
    mLocationRequest.setFastestInterval(5000); // 最快更新间隔
    mLocationRequest.setSmallestDisplacement(10); // 最小位移触发更新,按需调整
}

2. 添加自定义回调接口,监听位置获取状态

我们需要定义一个回调接口,用来通知调用者位置是否成功获取:

public interface LocationUpdateCallback {
    // 获取到有效位置时回调
    void onLocationReceived(Location location);
    // 获取失败时回调(比如位置为空、权限不足等)
    void onLocationFailed(String errorMessage);
}

3. 改造广播接收器,检查位置有效性并触发回调

因为你用的是PendingIntent接收位置更新,所以核心逻辑要放在自定义的BroadcastReceiver里,在这里检查返回的Location是否有效,并触发我们的回调:

public class LocationUpdatesReceiver extends BroadcastReceiver {
    private static final String TAG = "LocationUpdatesReceiver";
    private LocationUpdateCallback mCallback;

    // 构造时传入回调实例
    public LocationUpdatesReceiver(LocationUpdateCallback callback) {
        mCallback = callback;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (LocationResult.hasResult(intent)) {
            LocationResult result = LocationResult.extractResult(intent);
            if (result == null) {
                mCallback.onLocationFailed("位置结果为空");
                return;
            }

            Location location = result.getLastLocation();
            // 检查经纬度是否有效(避免0,0的默认无效值)
            if (location != null && location.getLatitude() != 0.0 && location.getLongitude() != 0.0) {
                mCallback.onLocationReceived(location);
            } else {
                mCallback.onLocationFailed("未获取到有效位置,请检查定位设置");
            }
        } else {
            // 处理定位提供者状态变化(比如用户关闭了所有定位)
            if (LocationManager.PROVIDERS_CHANGED_ACTION.equals(intent.getAction())) {
                LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
                boolean hasValidProvider = lm.isProviderEnabled(LocationManager.GPS_PROVIDER) 
                        || lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
                if (!hasValidProvider) {
                    mCallback.onLocationFailed("所有定位提供者均已禁用");
                }
            }
        }
    }
}

4. 在发起位置请求时添加回调,同时适配权限和设置检查

现在在你的Activity/Service中,初始化回调、注册广播,并发起位置请求,同时添加请求本身的成功/失败监听:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final int REQUEST_CHECK_SETTINGS = 1001;
    private static final String ACTION_LOCATION_UPDATES = "com.your.package.ACTION_LOCATION_UPDATES";

    private FusedLocationProviderClient mFusedLocationClient;
    private LocationRequest mLocationRequest;
    private LocationUpdatesReceiver mReceiver;

    // 初始化自定义回调
    private LocationUpdateCallback mLocationCallback = new LocationUpdateCallback() {
        @Override
        public void onLocationReceived(Location location) {
            Log.d(TAG, "成功获取位置:" + location.getLatitude() + ", " + location.getLongitude());
            // 在这里处理你的位置逻辑
        }

        @Override
        public void onLocationFailed(String errorMessage) {
            Log.e(TAG, "位置获取失败:" + errorMessage);
            // 可以在这里给用户弹提示,比如引导开启定位
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化广播接收器并注册
        mReceiver = new LocationUpdatesReceiver(mLocationCallback);
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_LOCATION_UPDATES);
        filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
        registerReceiver(mReceiver, filter);

        // 初始化FusedLocationClient和LocationRequest
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        buildLocationRequest();

        // 先检查定位设置是否满足要求,再发起请求
        checkLocationSettings();
    }

    // 检查定位设置,引导用户开启必要的定位提供者
    private void checkLocationSettings() {
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(mLocationRequest);
        SettingsClient settingsClient = LocationServices.getSettingsClient(this);
        Task<LocationSettingsResponse> task = settingsClient.checkLocationSettings(builder.build());

        task.addOnSuccessListener(this, response -> {
            // 定位设置满足,发起位置请求
            requestLocationUpdates();
        });

        task.addOnFailureListener(this, e -> {
            int statusCode = ((ApiException) e).getStatusCode();
            if (statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) {
                // 需要用户调整定位设置,弹出系统设置页面
                try {
                    ResolvableApiException resolvable = (ResolvableApiException) e;
                    resolvable.startResolutionForResult(this, REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException sendEx) {
                    mLocationCallback.onLocationFailed("无法打开定位设置页面");
                }
            } else if (statusCode == LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE) {
                mLocationCallback.onLocationFailed("设备不支持所需的定位设置");
            }
        });
    }

    // 发起位置请求,并添加请求状态监听
    private void requestLocationUpdates() {
        try {
            Intent intent = new Intent(ACTION_LOCATION_UPDATES);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    this,
                    0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
            );

            // 发起请求,同时监听请求是否成功提交
            mFusedLocationClient.requestLocationUpdates(mLocationRequest, pendingIntent)
                    .addOnSuccessListener(v -> Log.d(TAG, "位置更新请求已成功发起"))
                    .addOnFailureListener(e -> {
                        Log.e(TAG, "发起位置请求失败:" + e.getMessage());
                        mLocationCallback.onLocationFailed("发起请求失败:" + e.getMessage());
                    });
        } catch (SecurityException e) {
            e.printStackTrace();
            mLocationCallback.onLocationFailed("缺少定位权限,请先授权");
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CHECK_SETTINGS) {
            if (resultCode == RESULT_OK) {
                // 用户已开启定位设置,重新发起请求
                requestLocationUpdates();
            } else {
                mLocationCallback.onLocationFailed("用户拒绝开启定位设置");
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消位置请求
        if (mFusedLocationClient != null) {
            Intent intent = new Intent(ACTION_LOCATION_UPDATES);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    this,
                    0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
            );
            mFusedLocationClient.removeLocationUpdates(pendingIntent);
        }
        // 注销广播接收器
        unregisterReceiver(mReceiver);
    }

    // 前面定义的buildLocationRequest方法
    private void buildLocationRequest() {
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setSmallestDisplacement(10);
    }
}

5. 别忘了Manifest权限配置

确保在AndroidManifest.xml中添加必要的权限,尤其是5.1需要的网络定位相关权限:

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

最后补充几点

  • 对于Android 5.1,用户必须开启网络定位(不仅仅是GPS)才能在无GPS时获取位置,通过checkLocationSettings方法可以引导用户去开启。
  • 你可以根据需求调整LocationRequest的间隔、位移参数,平衡功耗和更新频率。
  • 如果应用进程被杀后仍要保持位置更新,确保你的PendingIntent是用FLAG_IMMUTABLE(Android 12+)或合适的标志,并且FusedLocationProvider会在进程重启后继续发送广播。

内容的提问来源于stack exchange,提问作者Code Spy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:30:45