Android Firebase数据加载完成后ProgressBar无法隐藏问题
问题原因
你的ProgressBar加载完成后无法隐藏是两个核心错误导致的:
- 控件查找逻辑位置错误:你的ProgressBar定义在Activity的根布局中,但你在RecyclerView子项的ViewHolder中调用
itemView.findViewById(R.id.progress_bar)查找控件,itemView对应的是列表单个条目布局circular_item,这个布局里根本没有id为progress_bar的控件,所以适配器里的progressBar变量始终为null,后续的隐藏逻辑永远不会触发。 - 职责划分错误:适配器只负责管理RecyclerView子项的视图渲染,不应该直接操作Activity层级的全局加载控件,这种写法耦合度高,很容易出现空指针问题。
修复步骤
1. 清理适配器中的无效代码
打开CAdapter.java,删除所有和ProgressBar相关的错误代码:
- 删除类成员变量声明
ProgressBar progressBar; - 删除myViewHolder构造方法中的
progressBar = itemView.findViewById(R.id.progress_bar); - 删除原来写在适配器中的
onDataChanged()方法里操作progressBar的逻辑
清理后适配器核心代码结构如下:
public class CAdapter extends FirebaseRecyclerAdapter<Cmodel,CAdapter.myViewHolder> { public CAdapter(@NonNull FirebaseRecyclerOptions<Cmodel> options) { super(options); } @Override protected void onBindViewHolder(@NonNull myViewHolder holder, int position, @NonNull Cmodel model) { holder.Cdate.setText(model.getCdate()); holder.Cheading.setText(model.getCheading()); holder.Cbody.setText(model.getCbody()); } @NonNull @Override public myViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.circular_item,parent,false); return new myViewHolder(view); } class myViewHolder extends RecyclerView.ViewHolder{ TextView Cdate,Cheading,Cbody,Ndate,Nheading,Nsheading,Nbody,Tdate,Tsubject,Ttopic,Ttdate; public myViewHolder(@NonNull View itemView) { super(itemView); Cdate = itemView.findViewById(R.id.cdate); Cheading = itemView.findViewById(R.id.cheading); Cbody = itemView.findViewById(R.id.cbody); } } }
2. 在Activity中实现加载完成隐藏逻辑
把ProgressBar的控制逻辑放到对应的Activity(你的布局中tools:context配置的是.CircularAct)中处理:
- 在Activity中初始化ProgressBar控件
- 给适配器注册数据变化监听,数据加载完成后隐藏ProgressBar
- 正确管理Firebase适配器的监听生命周期
参考代码如下:
public class CircularAct extends AppCompatActivity { private ProgressBar progressBar; private CAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 替换为你实际的布局文件名 // 初始化控件 RecyclerView rv = findViewById(R.id.rv); progressBar = findViewById(R.id.progress_bar); // 配置Firebase查询选项(替换为你自己的查询逻辑) FirebaseRecyclerOptions<Cmodel> options = new FirebaseRecyclerOptions.Builder<Cmodel>() .setQuery(/* 你的Firebase Database查询引用 */, Cmodel.class) .build(); adapter = new CAdapter(options); rv.setLayoutManager(new LinearLayoutManager(this)); // 必须给RecyclerView设置LayoutManager,否则列表不会显示 rv.setAdapter(adapter); // 监听数据加载状态 adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { @Override public void onChanged() { super.onChanged(); progressBar.setVisibility(View.GONE); } }); } @Override protected void onStart() { super.onStart(); adapter.startListening(); // 开始监听Firebase数据变化 } @Override protected void onStop() { super.onStop(); adapter.stopListening(); // 页面不可见时停止监听,避免内存泄漏 } }
可选方案:如果要在适配器内处理隐藏逻辑
如果不想在Activity里写监听,可以给适配器增加构造方法,把Activity里的ProgressBar实例传进来,再重写onDataChanged方法:
// 适配器修改构造方法 public class CAdapter extends FirebaseRecyclerAdapter<Cmodel,CAdapter.myViewHolder> { private ProgressBar progressBar; public CAdapter(@NonNull FirebaseRecyclerOptions<Cmodel> options, ProgressBar progressBar) { super(options); this.progressBar = progressBar; } // 其他onCreateViewHolder、onBindViewHolder、ViewHolder代码不变,重写onDataChanged @Override public void onDataChanged() { super.onDataChanged(); if (progressBar != null) { progressBar.setVisibility(View.GONE); } } }
然后在Activity初始化适配器的时候传入progressBar实例即可:adapter = new CAdapter(options, progressBar);
更推荐把视图控制逻辑放在Activity中,避免适配器持有控件引用导致的内存泄漏风险。
内容的提问来源于stack exchange,提问作者Gr8 BEAST
相关产品推荐
相关产品推荐

