Android RecyclerView调用setAdapter报空对象引用异常排查
问题报错
运行应用时触发空指针异常,报错信息如下:
Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setAdapter(androidx.recyclerview.widget.RecyclerView$Adapter)' on a null object reference
项目基于BottomNavigationView实现多Fragment切换,id为mRecyclerView的RecyclerView控件定义在HomeFragment的布局文件中,在MainActivity中直接通过findViewById获取控件实例后执行初始化操作时持续触发该空指针,参考同类问题方案无法适配当前项目场景。
关联代码
MainActivity 实现代码
package com.sti.lazshop; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.os.Bundle; import com.sti.lazshop.databinding.ActivityMainBinding; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { ActivityMainBinding binding; ArrayList<ItemModel> itemModels = new ArrayList<>(); int[] itemImages = {R.drawable.item_huion, R.drawable.item_iphone}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); RecyclerView recyclerView = findViewById(R.id.mRecyclerView); Item_RecyclerViewAdapter adapter = new Item_RecyclerViewAdapter(this, itemModels); setItemModels(); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); replaceFragment(new HomeFragment()); binding.bottomNavigationView2.setOnItemSelectedListener(item -> { switch (item.getItemId()) { case R.id.home: replaceFragment(new HomeFragment()); break; case R.id.cart: replaceFragment(new CartFragment()); break; case R.id.account: replaceFragment(new AccountFragment()); break; } return true; }); } private void replaceFragment(Fragment fragment) { FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(R.id.frameLayout, fragment); fragmentTransaction.commit(); } private void setItemModels() { String[] itemNames = getResources().getStringArray(R.array.item_full_txt); String[] itemPrices = getResources().getStringArray(R.array.item_prices); for (int i = 0; i < itemNames.length; i++) { itemModels.add(new ItemModel( itemNames[i], itemPrices[i], itemImages[i])); } } }
HomeFragment 实现代码
package com.sti.lazshop; import android.os.Bundle; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class HomeFragment extends Fragment { private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; private String mParam1; private String mParam2; public HomeFragment() { } public static HomeFragment newInstance(String param1, String param2) { HomeFragment fragment = new HomeFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_home, container, false); } }
fragment_home.xml 布局代码
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".HomeFragment"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/mRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
问题根因
- 控件查找范围不匹配:
mRecyclerView属于HomeFragment布局内的控件,不在MainActivity对应的activity_main布局层级中,在MainActivity中直接调用findViewById(R.id.mRecyclerView)无法匹配到对应控件,返回值为null,后续调用setAdapter等方法必然触发空指针。 - 执行时序错误:原代码中先执行控件查找逻辑,再调用
replaceFragment加载HomeFragment布局,查找动作发生在Fragment视图被添加到窗口层级之前,哪怕控件id在Activity布局中存在,此时也拿不到有效实例。 - 架构逻辑错误:Fragment内部的控件初始化逻辑应该放在Fragment自身的生命周期回调中实现,直接在宿主Activity中跨层级查找、操作Fragment的内部控件,不仅会触发空指针,后续Fragment切换、视图销毁重建时还会引发更多状态不一致的问题。
修复步骤
- 清理MainActivity中跨层级操作RecyclerView的冗余代码,删除以下片段:
RecyclerView recyclerView = findViewById(R.id.mRecyclerView); Item_RecyclerViewAdapter adapter = new Item_RecyclerViewAdapter(this, itemModels); setItemModels(); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this));
商品数据、资源配置如果后续需要在多页面共享,建议通过ViewModel实现,不要直接在Activity中持有、操作Fragment的内部控件。
- 调整HomeFragment代码,在Fragment自身的视图生命周期内完成RecyclerView初始化,修改后的参考代码如下:
package com.sti.lazshop; import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; public class HomeFragment extends Fragment { private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; private String mParam1; private String mParam2; private ArrayList<ItemModel> itemModels = new ArrayList<>(); private final int[] itemImages = {R.drawable.item_huion, R.drawable.item_iphone}; public HomeFragment() {} public static HomeFragment newInstance(String param1, String param2) { HomeFragment fragment = new HomeFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_home, container, false); // 从Fragment自身的根视图中查找RecyclerView实例 RecyclerView recyclerView = rootView.findViewById(R.id.mRecyclerView); // 初始化列表数据 setItemModels(); // 配置适配器与布局管理器 Item_RecyclerViewAdapter adapter = new Item_RecyclerViewAdapter(requireContext(), itemModels); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); return rootView; } private void setItemModels() { String[] itemNames = getResources().getStringArray(R.array.item_full_txt); String[] itemPrices = getResources().getStringArray(R.array.item_prices); for (int i = 0; i < itemNames.length; i++) { itemModels.add(new ItemModel( itemNames[i], itemPrices[i], itemImages[i])); } } }
- 开发注意事项
- Fragment中查找内部控件时,必须通过
onCreateView加载返回的根视图调用findViewById,不要直接使用Activity的查找方法,避免视图层级匹配错误。 - Fragment中获取上下文对象优先使用
requireContext()/requireActivity(),不要直接传入Fragment实例this,避免生命周期不匹配引发内存泄漏。 - Activity与Fragment之间的数据通信、交互不要通过直接操作对方控件实现,优先选择ViewModel、Fragment Result API或接口回调方案,保证生命周期安全。
内容的提问来源于stack exchange,提问作者Koi
相关产品推荐
相关产品推荐

