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

使用Fused Location请求位置更新时应用崩溃

排查开关点击触发位置更新崩溃的问题

这种没有IDE报错但运行时崩溃的情况确实头疼,咱们一步步拆解排查:

第一步:先拿到崩溃的具体信息

Android Studio没弹出错误提示不代表没有崩溃日志,你得打开Logcat窗口,过滤Error级别,找到崩溃时的堆栈信息(比如NullPointerException、SecurityException这类),这是定位问题的核心——比如权限被拒会抛出SecurityException,GoogleApiClient未就绪会抛出IllegalStateException。

第二步:修正GoogleApiClient的连接判断逻辑

你提到尝试了判断连接状态,但大概率是判断逻辑有漏洞:

  • 别只在点击事件里临时调用googleApiClient.isConnected(),因为GoogleApiClient的连接是异步的,点击开关时可能还处于CONNECTING状态,此时调用位置更新会直接崩溃。
  • 正确的做法是:
    1. 在Activity/Fragment里实现GoogleApiClient.ConnectionCallbacks和GoogleApiClient.OnConnectionFailedListener接口。
    2. 在onConnected(Bundle bundle)回调里标记一个isGoogleApiConnected = true的状态变量。
    3. 开关点击时先检查这个状态变量,只有连接完全就绪后再执行更新请求。
    4. 同时处理onConnectionFailed的情况,比如弹窗提示用户无法连接Google服务。

示例代码片段:

private GoogleApiClient googleApiClient;
private boolean isGoogleApiConnected = false;

// 初始化GoogleApiClient
private void initGoogleApiClient() {
    googleApiClient = new GoogleApiClient.Builder(this)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
    googleApiClient.connect();
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    isGoogleApiConnected = true;
    Log.d("Location", "GoogleApiClient已连接");
}

@Override
public void onConnectionSuspended(int i) {
    isGoogleApiConnected = false;
    googleApiClient.connect(); // 断开后自动重连
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    isGoogleApiConnected = false;
    Toast.makeText(this, "Google服务连接失败,请检查网络", Toast.LENGTH_SHORT).show();
}

// 开关点击事件
switchButton.setOnClickListener(v -> {
    if (switchButton.isChecked()) {
        if (!hasLocationPermission()) {
            // 先处理权限,后面会讲
            return;
        }
        if (isGoogleApiConnected) {
            // 安全调用位置更新
            LocationServices.FusedLocationApi.requestLocationUpdates(
                    googleApiClient, locationRequest, locationListener);
        } else {
            Toast.makeText(this, "Google服务未就绪,请稍后重试", Toast.LENGTH_SHORT).show();
            if (!googleApiClient.isConnecting()) {
                googleApiClient.connect();
            }
        }
    } else {
        // 关闭位置更新
        if (isGoogleApiConnected) {
            LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, locationListener);
        }
    }
});

第三步:检查动态权限是否正确申请

你虽然在Manifest里加了权限,但Android 6.0(API 23)及以上系统需要动态申请位置权限,如果用户拒绝权限,调用requestLocationUpdates会触发SecurityException崩溃:

  • 先在点击事件前检查权限:
// 检查位置权限的工具方法
private boolean hasLocationPermission() {
    return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED
            && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
            == PackageManager.PERMISSION_GRANTED;
}

// 在点击事件里先校验权限
switchButton.setOnClickListener(v -> {
    if (switchButton.isChecked()) {
        if (!hasLocationPermission()) {
            // 申请权限
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION},
                    1001);
            return;
        }
        // 再检查GoogleApi连接状态,执行更新请求
    } else {
        // 关闭更新逻辑
    }
});

// 处理权限申请结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1001) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 权限通过,再次尝试开启位置更新
            if (switchButton.isChecked() && isGoogleApiConnected) {
                LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, locationListener);
            }
        } else {
            Toast.makeText(this, "需要位置权限才能获取位置信息", Toast.LENGTH_SHORT).show();
            switchButton.setChecked(false);
        }
    }
}

第四步:确认LocationListener是否正确初始化

确保你的locationListener不是null,并且完整实现了必要方法:

private LocationListener locationListener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
        // 处理位置更新,别在这里做耗时操作
        Log.d("Location", "获取到位置:" + location.getLatitude() + ", " + location.getLongitude());
    }

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

    @Override
    public void onProviderEnabled(String provider) {}

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

第五步:考虑迁移到新的FusedLocationProviderClient

LocationServices.FusedLocationApi已经被Google废弃(从Play Services 11.0开始),推荐使用更简洁稳定的FusedLocationProviderClient:
示例代码:

private FusedLocationProviderClient fusedLocationClient;
private LocationRequest locationRequest;
private LocationCallback locationCallback;

// 初始化新的位置客户端
private void initLocationClient() {
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    locationRequest = LocationRequest.create();
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(5000); // 5秒更新一次

    locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult == null) return;
            for (Location location : locationResult.getLocations()) {
                Log.d("Location", "新API获取位置:" + location.getLatitude());
            }
        }
    };
}

// 开关点击事件
switchButton.setOnClickListener(v -> {
    if (switchButton.isChecked()) {
        if (!hasLocationPermission()) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    1001);
            return;
        }
        try {
            fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
            Toast.makeText(this, "已开启位置更新", Toast.LENGTH_SHORT).show();
        } catch (SecurityException e) {
            e.printStackTrace();
            Toast.makeText(this, "权限不足无法获取位置", Toast.LENGTH_SHORT).show();
        }
    } else {
        fusedLocationClient.removeLocationUpdates(locationCallback);
        Toast.makeText(this, "已关闭位置更新", Toast.LENGTH_SHORT).show();
    }
});

最后再强调一遍:先看Logcat的崩溃日志,这能帮你直接锁定问题根源,比盲目试错高效得多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:15:57