Android开发中addOnSuccessListener赋值后currentLocation仍为null如何解决
问题本质
你遇到的空值问题核心是定位请求是异步操作:
fusedLocationProviderClient.lastLocation的addOnSuccessListener回调不会阻塞主线程执行,你在onCreateView中调用完fetchLocation()后立刻打印日志,此时定位请求还没有返回结果,currentLocation自然还没被赋值,所以为空。- 你能看到TextView正常显示地址,是因为定位结果返回后才会执行回调里的赋值逻辑,两者存在时间差。
另外你现有代码里的权限申请逻辑也有问题:ActivityCompat.requestPermissions 同样是异步调用,申请后立刻判断请求码递归调用 fetchLocation() 是无效的,权限结果需要在 onRequestPermissionsResult 回调中接收。
修复方案
1. 调整定位后逻辑的执行时机
所有需要用到 currentLocation 的逻辑,统一放到定位成功的回调中执行,或者通过ViewModel的LiveData通知触发,不要在调用fetchLocation后立刻访问该变量。
2. 修复权限申请逻辑
移除fetchLocation里权限申请后的无效递归,重写权限申请结果回调,在用户授予权限后再触发定位。
3. 避免空指针崩溃
不要直接用 !! 强行解包可空变量,增加空判断避免异常。
修正后的示例代码
class EventNearMeFragment : Fragment() { private lateinit var binding: FragmentEventNearMeBinding private var fusedLocationProviderClient: FusedLocationProviderClient? = null private var currentLocation: Location? = null private val vm: EventNearMeViewModel by activityViewModels() // 定位权限请求码 private val LOCATION_PERMISSION_CODE = 1000 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View { binding = FragmentEventNearMeBinding.inflate(inflater, container, false) fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(requireContext()) fetchLocation() // 不要在这里直接访问currentLocation,此时还没赋值 return binding.root } private fun fetchLocation() { if(ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(requireContext(),android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ // 申请权限,结果在回调中接收 ActivityCompat.requestPermissions(requireActivity(), arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_CODE) return } val task = fusedLocationProviderClient?.lastLocation task?.addOnSuccessListener { location -> if(location != null) { this.currentLocation = location // 所有需要用到currentLocation的逻辑都放在这里执行,或者通知ViewModel处理 Log.d("current location value", "${location.latitude} ${location.longitude}") val geoCoder = Geocoder(requireContext(), Locale.getDefault()) val addresses = geoCoder.getFromLocation(location.latitude, location.longitude, 1) addresses?.firstOrNull()?.let { address -> Toast.makeText(context, address.getAddressLine(0), Toast.LENGTH_SHORT).show() binding.lblAddress.text = address.getAddressLine(0) // 如果需要把位置传给ViewModel,在这里赋值 vm.updateCurrentLocation(location) } } } } // 重写权限申请结果回调 override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == LOCATION_PERMISSION_CODE) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 用户授予权限,重新触发定位 fetchLocation() } else { // 用户拒绝权限,做降级处理 Toast.makeText(context, "需要定位权限才能获取附近事件", Toast.LENGTH_SHORT).show() } } } }
内容的提问来源于stack exchange,提问作者Chew Hong Yu
相关产品推荐
相关产品推荐

