android - MapView 的 onDestroy() 导致 UninitializedPropertyAccessException
问题描述
Google Map 的 MapView 组件有一个奇怪的问题,导致运行时异常 UninitializedPropertyAccessException。在除覆盖 MapView 方法的视图之外的所有其他视图中的第二次配置更改(设备旋转)后都会引发异常。因此,不会抛出此错误的MyMapViewFragment
处理生命周期,并且配置更改工作正常。com.google.android.gms.maps.MapView
问题出现在所有其他视图中,当我旋转设备MyMapViewFragment.onDestroy()
被调用时,它会破坏com.google.android.gms.maps.MapView
:
override fun onDestroy() {
super.onDestroy()
googleMapView.onDestroy()
}
第二次旋转设备会导致googleMapView.onDestroy()
UninitializedPropertyAccessException 上线 - MapView 未初始化。代码MyMapViewFragment
:
class MyMapViewFragment : Fragment(), OnMapReadyCallback {
private lateinit var googleMapView: com.google.android.gms.maps.MapView
private lateinit var googleMap : GoogleMap
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var view = inflater.inflate(R.layout.fragment_map_view, container, false)
googleMapView = view.findViewById(R.id.mapView2)
googleMapView.onCreate(savedInstanceState)
googleMapView.getMapAsync(this)
bottomNavigationView = requireActivity().findViewById(R.id.bottomNavigation)
mountainCustomInfoWindow.visibility = View.INVISIBLE
bottomNavigationView.visibility = View.VISIBLE
return view
}
override fun onMapReady(map: GoogleMap) {
googleMap = map
}
override fun onPause() {
super.onPause()
googleMapView.onPause()
}
override fun onResume() {
super.onResume()
googleMapView.onResume()
}
override fun onDestroy() {
super.onDestroy()
googleMapView.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
googleMapView.onLowMemory()
}
}
堆栈跟踪:
Process: com.hiker, PID: 25388
java.lang.RuntimeException: Unable to destroy activity {com.hiker/com.hiker.presentation.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property googleMapView has not been initialized
at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4605)
at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4623)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4897)
at android.app.ActivityThread.-wrap19(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1702)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property googleMapView has not been initialized
at com.hiker.presentation.map.MapView.onDestroy(MapView.kt:173)
at androidx.fragment.app.Fragment.performDestroy(Fragment.java:2830)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1028)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1310)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2659)
at androidx.fragment.app.FragmentManagerImpl.dispatchDestroy(FragmentManagerImpl.java:2644)
at androidx.fragment.app.Fragment.performDestroy(Fragment.java:2825)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1028)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2659)
at androidx.fragment.app.FragmentManagerImpl.dispatchDestroy(FragmentManagerImpl.java:2644)
at androidx.fragment.app.FragmentController.dispatchDestroy(FragmentController.java:329)
at androidx.fragment.app.FragmentActivity.onDestroy(FragmentActivity.java:366)
at androidx.appcompat.app.AppCompatActivity.onDestroy(AppCompatActivity.java:210)
at android.app.Activity.performDestroy(Activity.java:7479)
at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1255)
at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4592)
解决方案
更多的猜测:lateinit
期望在对其进行任何其他操作之前初始化该属性的属性。我们在这种情况下使用它,因为我们只能在构造函数中onCreateView
而不是在构造函数中初始化它。您确实googleMapView
在onCreateView
.
view.findViewById(R.id.mapView2)
但是,如果返回,您实际上可能没有正确初始化它null
。mapView2
如果布局中没有具有 id 的元素,就是这种情况fragment_map_view
。所以验证那里实际上有一个 MapView。
另一种可能发生的情况是,如果 Fragment 实际上没有附加到 View Hierarchy 而是在 Activity 中实例化和注册。当 Activity 被销毁时,它会销毁 Fragment 并在未初始化的对象上调用一个方法。这里的实际情况
(请参阅决议的评论)。
推荐阅读
- multithreading - 在 Kotlin 协程上运行阻塞 CPU 绑定任务
- node.js - Google App Engine 节点任务队列在完成前重试
- python - 如何手动对多索引数据框中的列进行排序?
- import - 导入到大查询表中的数据存储实体没有 id 列但 __key__.id
- javascript - 使用 JQuery 删除空 tbody
- python-3.x - 查找列表中仅出现一次的元素
- python - 通过在 Django 中根据条件运行查询来检索结果
- c++ - 每次运行程序时如何修复结果为零
- javascript - Firestore 返回未定义的 documentSnapshot.createTime(使用带有 javascript 的 webproject)
- javascript - 从模块导出的变量在角度类的函数内部不可访问