Android添加数据后RecyclerView无法实时更新列表问题求助
Room数据库新增数据后RecyclerView无法实时更新
我是Android开发新手,项目使用TabLayout、ViewPager2、Fragment和底部导航栏,做了两个Fragment:Tab1负责输入数据,Tab2用RecyclerView展示数据,数据存储依赖Room数据库。目前遇到的问题是:输入数据后Toast提示已成功存入数据库,但RecyclerView里看不到新数据,必须重启应用才能显示更新。
相关代码
WriteFragment(输入数据页面)
View mView; EditText addTitle; EditText addContent; ImageButton btnSave; public WriteFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.fragment_write, container, false); addTitle = mView.findViewById(R.id.edt_add_title); addContent = mView.findViewById(R.id.edt_add_content); btnSave = mView.findViewById(R.id.btn_save); btnSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { addItems(); } }); hideSoftKeyboard(); return mView; } private void addItems() { String strTitle = addTitle.getText().toString().trim(); String strContent = addContent.getText().toString().trim(); if (TextUtils.isEmpty(strTitle)|| TextUtils.isEmpty(strContent)){ return; } ItemsObject itemsObject = new ItemsObject(strTitle,strContent); MainActivity.diaryDatabase.getInstance(getActivity()).userDAO().insert(itemsObject); Toast.makeText(getActivity(),"Successfully Added",Toast.LENGTH_SHORT).show(); addTitle.setText(""); addContent.setText(""); hideSoftKeyboard(); } public void hideSoftKeyboard() { try { InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0); } catch (NullPointerException exception) { exception.printStackTrace(); } }
DiaryLogFragment(数据展示页面)
package com.haki.mysimplehakidiarynotes.fragments.diary_tabs; import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.haki.mysimplehakidiarynotes.ItemsAdapter; import com.haki.mysimplehakidiarynotes.ItemsObject; import com.haki.mysimplehakidiarynotes.MainActivity; import com.haki.mysimplehakidiarynotes.R; import java.util.ArrayList; import java.util.List; public class DiaryLogFragment extends Fragment { View mView; private RecyclerView rcvItems; private ItemsAdapter itemsAdapter; private List<ItemsObject> itemsObjectList; public DiaryLogFragment(){ } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.fragment_diary_log, container, false); rcvItems = mView.findViewById(R.id.rcv_items); itemsAdapter = new ItemsAdapter(); itemsObjectList = DiaryDatabase.getInstance(getActivity()).userDAO().getListUser(); itemsAdapter.setData(itemsObjectList); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); rcvItems.setLayoutManager(linearLayoutManager); rcvItems.setFocusable(true); rcvItems.setAdapter(itemsAdapter); return mView; } }
ItemsAdapter(RecyclerView适配器)
package com.haki.mysimplehakidiarynotes; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.ramotion.foldingcell.FoldingCell; import java.util.List; public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ItemViewHolder>{ private List<ItemsObject> mListItems; public void setData(List<ItemsObject> list) { this.mListItems = list; notifyDataSetChanged(); } @NonNull @Override public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.layout_items, parent, false); return new ItemViewHolder(view); } @Override public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) { ItemsObject itemsObject = mListItems.get(position); if (itemsObject == null){ return; } holder.txtTitle.setText(itemsObject.getTitle()); holder.txtContent.setText(itemsObject.getContent()); holder.foldingCell.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holder.foldingCell.toggle(false); } }); } @Override public int getItemCount() { if (mListItems != null){ return mListItems.size(); } return 0; } public class ItemViewHolder extends RecyclerView.ViewHolder { FoldingCell foldingCell; TextView txtTitle; TextView txtContent; public ItemViewHolder(@NonNull View itemView) { super(itemView); foldingCell = itemView.findViewById(R.id.folding_cell); txtTitle = itemView.findViewById(R.id.tv_title); txtContent = itemView.findViewById(R.id.tv_content); } } }
问题原因
- DiaryLogFragment仅在创建时读取一次数据:它只在
onCreateView里执行了一次数据库查询,之后数据库数据更新时,没有重新获取数据并通知适配器刷新。 - Room普通查询无监听能力:当前DAO的
getListUser()是单次查询,不会主动告知应用数据已变化。
解决方法
方法一:用Room+LiveData实现自动监听(官方推荐)
LiveData是Jetpack组件,能自动感知生命周期,数据变化时自动通知UI更新,步骤如下:
- 修改DAO接口,将查询方法返回类型改为
LiveData<List<ItemsObject>>:
@Dao public interface UserDAO { @Insert void insert(ItemsObject itemsObject); // 改为返回LiveData @Query("SELECT * FROM items_table") LiveData<List<ItemsObject>> getListUser(); }
- 修改DiaryLogFragment,观察LiveData的变化:
public class DiaryLogFragment extends Fragment { View mView; private RecyclerView rcvItems; private ItemsAdapter itemsAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.fragment_diary_log, container, false); rcvItems = mView.findViewById(R.id.rcv_items); itemsAdapter = new ItemsAdapter(); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); rcvItems.setLayoutManager(linearLayoutManager); rcvItems.setFocusable(true); rcvItems.setAdapter(itemsAdapter); // 观察LiveData,数据变化时自动更新Adapter DiaryDatabase.getInstance(getActivity()).userDAO().getListUser() .observe(getViewLifecycleOwner(), itemsObjects -> { itemsAdapter.setData(itemsObjects); }); return mView; } }
这样,当数据库里新增数据时,LiveData会自动把新列表推送给Fragment,Adapter就会刷新显示新数据。
方法二:手动通知数据更新(适合简单场景)
如果暂时不想用LiveData,可以在保存数据后手动触发DiaryLogFragment刷新:
- 在MainActivity定义通信接口:
public interface OnDataUpdatedListener { void onDataUpdated(); }
- 让DiaryLogFragment实现接口:
public class DiaryLogFragment extends Fragment implements OnDataUpdatedListener { // ... 原有代码 ... @Override public void onDataUpdated() { // 重新查询数据库并更新Adapter List<ItemsObject> newList = DiaryDatabase.getInstance(getActivity()).userDAO().getListUser(); itemsAdapter.setData(newList); } // ... 原有代码 ... }
- 在WriteFragment保存数据后调用接口:
private void addItems() { // ... 原有代码 ... MainActivity.diaryDatabase.getInstance(getActivity()).userDAO().insert(itemsObject); Toast.makeText(getActivity(),"Successfully Added",Toast.LENGTH_SHORT).show(); // 通知数据更新 if (getActivity() instanceof OnDataUpdatedListener) { ((OnDataUpdatedListener) getActivity()).onDataUpdated(); } // ... 原有代码 ... }
注意:方法二需要处理Fragment不在前台的情况(比如用户在Tab1保存数据后没切到Tab2),而方法一的LiveData会自动处理,更稳定。
内容的提问来源于stack exchange,提问作者ThankYouCamOnGraciasXieXie
相关产品推荐
相关产品推荐

