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

2021年如何使用FusedLocationProviderClient快速单次获取设备位置

安卓单次快速定位优化方案

现有代码核心问题

  • 调用requestLocationUpdates()后立刻执行removeLocationUpdates(),等于直接取消了定位请求,新的定位结果根本没机会返回,只能等用户多次点击重试,这是耗时久的核心原因
  • 不必要的flushLocations()调用会清空已有定位缓存,反而会增加获取位置的等待时间
  • 定位成功后的地址解析(Geocoder)直接在主线程执行,可能引发卡顿
  • TextWatcher的afterTextChanged回调中直接写入Firebase,只要文本发生变化就会触发,会出现多次无效提交,甚至可能写入空的经纬度
  • 网络状态判断使用的getNetworkInfoAPI在Android 9及以上版本已经废弃,判断结果不准确

优化实现方案

1. 全局变量补充

首先在Activity中新增两个全局变量,保存定位回调和请求对象:

private LocationCallback locationCallback;
private LocationRequest locationRequest;

2. 改造getCurrentLocation()方法

@SuppressLint("MissingPermission")
private void getCurrentLocation() {
    // 先获取缓存位置,有结果直接用
    fusedLocationProviderClient.getLastLocation().addOnCompleteListener(task -> {
        if (task.isSuccessful() && task.getResult() != null) {
            Location location = task.getResult();
            handleLocationResult(location);
            return;
        }
        // 缓存为空,请求单次新鲜定位
        locationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setNumUpdates(1) // 只请求一次定位
                .setInterval(0)
                .setFastestInterval(0);
        
        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                super.onLocationResult(locationResult);
                Location newLocation = locationResult.getLastLocation();
                if (newLocation != null) {
                    handleLocationResult(newLocation);
                    // 拿到结果后立刻移除回调,避免多余消耗
                    fusedLocationProviderClient.removeLocationUpdates(this);
                }
            }
        };
        fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
        Toast.makeText(getApplicationContext(), "正在获取位置,请稍候", Toast.LENGTH_SHORT).show();
    });
}

3. 新增定位结果处理方法,地址解析放子线程

private void handleLocationResult(Location location) {
    BuyerLatitude = String.valueOf(location.getLatitude());
    BuyerLongitude = String.valueOf(location.getLongitude());
    // 地址解析放子线程执行,避免阻塞主线程
    new Thread(() -> {
        Geocoder geocoder = new Geocoder(BuyerAreaFinderActivity.this, Locale.getDefault());
        try {
            List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
            if (addresses != null && !addresses.isEmpty()) {
                String address = addresses.get(0).getAddressLine(0);
                // 切回主线程更新UI
                runOnUiThread(() -> {
                    BuyerArea.setText(address);
                    BuyerAreaFetchBtn.setVisibility(View.INVISIBLE);
                    // 拿到正确结果后直接写入Firebase,删除原来的TextWatcher监听逻辑
                    saveLocationToFirebase();
                });
            }
        } catch (IOException e) {
            e.printStackTrace();
            // 地址解析失败直接用经纬度显示
            runOnUiThread(() -> {
                BuyerArea.setText("纬度:" + BuyerLatitude + ",经度:" + BuyerLongitude);
                BuyerAreaFetchBtn.setVisibility(View.INVISIBLE);
                saveLocationToFirebase();
            });
        }
    }).start();
}

4. 新增Firebase写入方法

private void saveLocationToFirebase() {
    HashMap<String, Object> buyerLocationMap = new HashMap<>();
    buyerLocationMap.put("buyerLatitude", BuyerLatitude);
    buyerLocationMap.put("buyerLongitude", BuyerLongitude);
    RootRef.child("Users").child(currentUserId).updateChildren(buyerLocationMap)
            .addOnCompleteListener(task -> {
                if (task.isSuccessful()) {
                    continueBtn.setVisibility(View.VISIBLE);
                    continueBtn.setEnabled(true);
                } else {
                    String ErrorMessage = task.getException().toString();
                    Toast.makeText(BuyerAreaFinderActivity.this, "Error : " + ErrorMessage, Toast.LENGTH_SHORT).show();
                }
            });
}

5. 其他优化点

  • 删除BuyerArea的TextChangedListener监听,避免重复提交
  • 删除getCurrentLocation()方法中的fusedLocationProviderClient.flushLocations()调用
  • 网络判断如果适配Android 10以上,可以替换为ConnectivityManager.NetworkCallback实现,适配更高系统版本
  • Activity销毁时如果还没拿到定位结果,主动移除回调避免内存泄漏:
@Override
protected void onDestroy() {
    super.onDestroy();
    if (fusedLocationProviderClient != null && locationCallback != null) {
        fusedLocationProviderClient.removeLocationUpdates(locationCallback);
    }
}

优化后首次获取定位的耗时可以控制在3秒以内,刚开启定位开关的场景也不会出现长时间等待的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 07:45:04