使用Fused Location请求位置更新时应用崩溃
排查开关点击触发位置更新崩溃的问题
这种没有IDE报错但运行时崩溃的情况确实头疼,咱们一步步拆解排查:
第一步:先拿到崩溃的具体信息
Android Studio没弹出错误提示不代表没有崩溃日志,你得打开Logcat窗口,过滤Error级别,找到崩溃时的堆栈信息(比如NullPointerException、SecurityException这类),这是定位问题的核心——比如权限被拒会抛出SecurityException,GoogleApiClient未就绪会抛出IllegalStateException。
第二步:修正GoogleApiClient的连接判断逻辑
你提到尝试了判断连接状态,但大概率是判断逻辑有漏洞:
- 别只在点击事件里临时调用
googleApiClient.isConnected(),因为GoogleApiClient的连接是异步的,点击开关时可能还处于CONNECTING状态,此时调用位置更新会直接崩溃。 - 正确的做法是:
- 在Activity/Fragment里实现
GoogleApiClient.ConnectionCallbacks和GoogleApiClient.OnConnectionFailedListener接口。 - 在
onConnected(Bundle bundle)回调里标记一个isGoogleApiConnected = true的状态变量。 - 开关点击时先检查这个状态变量,只有连接完全就绪后再执行更新请求。
- 同时处理
onConnectionFailed的情况,比如弹窗提示用户无法连接Google服务。
- 在Activity/Fragment里实现
示例代码片段:
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
相关产品推荐
相关产品推荐

