首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

RecyclerView「No adapter attached; skipping layout」:Fragment 生命週期導致的重複設置問題

     編輯:程式設計疑難解答

錯誤訊息

RecyclerView: No adapter attached; skipping layout

核心原因

Fragment 切換離開又回來時(如 ViewPager、BottomNavigationView),onCreateView 會重新執行,**但 RecyclerView 實例可能被保留**(取決於 setOffscreenPageLimit 或父容器)。若在 onResume/onViewCreated 再次呼叫 recyclerView = view.findViewById(...) 卻**忘記重新 setAdapter**,或將 recyclerView 設為 null 後未重設,即會出現此警告。

典型錯誤代碼

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_list, container, false);
    recyclerView = view.findViewById(R.id.rv); // 每次都新找
    return view;
}

@Override
public void onResume() {
    super.onResume();
    // 錯誤:這裡重新初始化 LayoutManager 但沒有 setAdapter
    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
    // 缺少 recyclerView.setAdapter(adapter);
}

正確模式:初始化與資料綁定分離

private RecyclerView recyclerView;
private MyAdapter adapter;
private List<Item> dataList = new ArrayList<>();

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_list, container, false);
    recyclerView = view.findViewById(R.id.rv);
    recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
    
    // Adapter 只建立一次,複用
    if (adapter == null) {
        adapter = new MyAdapter(dataList);
        recyclerView.setAdapter(adapter);
    }
    return view;
}

@Override
public void onResume() {
    super.onResume();
    // 只負責更新資料,不重設 LayoutManager/Adapter
    loadData(); // 內部做 dataList.clear(); dataList.addAll(...); adapter.notifyDataSetChanged();
}

進階:使用 ViewBinding + Lazy 初始化

private FragmentListBinding binding;
private MyAdapter adapter;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    binding = FragmentListBinding.inflate(inflater, container, false);
    binding.rv.setLayoutManager(new LinearLayoutManager(requireContext()));
    adapter = new MyAdapter();
    binding.rv.setAdapter(adapter);
    return binding.getRoot();
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null; // 釋放 View 參考,防洩漏
}

檢查清單

  • ✅ setLayoutManager 只在 onCreateView 呼叫一次。
  • ✅ setAdapter 只在 onCreateView 呼叫一次(或 adapter == null 時)。
  • ✅ onResume/onStart **只更新資料並 notifyDataSetChanged()**。
  • ✅ 使用 DiffUtil / ListAdapter 取代手動 notify,效能更好。

總結

「No adapter attached」源於 **Fragment 重建 View 時重設 LayoutManager 卻漏設 Adapter**。遵循「View 初始化一次、資料更新多次」原則,將 setAdapter 放入 onCreateView 並配合 adapter == null 守衛即可徹底解決。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved