Firebase数据存入成功但RecyclerView无内容显示问题求助
RecyclerView显示空白排查(Firebase数据已存储成功)
我是Android Studio新手,点击浮动操作按钮录入新数据后,数据已成功存储到Firebase数据库,且收到“budget item added successfully”的提示,应用未崩溃,但RecyclerView显示空白。以下是相关的Activity类和Adapter类代码,恳请帮忙排查问题:
Activity类代码
public class TodaySpendingActivity extends AppCompatActivity { private Toolbar toolbar; private TextView totalAmountSpentOn; private ProgressBar progressBar; private RecyclerView recyclerView; private FloatingActionButton fab; private ProgressDialog loader; private FirebaseAuth mAuth; private String onlineUserId = ""; private DatabaseReference expensesRef; private TodayItemAdapter todayItemAdapter; private List<Data> myDataList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_daily_spending); toolbar = findViewById(R.id.toolbar); setSupportActionBar((androidx.appcompat.widget.Toolbar)toolbar); getSupportActionBar().setTitle("Today's Spending"); totalAmountSpentOn = findViewById(R.id.totalAmountSpentOn); progressBar = findViewById(R.id.progressBar); fab = findViewById(R.id.fab); loader = new ProgressDialog(this); mAuth = FirebaseAuth.getInstance(); onlineUserId = mAuth.getCurrentUser().getUid(); expensesRef = FirebaseDatabase.getInstance().getReference("expenses").child(onlineUserId); recyclerView = findViewById(R.id.recyclerView); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setStackFromEnd(true); linearLayoutManager.setReverseLayout(true); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(linearLayoutManager); myDataList = new ArrayList<>(); todayItemAdapter = new TodayItemAdapter( TodaySpendingActivity.this, myDataList); recyclerView.setAdapter(todayItemAdapter); readItems(); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { addItemSpentOn(); } private void addItemSpentOn() { AlertDialog.Builder myDialog = new AlertDialog.Builder(TodaySpendingActivity.this); LayoutInflater inflater = LayoutInflater.from(TodaySpendingActivity.this); View myView = inflater.inflate(R.layout.input_layout, null); myDialog.setView(myView); final AlertDialog dialog = myDialog.create(); dialog.setCancelable(false); final Spinner itemSpinner = myView.findViewById(R.id.itemspinner); final EditText amount = myView.findViewById(R.id.amount); final EditText note = myView.findViewById(R.id.note); final Button cancel = myView.findViewById(R.id.cancel); final Button save = myView.findViewById(R.id.save); note.setVisibility(View.VISIBLE); save.setOnClickListener(view -> { String Amount = amount.getText().toString(); String Item = itemSpinner.getSelectedItem().toString(); String notes = note.getText().toString(); if(TextUtils.isEmpty(Amount)){ amount.setError("Please input an amount!"); return; } if (Item.equals("Select item")){ Toast.makeText(TodaySpendingActivity.this,"Select a valid item", Toast.LENGTH_SHORT).show(); } if (TextUtils.isEmpty(notes)){ note.setError("Note is Requires"); return; } else { loader.setMessage("Adding a budget item"); loader.setCanceledOnTouchOutside(false); loader.show(); String id = expensesRef.push().getKey(); DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); Calendar cal = Calendar.getInstance(); String date = dateFormat.format(cal.getTime()); MutableDateTime epoch = new MutableDateTime(); epoch.setDate(0); DateTime now = new DateTime(); Months months = Months.monthsBetween(epoch, now); Data data = new Data(Item, date, id, notes, Integer.parseInt(Amount), months.getMonths()); expensesRef.child(id).setValue(data).addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { Toast.makeText(TodaySpendingActivity.this, "Budget item added successfully", Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(TodaySpendingActivity.this, task.getException().toString(), Toast.LENGTH_SHORT).show(); } loader.dismiss(); } }); } dialog.dismiss(); }); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dialog.dismiss(); } }); dialog.show(); } }); } private void readItems() { Query query = expensesRef.orderByChild("month").equalTo(new DateTime().getMonthOfYear()); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { myDataList.clear(); for (DataSnapshot ds: snapshot.getChildren()){ Data data = ds.getValue(Data.class); myDataList.add(data); } todayItemAdapter.notifyDataSetChanged(); progressBar.setVisibility(View.GONE); int totalAmount = 0; for (int i = 0; i < myDataList.size(); i++){ totalAmount += myDataList.get(i).getAmount(); String stTotal = String.valueOf(totalAmount); totalAmountSpentOn.setText(stTotal); } } @Override public void onCancelled(@NonNull DatabaseError error) { } }); } }
Adapter类代码
public class TodayItemAdapter extends RecyclerView.Adapter<TodayItemAdapter.ViewHolder>{ private Context mContext; private List<Data> myDataList; private String post_key= ""; private String item= ""; private String note=""; private int amount = 0; public TodayItemAdapter(Context mContext, List<Data> myDataList) { this.mContext = mContext; this.myDataList = myDataList; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.retrieve_layout, parent, false); return new TodayItemAdapter.ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { final Data data = myDataList.get(position); holder.item.setText("Item: "+ data.getItem()); holder.amount.setText("Amount: "+ data.getAmount()); holder.date.setText("On: "+ data.getDate()); holder.note.setText("Note: "+ data.getNotes()); switch (data.getItem()){ case "Transport": holder.imageView.setImageResource(R.drawable.ic_transport); break; case "Food": holder.imageView.setImageResource(R.drawable.ic_food); break; case "House": holder.imageView.setImageResource(R.drawable.ic_house); break; case "Entertainment": holder.imageView.setImageResource(R.drawable.ic_entertainment); break; case "Education": holder.imageView.setImageResource(R.drawable.ic_education); break; case "Charity": holder.imageView.setImageResource(R.drawable.ic_charity); break; case "Clothing": holder.imageView.setImageResource(R.drawable.ic_clothing); break; case "Health": holder.imageView.setImageResource(R.drawable.ic_health); break; case "Personal": holder.imageView.setImageResource(R.drawable.ic_personal); break; case "Other": holder.imageView.setImageResource(R.drawable.ic_other); break; } } @Override public int getItemCount() { return myDataList.size(); } public class ViewHolder extends RecyclerView.ViewHolder{ public TextView item, amount, date, note; public ImageView imageView; public ViewHolder(@NonNull View itemView) { super(itemView); item = itemView.findViewById(R.id.item); amount = itemView.findViewById(R.id.amount); date = itemView.findViewById(R.id.date); note = itemView.findViewById(R.id.note); imageView = itemView.findViewById(R.id.imageView); } } }
排查方向及解决建议
月份字段不匹配
存储数据时用Months.monthsBetween(epoch, now).getMonths()计算的是从公元0年到当前的总月数(数值极大),但查询时用new DateTime().getMonthOfYear()获取的是1-12的当月序号,两者完全不匹配,导致查询无结果。- 修正:存储和查询统一用当月序号,同时增加年份判断避免跨年度数据干扰。比如存储时记录
new DateTime().getYear()和new DateTime().getMonthOfYear(),查询时同时匹配年份和月份。
- 修正:存储和查询统一用当月序号,同时增加年份判断避免跨年度数据干扰。比如存储时记录
Data类序列化问题
Firebase反序列化需要Data类具备无参构造函数,且所有字段的getter/setter方法完整实现。如果缺少无参构造,ds.getValue(Data.class)会返回null,导致列表为空。Firebase权限设置
检查数据库规则,确认当前用户拥有expenses/{userId}路径的读取权限。权限不足会导致查询返回空快照。布局文件问题
- 检查
retrieve_layout根布局高度是否为wrap_content,若设为match_parent会导致单个item占满屏幕,视觉上显示空白。 - 确认
activity_daily_spending中的RecyclerView未被其他控件遮挡,且宽高设置正确。
- 检查
内容的提问来源于stack exchange,提问作者nephilimzeus
相关产品推荐
相关产品推荐

