Bottom Navigation切换Fragment后数据丢失问题求助(附代码)
解决Fragment切换后数据丢失的问题
我帮你分析了下问题所在,以及对应的解决方案:
问题根源
你遇到的核心问题有两个:
- Fragment切换时的视图销毁:你的
setFragment方法用了replace,这个操作会把之前的Fragment视图完全销毁,切回Fragment A时会重新执行onCreateView。而你在onCreateView里每次都重新初始化herbalModels = new ArrayList<>()和kampoModels = new ArrayList<>(),直接清空了之前加载的数据。 - 异步请求的空白期:即使重新发起Volley请求,因为网络请求是异步的,界面会短暂空白,体验很差。
解决方案
1. 保留Fragment数据,避免重复初始化列表
把数据列表从onCreateView里的局部变量改成Fragment的成员变量,只在Fragment创建时初始化一次:
public class herbal extends Fragment { // 你的Fragment类 // 把列表提升为成员变量,不要在onCreateView里重新new private ArrayList<herbalModel> herbalModels; private ArrayList<kampoModel> kampoModels; // 其他成员变量(适配器、RecyclerView等)... @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 只在Fragment创建时初始化一次列表 herbalModels = new ArrayList<>(); kampoModels = new ArrayList<>(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_herbal, container, false); // 删掉这两行:herbalModels = new ArrayList<>(); kampoModels = new ArrayList<>(); // 剩下的原有逻辑... return rootView; } }
2. 改用Hide/Show切换Fragment,避免视图销毁
修改MainActivity的setFragment方法,用hide和show替代replace,这样Fragment的视图和数据都会被保留,切换时只是隐藏/显示,不会重新创建:
首先在MainActivity里添加一个变量记录当前显示的Fragment:
private Fragment currentFragment;
然后修改初始化Fragment的逻辑:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(isNetworkStatusAvialable (getApplicationContext())) { bottomNavigationView=(BottomNavigationView)findViewById(R.id.main_nav); frameLayout=(FrameLayout) findViewById(R.id.main_frame); // 初始化所有Fragment herbal= new herbal(); crude = new crude(); database=new database(); analysis=new analysis(); compound=new compound(); // 初始化显示第一个Fragment currentFragment = herbal; getSupportFragmentManager().beginTransaction() .add(R.id.main_frame, herbal) .commit(); bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.nav_herbal: setFragment(herbal); return true; case R.id.nav_crude: setFragment(crude); return true; case R.id.nav_database: setFragment(database); return true; case R.id.nav_analysis: setFragment(analysis); return true; case R.id.nav_compound: setFragment(compound); return true; default: return false; } } }); } else { Toast.makeText(getApplicationContext(), "internet is not avialable", Toast.LENGTH_SHORT).show(); } }
最后修改setFragment方法:
private void setFragment(Fragment fragment) { FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); // 隐藏当前显示的Fragment if (currentFragment != null) { fragmentTransaction.hide(currentFragment); } // 如果目标Fragment还没添加到容器,先添加;否则直接显示 if (!fragment.isAdded()) { fragmentTransaction.add(R.id.main_frame, fragment); } else { fragmentTransaction.show(fragment); } fragmentTransaction.commit(); currentFragment = fragment; }
3. 优化请求逻辑,避免重复加载数据
在Fragment A的加载数据方法里,先判断列表是否已有数据,避免重复发起网络请求:
private void get20DataJamu() { // 如果已有数据,直接更新适配器,不用再请求 if (!herbalModels.isEmpty()) { mAdapter.notifyDataSetChanged(); return; } // 原有Volley请求代码... } private void get20DataKampo() { if (!kampoModels.isEmpty()) { kampoAdapter.notifyDataSetChanged(); return; } // 原有Volley请求代码... }
这样修改后,切换Fragment再切回来时,数据会完整保留,界面也不会出现空白,同时避免了不必要的网络请求。
内容的提问来源于stack exchange,提问作者Muhammad Ilham Ramadhan
相关产品推荐
相关产品推荐

