Android中LocationListener的onLocationChange()方法无法触发问题
解决索尼Z3 Compact日版(SO-O2G)定位应用onLocationChange()未触发的问题
嘿,我来帮你搞定这个定位监听不触发的问题!既然谷歌地图能正常定位,说明设备硬件和系统定位服务是没问题的,问题大概率出在你的应用代码的权限处理逻辑上,下面是具体的排查和修复方案:
1. 核心问题:缺少权限请求的回调处理
你在onCreate里发起了动态权限请求,但权限请求是异步操作——用户点击授权的时机可能晚于onStart的执行,这时候onStart里的权限检查会失败,导致requestLocationUpdates根本没被调用。必须添加onRequestPermissionsResult回调方法,在用户完成授权后再初始化定位监听:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 0) { // 只要有一个定位权限被授予,就尝试启动定位监听 boolean hasLocationPermission = false; for (int result : grantResults) { if (result == PackageManager.PERMISSION_GRANTED) { hasLocationPermission = true; break; } } if (hasLocationPermission && locationManager != null) { try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); Toast.makeText(this, "定位监听已启动", Toast.LENGTH_SHORT).show(); } catch (SecurityException e) { Log.e("LocationError", "权限异常: " + e.getMessage()); } } else { Toast.makeText(this, "需要定位权限才能获取位置", Toast.LENGTH_SHORT).show(); } } }
2. 调整权限判断逻辑(过于严格的条件)
你在onStart里的判断要求同时拥有ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限才会启动定位,但实际上ACCESS_FINE_LOCATION已经包含了ACCESS_COARSE_LOCATION的权限范围,只要有其中一个权限就可以正常请求定位更新。修改后的onStart方法:
@Override protected void onStart() { super.onStart(); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (locationManager != null) { // 只要有一个定位权限被授予就执行 boolean hasFinePermission = ContextCompat.checkSelfPermission(this, PERMISSION_ONE) == PackageManager.PERMISSION_GRANTED; boolean hasCoarsePermission = ContextCompat.checkSelfPermission(this, PERMISSION_TWO) == PackageManager.PERMISSION_GRANTED; if (hasFinePermission || hasCoarsePermission) { try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); Log.i("LocationInit", "已启动定位监听"); } catch (SecurityException e) { Log.e("LocationError", "启动监听失败: " + e.getMessage()); } } else { Toast.makeText(this, "权限未授予", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(this, "无法获取定位服务", Toast.LENGTH_SHORT).show(); } periodicallyCheck(); }
3. 额外的排查与验证点
- 检查应用权限设置:进入设备的「设置-应用-你的应用-权限」,确认「位置」权限已经被授予(有时候动态权限请求可能被用户误拒,或者系统默认未开启)。
- 测试环境适配:室内环境下GPS定位可能需要较长时间,你可以先关闭GPS_PROVIDER的请求,单独测试NETWORK_PROVIDER(确保移动数据或Wi-Fi已开启),看是否能触发
onLocationChange。 - 日志排查:在权限检查和
requestLocationUpdates的位置添加日志,确认代码是否走到了对应的逻辑块——比如在onStart的权限判断分支打印Log,明确是进入了授权分支还是未授权分支。
修复后的完整MainActivity代码
package com.testingpurpose; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Handler; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private LocationManager locationManager; private Location lastLocation; private double distanceIntoMeters; private final String PERMISSION_ONE = Manifest.permission.ACCESS_FINE_LOCATION; private final String PERMISSION_TWO = Manifest.permission.ACCESS_COARSE_LOCATION; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ContextCompat.checkSelfPermission(this, PERMISSION_ONE) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, PERMISSION_TWO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{PERMISSION_ONE, PERMISSION_TWO}, 0); } } @Override protected void onStart() { super.onStart(); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (locationManager != null) { boolean hasFinePermission = ContextCompat.checkSelfPermission(this, PERMISSION_ONE) == PackageManager.PERMISSION_GRANTED; boolean hasCoarsePermission = ContextCompat.checkSelfPermission(this, PERMISSION_TWO) == PackageManager.PERMISSION_GRANTED; if (hasFinePermission || hasCoarsePermission) { try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); Log.i("LocationInit", "已启动定位监听"); } catch (SecurityException e) { Log.e("LocationError", "启动监听失败: " + e.getMessage()); } } else { Toast.makeText(this, "权限未授予", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(this, "无法获取定位服务", Toast.LENGTH_SHORT).show(); } periodicallyCheck(); } void periodicallyCheck(){ final Handler handler = new Handler(); final TextView tv = findViewById(R.id.tv); handler.post(new Runnable() { @Override public void run() { String format = String.format("%.2f %s",distanceIntoMeters,"meters"); tv.setText(format); handler.postDelayed(this,1000); } }); } private LocationListener listener = new LocationListener() { @Override public void onLocationChanged(Location location) { Log.i("Location Updates: ",">>> Lat "+location.getLatitude()+" , >>> Long "+location.getLongitude()); if ( lastLocation == null ){ lastLocation = location; return; } distanceIntoMeters += location.distanceTo(lastLocation); lastLocation = location; } @Override public void onStatusChanged(String provider, int status, Bundle extras) {} @Override public void onProviderEnabled(String provider) {} @Override public void onProviderDisabled(String provider) {} }; @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 0) { boolean hasLocationPermission = false; for (int result : grantResults) { if (result == PackageManager.PERMISSION_GRANTED) { hasLocationPermission = true; break; } } if (hasLocationPermission && locationManager != null) { try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); Toast.makeText(this, "定位监听已启动", Toast.LENGTH_SHORT).show(); } catch (SecurityException e) { Log.e("LocationError", "权限异常: " + e.getMessage()); } } else { Toast.makeText(this, "需要定位权限才能获取位置", Toast.LENGTH_SHORT).show(); } } } @Override protected void onDestroy() { super.onDestroy(); if (locationManager != null && listener != null){ locationManager.removeUpdates(listener); } } }
另外,你的activity_main.xml代码不完整,只需补全TextView的layout_height属性为wrap_content即可,不影响定位逻辑。
内容的提问来源于stack exchange,提问作者Paranoid
相关产品推荐
相关产品推荐

