Fragment中submitList加载Room数据后RecyclerView无显示问题
问题描述
运行应用后RecyclerView显示为空,日志中ItemCountOUTSIDE先输出且值为0,ItemCount后输出值为2(数据库内确实存在2条数据)。已确认Room数据库和ViewModel能正常获取数据(用同一个观察者可在TextView中显示数据),知晓观察者在独立线程执行导致滞后,但不清楚解决办法。
相关代码
Fragment代码
import android.content.Context; import android.content.Intent; import android.content.pm.LauncherActivityInfo; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; public class Frag1 extends Fragment { CustomViewModel viewModel; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.frag1_layout, container, false); viewModel = new ViewModelProvider(this).get(CustomViewModel.class); RecyclerView recyclerView = rootView.findViewById(R.id.rv1); final Adapter adapter = new Adapter(new Adapter.Diff()); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); viewModel.show().observe(getViewLifecycleOwner(), rEnts -> { adapter.submitList(rEnts); Log.d("ItemCount", String.valueOf(adapter.getItemCount())); }); Log.d("ItemCountOUTSIDE", String.valueOf(adapter.getItemCount())); return rootView; } }
Holder代码
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 org.w3c.dom.Text; public class Holder extends RecyclerView.ViewHolder { private final TextView textView; private Holder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.textName); } public void bind(rEnt E){ textView.setText(E.rN); } static Holder create(ViewGroup parent){ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv1_item, parent, false); return new Holder(view); } }
Adapter代码
import android.util.Log; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.ListAdapter; import androidx.recyclerview.widget.RecyclerView; import androidx.room.Query; import java.util.List; public class Adapter extends ListAdapter<rEnt, Holder> { List<rEnt> myList = getCurrentList(); public Adapter(@NonNull DiffUtil.ItemCallback<rEnt> diffCB){ super(diffCB); } @NonNull @Override public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return Holder.create(parent); } @Override public void onBindViewHolder(@NonNull Holder holder, int position) { rEnt currentEnt = getItem(position); holder.bind(currentEnt); } static class Diff extends DiffUtil.ItemCallback<rEnt>{ @Override public boolean areItemsTheSame(@NonNull rEnt oldItem, @NonNull rEnt newItem) { return oldItem.getId() == newItem.getId(); } @Override public boolean areContentsTheSame(@NonNull rEnt oldItem, @NonNull rEnt newItem) { return oldItem.rN.equals(newItem.rN); } } }
解决方法
你的核心逻辑没问题,submitList会自动通知RecyclerView更新,空列表问题大概率是细节疏漏导致,按以下步骤排查:
修正DiffUtil的ID比较逻辑
如果rEnt的主键id是Long类型,不能用==比较(自动装箱会导致对象地址判断错误),改成equals:@Override public boolean areItemsTheSame(@NonNull rEnt oldItem, @NonNull rEnt newItem) { return oldItem.getId().equals(newItem.getId()); }检查Item布局高度
打开rv1_item.xml,确认根布局高度是wrap_content或固定值,若设为match_parent会导致item被挤压无法显示。移除无效的列表变量
Adapter中List<rEnt> myList = getCurrentList();这行是在构造时初始化,后续submitList更新后该变量不会同步,直接删除即可,需要列表时用getCurrentList()或getItem(position)获取最新数据。验证观察者生命周期
你已经使用getViewLifecycleOwner()绑定观察者,这是正确的,确保Fragment视图销毁时自动解绑,避免内存泄漏。
另外,日志中ItemCountOUTSIDE先输出是正常现象——Room数据库查询是异步操作,观察者回调要等查询完成才会执行,无需额外处理,只要submitList调用后RecyclerView能自动更新即可。如果以上步骤都排查过仍无效果,可以在submitList后临时添加adapter.notifyDataSetChanged()强制刷新(ListAdapter的submitList本应自动处理,这只是排查手段)。
内容的提问来源于stack exchange,提问作者novykovd

