You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

应用运行时更新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);
}
}

问题分析及解决方案

核心问题

  1. 数据更新无通知:AddFragment插入数据后,没有通知ShowFragment或ViewModel刷新数据,导致ShowFragment只能拿到初始化时的旧数据。
  2. ViewModel未利用Room自动监听:当前ViewModel手动维护MutableLiveData,没有绑定Room的LiveData能力,无法自动感知数据库变化。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:29:56