LocalBroadcastManager失效:后台定位服务无法获取经纬度问题排查
嘿,我看了你的代码,发现几个关键问题导致无法获取经纬度,咱们一个个来解决:
1. 广播Action不匹配(最致命的问题)
你在MainActivity里注册广播时用了硬编码的"ACTION_LOCATION_BROADCAST",但Service里定义的广播Action是Map.class.getName() + "LocationBroadcast"——这俩字符串完全不一样啊!BroadcastReceiver根本收不到Service发的位置广播,自然不会更新TextView。
修复代码:把MainActivity里的IntentFilter改成用Service的常量:
LocalBroadcastManager.getInstance(this).registerReceiver( bReceiver, new IntentFilter(Map.ACTION_LOCATION_BROADCAST));
2. 动态权限没申请
虽然Service里有权限检查,但如果用户还没授权,onConnected直接就返回了,根本不会请求位置更新。你代码里定义了REQUEST_PERMISSIONS_REQUEST_CODE但没实现申请逻辑,得补上:
添加权限申请代码到MainActivity:
// 检查权限是否已授予 private boolean hasLocationPermission() { return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } // 启动服务前先检查权限 private void prepareStartLocationService() { if (!hasLocationPermission()) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSIONS_REQUEST_CODE); } else { startStep3(); } } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startStep3(); } else { Toast.makeText(this, "需要位置权限才能获取位置信息哦", Toast.LENGTH_SHORT).show(); } } } // 修改onResume方法,先检查权限再启动服务 @Override public void onResume() { super.onResume(); prepareStartLocationService(); ee.setText("Start"); }
还要确保AndroidManifest.xml里加了权限声明:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
3. Service里GoogleApiClient重复初始化
每次Service启动(onStartCommand)你都新建一个GoogleApiClient并连接,这会导致重复连接的问题,甚至可能引发异常。应该把初始化移到onCreate里,启动时只检查连接状态:
修改Service的代码:
@Override public void onCreate() { super.onCreate(); // 只在Service创建时初始化一次 mLocationClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); mLocationRequest.setInterval(10000); mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 只有未连接且未在连接中时才发起连接 if (!mLocationClient.isConnected() && !mLocationClient.isConnecting()) { mLocationClient.connect(); } return START_STICKY; } // 别忘了在销毁Service时断开连接,避免内存泄漏 @Override public void onDestroy() { if (mLocationClient != null && mLocationClient.isConnected()) { LocationServices.FusedLocationApi.removeLocationUpdates(mLocationClient, this); mLocationClient.disconnect(); } super.onDestroy(); }
4. TextView没初始化
你代码里用了dd、cc这些TextView,但没看到你调用findViewById初始化它们!如果没初始化,执行cc.setText时会直接崩溃,自然不会更新文本。
在MainActivity的onCreate里初始化TextView:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_main_activity_layout); // 替换成你的布局文件名 mAuth = FirebaseAuth.getInstance(); mDatabase = FirebaseDatabase.getInstance().getReference(); user = mAuth.getCurrentUser(); // 初始化所有用到的TextView dd = findViewById(R.id.dd); cc = findViewById(R.id.cc); ff = findViewById(R.id.ff); ee = findViewById(R.id.ee); // 注册广播接收器 LocalBroadcastManager.getInstance(this).registerReceiver( bReceiver, new IntentFilter(Map.ACTION_LOCATION_BROADCAST)); }
最后几个检查点
- 确保设备的位置服务已经开启(设置→位置→开启)
- 如果用模拟器测试,要手动设置模拟位置(模拟器侧边栏→位置→输入经纬度)
- 打开Logcat,搜索
Map和MainActivity的TAG,看看有没有Location changed、Sending info...这些日志,判断位置更新是否触发,广播是否正常发送
内容的提问来源于stack exchange,提问作者belllele

