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

Android中点击Button通过Geofire向Firebase上传位置的代码问题求解

现有代码问题梳理
  • 缺少动态位置权限申请逻辑,未获得权限无法获取用户位置
  • 没有实现位置获取逻辑,代码中直接调用的location变量未初始化,运行会崩溃
  • 覆盖场景不全:仅在用户手动开启GPS后触发上传,若用户之前已经打开GPS,不会执行位置上传逻辑
  • onActivityResult中case未加break,会出现逻辑穿透,执行完RESULT_OK的代码后还会执行RESULT_CANCELED的提示
  • GeoFire存储路径重复:已经获取Location根节点后重复调用child("Location"),会生成多余的嵌套路径
代码修改方案

1. 先添加AndroidManifest权限声明

<!-- 基础位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 安卓10及以上后台位置权限(如果需要后台上传的话加) -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

2. 修改Activity代码

首先在Activity全局声明变量:

// 位置服务客户端
private FusedLocationProviderClient fusedLocationClient;
// 位置更新回调
private LocationCallback locationCallback;
// 权限请求码
private static final int LOCATION_PERMISSION_CODE = 100;

然后修改onCreate中的点击事件逻辑,增加权限校验、位置获取逻辑:

sendLocation = findViewById(R.id.sendButton);
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
// 初始化位置回调
locationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(@NonNull LocationResult locationResult) {
        super.onLocationResult(locationResult);
        if (locationResult == null) return;
        Location location = locationResult.getLastLocation();
        // 上传位置到Geofire
        uploadLocationToGeoFire(location);
        // 如果只需要单次上传,拿到位置后就停止更新
        fusedLocationClient.removeLocationUpdates(locationCallback);
    }
};

sendLocation.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 先校验位置权限
        if (ContextCompat.checkSelfPermission(SendLocation.this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            // 没有权限就申请权限
            ActivityCompat.requestPermissions(SendLocation.this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    LOCATION_PERMISSION_CODE);
            return;
        }

        locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(5000);
        locationRequest.setFastestInterval(2000);

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest);
        builder.setAlwaysShow(true);

        Task<LocationSettingsResponse> result = LocationServices.getSettingsClient(getApplicationContext())
                .checkLocationSettings(builder.build());

        result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
            @Override
            public void onComplete(@NonNull Task<LocationSettingsResponse> task) {
                try {
                    LocationSettingsResponse response = task.getResult(ApiException.class);
                    // GPS已经开启,直接获取位置
                    getCurrentLocation();
                    Toast.makeText(SendLocation.this, "GPS已开启", Toast.LENGTH_SHORT).show();
                } catch (ApiException e) {
                    switch (e.getStatusCode()) {
                        case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                            try {
                                ResolvableApiException resolvableApiException = (ResolvableApiException)e;
                                resolvableApiException.startResolutionForResult(SendLocation.this,REQUEST_CHECK_SETTINGS);
                            } catch (IntentSender.SendIntentException ex) {
                                ex.printStackTrace();
                            }
                            break;
                        case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                            Toast.makeText(SendLocation.this, "设备不支持位置功能", Toast.LENGTH_SHORT).show();
                            break;
                    }
                }
            }
        });
    }
});

新增权限申请回调、获取位置方法、上传位置方法:

// 权限申请结果回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == LOCATION_PERMISSION_CODE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 权限通过,触发点击事件逻辑
            sendLocation.performClick();
        } else {
            Toast.makeText(this, "需要位置权限才能上传位置", Toast.LENGTH_SHORT).show();
        }
    }
}

// 获取当前位置
private void getCurrentLocation() {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    // 先尝试拿最后一次缓存的位置,如果有就直接上传
    fusedLocationClient.getLastLocation().addOnSuccessListener(location -> {
        if (location != null) {
            uploadLocationToGeoFire(location);
        } else {
            // 没有缓存位置就请求实时更新
            fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
        }
    });
}

// 上传位置到Geofire
private void uploadLocationToGeoFire(Location location) {
    DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Location");
    GeoFire geoFire = new GeoFire(reference.child(phoneNum.getUid()));
    geoFire.setLocation("location", new GeoLocation(location.getLatitude(), location.getLongitude()), (key, error) -> {
        if (error == null) {
            Toast.makeText(SendLocation.this, "位置上传成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(SendLocation.this, "位置上传失败:" + error.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

修改onActivityResult,添加break修复逻辑穿透:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CHECK_SETTINGS) {
        switch (resultCode) {
            case Activity.RESULT_OK:
                // 用户同意开启GPS,获取位置上传
                getCurrentLocation();
                Toast.makeText(this, "GPS已开启", Toast.LENGTH_SHORT).show();
                break; // 必须加break,否则会穿透到下一个case
            case Activity.RESULT_CANCELED:
                Toast.makeText(this, "需要开启GPS功能", Toast.LENGTH_SHORT).show();
                break;
        }
    }
}
其他实现方式
  • 单次定位上传:如果不需要持续获取位置,可以不用设置位置更新回调,直接使用fusedLocationClient.getCurrentLocation()方法获取一次位置即可,代码更简洁
  • 定期上传位置:使用WorkManager启动定时任务,在后台持续同步位置到Firebase,适合需要实时位置同步的场景,不会因为Activity关闭就停止
  • 直接使用Firestore存储位置:Firestore原生支持GeoPoint类型,自带地理范围查询能力,不需要额外集成Geofire库,维护成本更低
  • 前台服务绑定位置更新:如果需要长时间持续获取位置,使用前台服务可以降低被系统回收的概率,稳定性更高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 13:36:05