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

Android Fragment 切換返回時重複載入資料?單一載入模式實現指南

     編輯:程式設計綜合問答

問題場景

使用 `FragmentTransaction.replace()` 切換 Fragment A → B,再按返回鍵回到 A 時,`onCreateView()` 或 `onResume()` 再次執行,導致資料重複請求、列表重複載入。

核心原因

  • `replace()` 預設會 銷毀 當前 Fragment (執行 `onDestroyView` → `onDestroy`),回退時重新建立實例。
  • 若在 `onCreateView` 中發起網路請求,每次建立都會觸發。

方案一:使用 hide/show 替代 replace(推薦)

// 容器持有所有 Fragment 實例
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (!fragmentB.isAdded()) {
    ft.add(R.id.container, fragmentB, "B");
}
ft.hide(fragmentA).show(fragmentB).addToBackStack(null).commit();

// 返回鍵自動處理 hide/show,Fragment 實例不銷毀,onCreateView 僅執行一次

優點:生命週期簡單、狀態自動保留、程式碼最少。
缺點:所有 Fragment 長駐記憶體,適用於 3-5 個標籤頁場景。

方案二:ViewPager + FragmentPagerAdapter(官方標準)

// FragmentPagerAdapter 會保留 Fragment 實例 (detach view 不 destroy)
viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
    @Override public Fragment getItem(int pos) { return fragments[pos]; }
    @Override public int getCount() { return fragments.length; }
});

配合 `TabLayout` 實現頂部標籤切換,Fragment 只建立一次,`setUserVisibleHint` 或 `setMenuVisibility` 控制可見時載入資料。

方案三:手動快取資料 / 狀態保存


// 在 Fragment 內部
private List cachedData;
private boolean isLoaded = false;

@Override
public void onResume() {
    super.onResume();
    if (!isLoaded) {
        loadData(); // 僅第一次載入
        isLoaded = true;
    }
    // 或使用 cachedData 直接更新 UI
}

private void loadData() {
    // 網路請求成功後
    cachedData = result;
    adapter.setData(cachedData);
}

配合 `setRetainInstance(true)` (僅適用非嵌套 Fragment) 可在 Activity 重建時保留實例。

方案對比總結

方案適用場景記憶體實現難度
hide/show底部導航 3-5 頁中低
ViewPager頂部標籤、左右滑動中低
手動快取複雜嵌套、需精確控制低中
replace + ViewModel (Jetpack)現代架構、配合 LiveData低中

最佳實踐建議 (2024+)

採用 Navigation Component + ViewModel:
Fragment 只負責 UI,資料存放於 `ViewModel` (生命週期跟隨 Activity/Navigation Graph),Fragment 重建時自動獲取相同 ViewModel 實例,資料零重複請求。


// Fragment 內
MyViewModel vm = new ViewModelProvider(requireActivity()).get(MyViewModel.class);
vm.getData().observe(getViewLifecycleOwner(), data -> adapter.submitList(data));
// 首次進入時 vm 發起請求,後續重建直接取緩存
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved