Android:解决Fragment B传对象后Fragment A列表新增项丢失问题
嘿,我来帮你解决这个问题!你遇到的情况确实是因为每次从Fragment B切回Fragment A时,A都会被重新实例化,导致之前添加的列表项被初始数据覆盖了。下面是具体的问题分析和解决方案:
问题根源
每次你在Fragment B里调用replace(R.id.FLfragment, fragment)回到Fragment A时,系统都会创建一个全新的Registration实例,而不是复用之前的那个。新实例会执行onCreateView里的createSubjectList()方法,把subjectlist重新初始化为只有person1和person2的列表,之前添加的person3、person4自然就被覆盖消失了。
解决方案
这里提供两种最适合新手的靠谱方案,你可以根据自己的需求选择:
方案一:用ViewModel保存列表数据(推荐,符合Android架构规范)
ViewModel专门用来在Fragment/Activity重建时保存数据,不会因为生命周期变化丢失内容,是Android官方推荐的持久化临时数据的方式。
- 先创建一个
SubjectViewModel类:
import androidx.lifecycle.ViewModel; import java.util.ArrayList; import java.util.List; public class SubjectViewModel extends ViewModel { private List<subjects> subjectList; public List<subjects> getSubjectList() { if (subjectList == null) { subjectList = new ArrayList<>(); // 初始化默认数据 subjectList.add(new subjects("person1",23,52,160)); subjectList.add(new subjects("person2",23,80,180)); } return subjectList; } public void addSubject(subjects newSubject) { subjectList.add(newSubject); } }
- 修改Fragment A(Registration)的关键代码:
- 移除原来的
createSubjectList()方法,改用ViewModel获取列表 - 修复
notifyItemInserted的位置参数(你之前写的0是添加到开头,要改成列表末尾的索引)
修改后的Registration核心代码:
public class Registration extends Fragment { private RecyclerView recyclerView; private SubjectAdapter msubjectadapter; private SubjectViewModel viewModel; // 新增ViewModel实例 private Button btn_addsubject; public Registration() { // Required empty public constructor } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 获取ViewModel,确保数据在重建时保留 viewModel = new ViewModelProvider(this).get(SubjectViewModel.class); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View FragmentView = inflater.inflate(R.layout.fragment_registeration, container, false); btn_addsubject= (Button) FragmentView.findViewById(R.id.addsubject); btn_addsubject.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { newsubject NewSubject = new newsubject(); FragmentTransaction transaction= getFragmentManager().beginTransaction(); transaction.replace(R.id.FLfragment,NewSubject); transaction.addToBackStack(null); transaction.commit(); } }); // 从ViewModel获取持久化的列表 List<subjects> subjectlist = viewModel.getSubjectList(); buildRecyclerView(FragmentView, subjectlist); msubjectadapter.SetOnClickListener(new SubjectAdapter.OnClickItemListener() { @Override public void onItemClick(int position) { Toast.makeText(getActivity(), "You clicked " + subjectlist.get(position).getName() + " on row number " + position, Toast.LENGTH_SHORT).show(); } }); return FragmentView; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Bundle bundle = this.getArguments(); if (bundle != null) { subjects s = (subjects) bundle.getParcelable("subj"); Toast.makeText(getActivity(), ""+s.getHeight() + s.getName() + s.getAge() +s.getWeight(), Toast.LENGTH_SHORT).show(); // 通过ViewModel添加新数据 viewModel.addSubject(s); // 通知适配器在列表末尾插入新项 msubjectadapter.notifyItemInserted(viewModel.getSubjectList().size() - 1); } } // 修改buildRecyclerView,接收外部传入的列表 public void buildRecyclerView(View FView, List<subjects> subjectlist){ recyclerView = (RecyclerView) FView.findViewById(R.id.subjects); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(FView.getContext())); msubjectadapter= new SubjectAdapter(subjectlist); recyclerView.setAdapter(msubjectadapter); } }
方案二:用hide/show替代replace切换Fragment(适合简单场景)
如果你不想引入ViewModel,可以通过隐藏原有Fragment、显示新Fragment的方式,让Fragment A不被销毁,从而保留列表数据。
- 修改Fragment A跳转到B的代码:
btn_addsubject.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { newsubject NewSubject = new newsubject(); FragmentTransaction transaction= getFragmentManager().beginTransaction(); // 隐藏当前Fragment A,添加Fragment B到容器 transaction.hide(Registration.this); transaction.add(R.id.FLfragment, NewSubject); transaction.addToBackStack(null); transaction.commit(); } });
- 修改Fragment B返回A的代码:
btn_add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 先做输入校验,避免空指针 String name = et_name.getText().toString().trim(); String ageStr = et_age.getText().toString().trim(); String weightStr = et_weight.getText().toString().trim(); String heightStr = et_height.getText().toString().trim(); if(TextUtils.isEmpty(name) || TextUtils.isEmpty(ageStr) || TextUtils.isEmpty(weightStr) || TextUtils.isEmpty(heightStr)){ Toast.makeText(getActivity(), "请填写完整信息", Toast.LENGTH_SHORT).show(); return; } subjects subject=new subjects(name,Integer.parseInt(ageStr),Integer.parseInt(weightStr),Integer.parseInt(heightStr)); // 获取之前隐藏的Registration实例 Registration fragment = (Registration) getFragmentManager().findFragmentByTag("REGISTRATION_TAG"); if(fragment != null){ // 直接调用A的方法添加数据 fragment.addNewSubject(subject); // 返回上一页,显示原来的Fragment A getFragmentManager().popBackStack(); } } });
- 在Fragment A中添加方法并设置tag:
首先在Activity中添加Registration时设置tag(或者在A自己的创建逻辑里设置):
// Activity中的代码示例 getSupportFragmentManager().beginTransaction() .add(R.id.FLfragment, new Registration(), "REGISTRATION_TAG") .commit();
然后在Registration中添加添加新数据的方法:
public void addNewSubject(subjects newSubject){ subjectlist.add(newSubject); msubjectadapter.notifyItemInserted(subjectlist.size()-1); }
额外小提醒
- Java类名首字母要大写,你的
subjects建议改成Subjects,符合命名规范 - 获取EditText输入值时一定要做非空和有效性校验,避免崩溃
内容的提问来源于stack exchange,提问作者Naima Abiad
相关产品推荐
相关产品推荐

