应用运行时更新RecyclerView求助:Room数据切换Tab无法实时显示
问题描述
我在TabLayout第一个页签的输入框中填写数据并存储到Room数据库,切换到第二个页签时,希望RecyclerView能直接显示新增的数据,但现在只有重启应用后数据才会出现,怀疑是Fragment生命周期的问题,求解决。
相关代码
MainActivity
import .. public class MainActivity extends AppCompatActivity { TabLayout tabLayout; ViewPager2 viewPager2; ViewPagerAdapter adapter; private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); viewPager2 = binding.viewPager; tabLayout = binding.tabLayout; tabLayout.addTab(tabLayout.newTab().setText(R.string.tab_text_1)); tabLayout.addTab(tabLayout.newTab().setText(R.string.tab_text_2)); adapter = new ViewPagerAdapter(this,getSupportFragmentManager(), getLifecycle()); viewPager2.setAdapter(adapter); tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { viewPager2.setCurrentItem(tab.getPosition()); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } }); viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { tabLayout.selectTab(tabLayout.getTabAt(position)); } }); } }
AddFragment
import .. public class addFragment extends Fragment { FragmentAddBinding binding; PeopleDao dao; Database db; private final CompositeDisposable mDisposable = new CompositeDisposable(); public static addFragment newInstance(){ return new addFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); db = Room.databaseBuilder(requireContext(), Database.class, "PeopleInfo") .build(); dao = db.peopleDao(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding =FragmentAddBinding.inflate(inflater,container,false); View view = binding.getRoot(); return view; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Button saveBtn = binding.buttonSave; saveBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { buttonSave(v); } }); } public void buttonSave(View view){ String fllName = binding.editTextFullName.getText().toString(); String phoneNum = binding.editTextTelNo.getText().toString(); String ClosenessD = binding.editTextClosenessDegree.getText().toString(); PeopleInfo peopleInfo = new PeopleInfo(fllName,phoneNum,ClosenessD); mDisposable.add(dao.insert(peopleInfo) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(addFragment.this::handleResponse) ); } private void handleResponse(){ Toast.makeText(requireActivity(),"Successfuly Added",Toast.LENGTH_LONG).show(); binding.editTextFullName.setText(""); binding.editTextTelNo.setText(""); binding.editTextClosenessDegree.setText(""); } @Override public void onDestroy() { super.onDestroy(); binding = null; mDisposable.clear(); } }
ShowFragment
import .. public class showFragment extends Fragment { PeopleAdapter peopleAdapter; List<PeopleInfo> arrayList; FragmentShowBinding binding; PeopleDao dao; Database database; private final CompositeDisposable compositeDisposable = new CompositeDisposable(); PageViewModel pageViewModel; public static showFragment newInstance() { return new showFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); arrayList = new ArrayList<>(); database = Room.databaseBuilder(requireContext(), Database.class, "PeopleInfo") .build(); dao = database.peopleDao(); getData(); pageViewModel = new ViewModelProvider(requireActivity()).get(PageViewModel.class); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentShowBinding.inflate(inflater,container,false); View view = binding.getRoot(); return view; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); pageViewModel.getAll().observe(requireActivity(), new Observer<List<PeopleInfo>>() { @Override public void onChanged(List<PeopleInfo> peopleInfos) { peopleAdapter.setData(peopleInfos); peopleAdapter.notifyDataSetChanged(); getData(); } }); } public void getData() { compositeDisposable.add(dao.getAll() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(showFragment.this::handleResponce)); } private void handleResponce(List<PeopleInfo> peopleInfoList){ binding.recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); peopleAdapter = new PeopleAdapter(peopleInfoList); binding.recyclerView.setAdapter(peopleAdapter); } @Override public void onDestroy() { super.onDestroy(); binding = null; compositeDisposable.clear(); } }
PeopleAdapter
public class PeopleAdapter extends RecyclerView.Adapter<PeopleAdapter.viewHolder> { private List<PeopleInfo> peopleInfoArrayList = new ArrayList<>(); public PeopleAdapter(List<PeopleInfo> peopleInfoArrayList) { this.peopleInfoArrayList = peopleInfoArrayList; } public void setData(List<PeopleInfo> newData){ peopleInfoArrayList.clear(); peopleInfoArrayList.addAll(newData); } @NonNull @Override public viewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { RecyclerRowBinding recyclerRowBinding = RecyclerRowBinding.inflate(LayoutInflater.from(parent.getContext()),parent,false); return new viewHolder(recyclerRowBinding); } @Override public void onBindViewHolder(@NonNull viewHolder holder, int position) { holder.binding.fullNameTxt.setText(peopleInfoArrayList.get(position).fullName); } @Override public int getItemCount() { return peopleInfoArrayList.size(); } public class viewHolder extends RecyclerView.ViewHolder{ private RecyclerRowBinding binding; public viewHolder(RecyclerRowBinding binding) { super(binding.getRoot()); this.binding = binding; } } }
PageViewModel
public class PageViewModel extends ViewModel { private MutableLiveData<List<PeopleInfo>> pInfo = new MutableLiveData<>(); public LiveData<List<PeopleInfo>> getAll() { return pInfo; } public void setData(List<PeopleInfo> info){ pInfo.setValue(info); } }
问题分析及解决方案
核心问题
- 数据更新无通知:AddFragment插入数据后,没有通知ShowFragment或ViewModel刷新数据,导致ShowFragment只能拿到初始化时的旧数据。
- ViewModel未利用Room自动监听:当前ViewModel手动维护MutableLiveData,没有绑定Room的LiveData能力,无法自动感知数据库变化。
- ShowFragment数据逻辑混乱:每次调用
getData()都会新建Adapter,且在ViewModel的观察者里重复调用getData(),造成无效循环和数据丢失。
修改步骤
1. 修改PeopleDao,让查询返回LiveData
Room支持直接返回LiveData,数据库变化时会自动通知观察者:
@Dao public interface PeopleDao { @Insert Completable insert(PeopleInfo peopleInfo); // 改为返回LiveData,自动监听数据库变化 @Query("SELECT * FROM PeopleInfo") LiveData<List<PeopleInfo>> getAll(); }
2. 重构PageViewModel,绑定Room的LiveData
让ViewModel直接持有Room的LiveData,不用手动维护数据:
public class PageViewModel extends ViewModel { private LiveData<List<PeopleInfo>> pInfo; // 初始化时传入Dao,避免重复创建数据库实例 public void init(PeopleDao dao) { if (pInfo == null) { pInfo = dao.getAll(); } } public LiveData<List<PeopleInfo>> getAll() { return pInfo; } }
3. 简化ShowFragment逻辑
移除手动查询,直接观察ViewModel的LiveData,初始化一次Adapter:
public class showFragment extends Fragment { PeopleAdapter peopleAdapter; FragmentShowBinding binding; PageViewModel pageViewModel; public static showFragment newInstance() { return new showFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); pageViewModel = new ViewModelProvider(requireActivity()).get(PageViewModel.class); // 初始化ViewModel,传入Dao Database database = Room.databaseBuilder(requireContext(), Database.class, "PeopleInfo").build(); pageViewModel.init(database.peopleDao()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentShowBinding.inflate(inflater,container,false); return binding.getRoot(); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 初始化RecyclerView和Adapter,只做一次 binding.recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); peopleAdapter = new PeopleAdapter(new ArrayList<>()); binding.recyclerView.setAdapter(peopleAdapter); // 观察ViewModel的数据变化,用getViewLifecycleOwner避免内存泄漏 pageViewModel.getAll().observe(getViewLifecycleOwner(), peopleInfos -> { peopleAdapter.setData(peopleInfos); peopleAdapter.notifyDataSetChanged(); }); } @Override public void onDestroy() { super.onDestroy(); binding = null; } }
4. 优化AddFragment,确保数据插入后触发更新
插入成功后无需额外操作,因为Room的LiveData会自动监听数据库变化并通知ViewModel,最终更新ShowFragment的RecyclerView:
private void handleResponse(){ Toast.makeText(requireActivity(),"添加成功",Toast.LENGTH_LONG).show(); binding.editTextFullName.setText(""); binding.editTextTelNo.setText(""); binding.editTextClosenessDegree.setText(""); }
内容的提问来源于stack exchange,提问作者ismail Vasip
相关产品推荐
相关产品推荐

