MapView 的 onDestroy() 导致 UninitializedPropertyAccessException
Posted
技术标签:
【中文标题】MapView 的 onDestroy() 导致 UninitializedPropertyAccessException【英文标题】:MapView's onDestroy() causing UninitializedPropertyAccessException 【发布时间】:2020-03-09 07:17:24 【问题描述】:Google Map 的 MapView 组件有一个奇怪的问题,导致运行时异常 UninitializedPropertyAccessException。 除了 MapView 的方法被覆盖的视图之外的所有其他视图中的第二次配置更改(设备旋转)后都会引发异常。因此,在处理 com.google.android.gms.maps.MapView
生命周期的 MyMapViewFragment
中不会引发此错误并且配置更改工作正常。
问题出现在所有其他视图中,当我旋转设备时,调用 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)
【问题讨论】:
你能发布完整的堆栈跟踪吗? 当然,在问题中添加了堆栈跟踪。为了清楚起见,我将com.hiker.presentation.map.MapView
命名为MyMapViewFragment
在我看来 onDestroy
在 onCreateView
之前被调用过,这确实很奇怪。您如何将片段添加到活动中?
是的,您是对的,配置更改时不会调用 onCreateView。我正在使用带有导航图的导航组件,com.hiker.presentation.map.MapView
是我的起始视图。在我的 MainActivity 中,我有 BottomNavigationView,它处理切换视图
酷,我刚刚添加了另一个潜在问题的答案。所以如果你愿意,可以接受它
【参考方案1】:
更多猜测:
lateinit
的属性期望在对其进行任何其他操作之前初始化该属性。我们在这种情况下使用它,因为我们只能在 onCreateView
中初始化它,而不是在构造函数中。您确实在onCreateView
的第二行初始化googleMapView
。
但是,如果view.findViewById(R.id.mapView2)
将返回null
,您实际上可能没有正确初始化它。如果布局fragment_map_view
中没有id 为mapView2
的元素,情况就是这样。所以验证那里确实有一个 MapView。
另一种可能发生的情况是,如果 Fragment 实际上并未附加到 View Hierarchy,而是在 Activity 中实例化并注册。当 Activity 被销毁时,它会销毁 Fragment 并在未初始化的对象上调用一个方法。 这里的实际情况
(请参阅 cmets 了解分辨率)。
【讨论】:
我发现当我在 TripView 上旋转设备时,会发生以下流程:MapView.onDestroy() -> MainActivity.onCreate() -> MapView.onCreate() -> TripView.onCreate()。奇怪的是,调用了 MapView.onCreate(),但为什么呢?该片段不依赖于 TripView。当我第二次旋转设备时,首先是 MapView.onDestroy() 并且应用程序崩溃了..以上是关于MapView 的 onDestroy() 导致 UninitializedPropertyAccessException的主要内容,如果未能解决你的问题,请参考以下文章
以编程方式创建 MapView 并添加标记导致片段中出现空指针异常
精简模式下的 MapView 导致 RecyclerView 无法正确滚动
iOS MapKit更改mapview maptype会导致注释图像更改为pin?