调用(listAdapter as WiFiPeerListAdapter).notifyDataSetChanged()引发崩溃求助
场景复现
在基于ListFragment的开发中,于onViewCreated方法内初始化适配器:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) listAdapter = WiFiPeerListAdapter(requireContext(), R.layout.row_devices, peers) }
执行clearPeers方法时触发崩溃:
fun clearPeers() { peers.clear() (listAdapter as WiFiPeerListAdapter).notifyDataSetChanged() }
此处listAdapter来自ListFragment的setListAdapter方法:
public void setListAdapter(@Nullable ListAdapter adapter) { boolean hadAdapter = mAdapter != null; mAdapter = adapter; if (mList != null) { mList.setAdapter(adapter); if (!mListShown && !hadAdapter) { // The list was hidden, and previously didn't have an // adapter. It is now time to show it. setListShown(true, requireView().getWindowToken() != null); } } }
崩溃日志
FATAL EXCEPTION: main
Process: com.tsfapps.wifip2p, PID: 29222
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.p2p.CONNECTION_STATE_CHANGE flg=0x24000010 (has extras) } in com.tsfapps.wifip2p.WiFiDirectBroadcastReceiver@b154cba
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1689)
at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.NullPointerException: null cannot be cast to non-null type com.tsfapps.wifip2p.DeviceListFragment.WiFiPeerListAdapter
at com.tsfapps.wifip2p.DeviceListFragment.clearPeers(DeviceListFragment.kt:102)
at com.tsfapps.wifip2p.MainActivity.resetData(MainActivity.kt:159)
at com.tsfapps.wifip2p.WiFiDirectBroadcastReceiver.onReceive(WiFiDirectBroadcastReceiver.kt:77)
... 11 more
问题原因
- 适配器未完成初始化:
clearPeers在Fragment的onViewCreated回调执行前被调用(比如广播接收器提前触发),此时listAdapter仍为null,Kotlin非空强转as WiFiPeerListAdapter直接抛出空指针异常。 - 适配器未正确绑定:仅给
listAdapter赋值但未调用setListAdapter,导致适配器未被Fragment正确持有,视图重建或生命周期异常时可能丢失适配器引用。
解决方案
1. 安全转型避免空指针
修改clearPeers方法,使用as?安全转型,避免空指针崩溃:
fun clearPeers() { peers.clear() val adapter = listAdapter as? WiFiPeerListAdapter adapter?.notifyDataSetChanged() }
2. 正确绑定适配器到ListView
在onViewCreated中调用setListAdapter,确保适配器被Fragment和ListView持有:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val adapter = WiFiPeerListAdapter(requireContext(), R.layout.row_devices, peers) listAdapter = adapter setListAdapter(adapter) // 关键:绑定适配器到ListView }
3. 合理管理广播接收器生命周期
在Fragment的onStart中注册广播接收器,onStop中注销,确保仅当Fragment处于活跃状态时才触发广播回调,避免提前调用clearPeers:
override fun onStart() { super.onStart() // 注册WiFi P2P广播接收器 } override fun onStop() { super.onStop() // 注销WiFi P2P广播接收器 }
内容的提问来源于stack exchange,提问作者Tousif Akram

