请求位置权限时App崩溃:Task is not yet complete异常排查
安卓App位置权限请求时崩溃问题排查与解决
问题背景
开发一个包含两个Activity的简易安卓App:主Activity有一个TextView(显示占位符或地图返回的坐标)和跳转按钮,通过registerForActivityResult跳转到MapActivity;MapActivity是可放置标记的地图页面,提交后将坐标返回主Activity显示。但App请求用户位置权限时发生崩溃,抛出IllegalStateException: Task is not yet complete异常。
崩溃日志
2022-09-16 00:28:51.357 10442-10442/com.example.ymapstest E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.ymapstest, PID: 10442 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ymapstest/com.example.ymapstest.MapActivity}: java.lang.IllegalStateException: Task is not yet complete at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Caused by: java.lang.IllegalStateException: Task is not yet complete at com.google.android.gms.common.internal.Preconditions.checkState(com.google.android.gms:play-services-basement@@18.0.0:2) at com.google.android.gms.tasks.zzw.zzf(com.google.android.gms:play-services-tasks@@18.0.1:1) at com.google.android.gms.tasks.zzw.getResult(com.google.android.gms:play-services-tasks@@18.0.1:1) at com.example.ymapstest.MapActivity.getLastLocation(MapActivity.kt:61) at com.example.ymapstest.MapActivity.onCreate(MapActivity.kt:35) at android.app.Activity.performCreate(Activity.java:8000) at android.app.Activity.performCreate(Activity.java:7984) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
相关代码
MainActivity代码
class MainActivity : AppCompatActivity() { private var launcher: ActivityResultLauncher<Intent>? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val textView: TextView = findViewById(R.id.tv_message) launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == RESULT_OK) { val latitude = result.data?.getDoubleExtra("latitude", 0.0).toString() val longitude = result.data?.getDoubleExtra("longitude", 0.0).toString() textView.text = getString(R.string.address, latitude, longitude) } } } fun onClickToMap(view: View) { launcher?.launch(Intent(this, MapActivity::class.java)) } }
MapActivity代码
class MapActivity : AppCompatActivity(), InputListener{ private lateinit var mapView: MapView private val mapAPI = "my api key here" private val REQUEST_CODE = 101 var userInput: Point = Point(0.0, 0.0) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) MapKitFactory.setApiKey(mapAPI) MapKitFactory.initialize(this) setContentView(R.layout.activity_map) val userLocation = Point(getLastLocation().latitude, getLastLocation().longitude) mapView = findViewById(R.id.mapview) mapView.map.move( CameraPosition(userLocation, 11.0f, 0.0f, 0.0f), Animation(Animation.Type.SMOOTH, 300f), null) } fun onClick(view: View) { if (userInput.equals(Point(0.0, 0.0))) { Toast.makeText(this, "You didnt place the point", Toast.LENGTH_LONG).show() } else { val intent = Intent() intent.putExtra("latitude", userInput.latitude) intent.putExtra("longitude", userInput.longitude) setResult(RESULT_OK, intent) } } private fun getLastLocation(): Location { val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this) if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) { requestLocationPermission() return fusedLocationProviderClient.lastLocation.result } else { return fusedLocationProviderClient.lastLocation.result } } private fun requestLocationPermission() { if (ContextCompat.checkSelfPermission(this, "android.permission.ACCESS_FINE_LOCATION")!= PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_CODE) } } override fun onStop() { super.onStop() mapView.onStop() MapKitFactory.getInstance().onStop() } override fun onStart() { super.onStart() mapView.onStart() MapKitFactory.getInstance().onStart() } override fun onMapTap(map: Map, point: Point) { mapView.map.mapObjects.clear() mapView.map.mapObjects.addPlacemark(point, ImageProvider.fromResource(this, R.drawable.ic_pin)) userInput = point } }
问题根源
- 异步任务同步获取结果:
fusedLocationProviderClient.lastLocation返回的是Task<Location>,这是一个异步操作,直接调用.result会在任务未完成时抛出Task is not yet complete异常。 - 权限处理逻辑错误:请求权限后立即尝试获取位置,此时用户还未完成权限授权操作,权限状态仍为未授予,同时异步位置任务也未执行。
- 缺少Activity关闭逻辑:MapActivity提交坐标后未调用
finish(),导致Activity无法返回主Activity。
修复方案
1. 异步处理位置获取
使用Task的监听器方法addOnSuccessListener和addOnFailureListener异步获取位置结果,避免同步阻塞。
2. 正确处理权限回调
重写onRequestPermissionsResult方法,在用户授予权限后再执行位置获取逻辑;若用户拒绝权限,可设置默认位置或提示用户。
3. 补充Activity关闭逻辑
在提交坐标后调用finish()关闭MapActivity,确保结果返回主Activity。
修复后的MapActivity代码
class MapActivity : AppCompatActivity(), InputListener { private lateinit var mapView: MapView private val mapAPI = "my api key here" private val REQUEST_CODE = 101 var userInput: Point = Point(0.0, 0.0) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) MapKitFactory.setApiKey(mapAPI) MapKitFactory.initialize(this) setContentView(R.layout.activity_map) mapView = findViewById(R.id.mapview) // 先初始化地图到默认位置,后续获取到位置后再移动 val defaultLocation = Point(55.751244, 37.618423) // 莫斯科坐标作为默认 mapView.map.move( CameraPosition(defaultLocation, 11.0f, 0.0f, 0.0f), Animation(Animation.Type.SMOOTH, 300f), null) // 检查权限并尝试获取位置 checkLocationPermissionAndFetchLocation() } fun onClick(view: View) { if (userInput.equals(Point(0.0, 0.0))) { Toast.makeText(this, "You didn't place the point", Toast.LENGTH_LONG).show() } else { val intent = Intent() intent.putExtra("latitude", userInput.latitude) intent.putExtra("longitude", userInput.longitude) setResult(RESULT_OK, intent) finish() // 关闭Activity返回主页面 } } private fun checkLocationPermissionAndFetchLocation() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { // 权限已授予,异步获取位置 fetchLastLocation() } else { // 权限未授予,发起请求 ActivityCompat.requestPermissions( this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_CODE ) } } private fun fetchLastLocation() { val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this) fusedLocationProviderClient.lastLocation.addOnSuccessListener { location: Location? -> location?.let { val userLocation = Point(it.latitude, it.longitude) // 移动地图到用户位置 mapView.map.move( CameraPosition(userLocation, 11.0f, 0.0f, 0.0f), Animation(Animation.Type.SMOOTH, 300f), null) } ?: run { // 位置获取失败,提示用户 Toast.makeText(this, "Failed to get your location", Toast.LENGTH_SHORT).show() } }.addOnFailureListener { exception -> // 处理获取位置失败的情况 Toast.makeText(this, "Location fetch error: ${exception.message}", Toast.LENGTH_SHORT).show() } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_CODE) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 用户授予权限,获取位置 fetchLastLocation() } else { // 用户拒绝权限,提示或使用默认位置 Toast.makeText(this, "Location permission denied, using default location", Toast.LENGTH_SHORT).show() } } } override fun onStop() { super.onStop() mapView.onStop() MapKitFactory.getInstance().onStop() } override fun onStart() { super.onStart() mapView.onStart() MapKitFactory.getInstance().onStart() } override fun onMapTap(map: Map, point: Point) { mapView.map.mapObjects.clear() mapView.map.mapObjects.addPlacemark(point, ImageProvider.fromResource(this, R.drawable.ic_pin)) userInput = point } }
内容的提问来源于stack exchange,提问作者Eugene Mihailukov
相关产品推荐
相关产品推荐

