Android中Room数据库与RecyclerView数据不显示问题求助
我的App中,用户可通过DatePicker输入日期,点击按钮后计算该日期与SharedPreferences中存储日期的差值,将相关的三个字符串存入Room数据库。完成后启动另一Activity,通过RecyclerView展示数据库中的所有对象。但当前RecyclerView无任何内容显示,且无报错信息,同一数据库的另一张表通过RecyclerView展示正常。
相关代码
日期输入与保存的Activity
public class NeuePeriodeActivity extends AppCompatActivity { private ActivityNeuePeriodeBinding binding; Zyklen zyklus; String laengeDb; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityNeuePeriodeBinding.inflate(getLayoutInflater()); View view = binding.getRoot(); setContentView(view); binding.btnSpeichern.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { neuePeriodeVorbereiten(); finish(); } }); } private View.OnClickListener neuePeriodeVorbereiten() { SharedPreferences prefs = getApplicationContext().getSharedPreferences("SharedPrefs", Context.MODE_PRIVATE); int tag = binding.datepickerNeuePeriode.getDayOfMonth(); String monatStrFertig; String tagStrFertig; String jahr = Integer.toString(binding.datepickerNeuePeriode.getYear()); int monat = binding.datepickerNeuePeriode.getMonth(); monat += 1; if(tag<10){ String tagStr = Integer.toString(tag); tagStrFertig = "0"+tagStr; }else{ tagStrFertig = Integer.toString(tag); } if(monat<10){ String monatStr = Integer.toString(monat); monatStrFertig = "0"+monatStr; }else{ monatStrFertig = Integer.toString(monat); } String aktuellePeriode = tagStrFertig+"-"+monatStrFertig+"-"+jahr; zyklusLaengeAusrechnen(aktuellePeriode, prefs); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); String letztePeriode = prefs.getString("letztePeriode", ""); LocalDate date1 = parse(letztePeriode, formatter); LocalDate date2 = parse(aktuellePeriode, formatter); date2 = date2.minusDays(1); DateTimeFormatter df = DateTimeFormatter.ofPattern("dd-MM-yyyy"); zyklus = new Zyklen(); zyklus.setLaenge(laengeDb); zyklus.setStart(df.format(date1)); zyklus.setEnde(df.format(date2)); Intent intent = new Intent(NeuePeriodeActivity.this, ZusammenfassungActivity.class); intent.putExtra("zyklus", zyklus); setResult(Activity.RESULT_OK, intent); neuePeriodeInPrefsSpeichern(aktuellePeriode, prefs); return null; } private String zyklusLaengeAusrechnen(String neuePeriode, SharedPreferences prefs) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); String letztePeriode = prefs.getString("letztePeriode", ""); int laenge = Integer.parseInt(prefs.getString("laenge", "")); LocalDate date1 = parse(letztePeriode, formatter); LocalDate date2 = parse(neuePeriode, formatter); long differenz = ChronoUnit.DAYS.between(date1, date2.plusDays(1)); laengeDb = Long.toString(differenz); int differenzKonvertiert = Long.valueOf(differenz).intValue(); int durchschnitt = (differenzKonvertiert+laenge)/2; String fertigeLaenge = String.valueOf(durchschnitt); SharedPreferences.Editor editor = prefs.edit(); editor.putString("laenge", fertigeLaenge); editor.commit(); return laengeDb; } public void neuePeriodeInPrefsSpeichern(String letztePeriode, SharedPreferences prefs) { SharedPreferences.Editor editor = prefs.edit(); editor.putString("letztePeriode", letztePeriode); editor.commit(); } }
展示数据的Activity
public class ZusammenfassungActivity extends AppCompatActivity { private ActivityZusammenfassungBinding binding; RoomDB database_zyklen; ZyklenListeAdapter zyklenListeAdapter; List<Zyklen> zyklen = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityZusammenfassungBinding.inflate(getLayoutInflater()); View view = binding.getRoot(); setContentView(view); database_zyklen = RoomDB.getInstance(this); zyklen = database_zyklen.zyklenDao().getAll(); updateRecycler(zyklen); binding.buttonTagebuch.setOnClickListener(view1 -> { Intent tagebuchActivity = new Intent(ZusammenfassungActivity.this, TagebuchActivity.class); startActivity(tagebuchActivity); }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 101){ if(resultCode== Activity.RESULT_OK){ Zyklen neuerZyklus = (Zyklen) data.getSerializableExtra("zyklus"); database_zyklen.zyklenDao().insert(neuerZyklus); zyklen.clear(); zyklen.addAll(database_zyklen.zyklenDao().getAll()); zyklenListeAdapter.notifyDataSetChanged(); } } } private void updateRecycler(List<Zyklen> zyklen) { binding.recyclerviewZyklen.setHasFixedSize(true); binding.recyclerviewZyklen.setLayoutManager(new LinearLayoutManager(this)); zyklenListeAdapter = new ZyklenListeAdapter(ZusammenfassungActivity.this, zyklen); binding.recyclerviewZyklen.setAdapter(zyklenListeAdapter); } }
RecyclerView适配器
public class ZyklenListeAdapter extends RecyclerView.Adapter<ZyklenViewHolder> { Context context; List<Zyklen> liste; public ZyklenListeAdapter(Context context, List<Zyklen> liste){ this.context = context; this.liste = liste; } @NonNull @Override public ZyklenViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new ZyklenViewHolder(LayoutInflater.from(context).inflate(R.layout.zyklen_liste, parent, false)); } @Override public void onBindViewHolder(@NonNull ZyklenViewHolder holder, int position) { holder.textview_beschreibung.setText(liste.get(position).getStart()+" - "+liste.get(position).getStart()+", "+liste.get(position).getLaenge()+" Tage"); } @Override public int getItemCount() { return liste.size(); } } class ZyklenViewHolder extends RecyclerView.ViewHolder{ CardView cardview_zyklencontainer; TextView textview_beschreibung; public ZyklenViewHolder(@NonNull View itemView) { super(itemView); cardview_zyklencontainer = itemView.findViewById(R.id.cardview_zyklencontainer); textview_beschreibung = itemView.findViewById(R.id.textview_beschreibung); } }
排查与修复方案
1. 核心问题:数据未插入数据库
你当前的逻辑是把Zyklen对象通过Intent传递给ZusammenfassungActivity,但只有当ZusammenfassungActivity通过startActivityForResult启动NeuePeriodeActivity时,onActivityResult才会触发并插入数据。如果是直接启动NeuePeriodeActivity,数据根本不会存入数据库。
修复方式二选一:
- 方式一:在
NeuePeriodeActivity中直接插入数据库:
在neuePeriodeVorbereiten方法里,创建Zyklen对象后,直接获取Room实例插入:zyklus = new Zyklen(); zyklus.setLaenge(laengeDb); zyklus.setStart(df.format(date1)); zyklus.setEnde(df.format(date2)); // 新增:直接插入数据库 RoomDB.getInstance(this).zyklenDao().insert(zyklus); - 方式二:确保用
startActivityForResult启动NeuePeriodeActivity:
在ZusammenfassungActivity中添加启动代码:// 比如添加一个按钮点击事件启动NeuePeriodeActivity binding.btnAddPeriode.setOnClickListener(v -> { Intent intent = new Intent(ZusammenfassungActivity.this, NeuePeriodeActivity.class); startActivityForResult(intent, 101); });
2. 主线程执行Room查询的问题
database_zyklen.zyklenDao().getAll()是同步查询,直接在主线程调用会违反Room的线程规则(默认不允许主线程执行查询),可能导致查询被静默拦截,返回空列表。
修复:把Dao的查询改为异步,推荐用LiveData:
- 修改Dao接口:
@Dao public interface ZyklenDao { @Insert void insert(Zyklen zyklen); @Query("SELECT * FROM zyklen") LiveData<List<Zyklen>> getAll(); } - 在
ZusammenfassungActivity中观察数据变化:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... 其他初始化代码 database_zyklen = RoomDB.getInstance(this); // 观察LiveData,数据变化时更新RecyclerView database_zyklen.zyklenDao().getAll().observe(this, zyklenList -> { zyklen.clear(); zyklen.addAll(zyklenList); zyklenListeAdapter.notifyDataSetChanged(); }); updateRecycler(zyklen); }
3. 适配器文本拼接错误
在ZyklenListeAdapter的onBindViewHolder中,你重复使用了getStart(),应该替换为getEnde(),否则显示的日期范围是重复的:
holder.textview_beschreibung.setText(liste.get(position).getStart()+" - "+liste.get(position).getEnde()+", "+liste.get(position).getLaenge()+" Tage");
4. 处理SharedPreferences初始值异常
zyklusLaengeAusrechnen方法中,Integer.parseInt(prefs.getString("laenge", ""))如果laenge没有初始值,会抛出NumberFormatException,建议设置默认值:
int laenge = Integer.parseInt(prefs.getString("laenge", "28"));
5. 处理首次使用时的空日期解析
当用户第一次使用App时,letztePeriode是空字符串,LocalDate.parse会抛出异常,建议添加判断:
String letztePeriode = prefs.getString("letztePeriode", ""); if (!letztePeriode.isEmpty()) { LocalDate date1 = LocalDate.parse(letztePeriode, formatter); LocalDate date2 = LocalDate.parse(aktuellePeriode, formatter); date2 = date2.minusDays(1); DateTimeFormatter df = DateTimeFormatter.ofPattern("dd-MM-yyyy"); zyklus = new Zyklen(); zyklus.setLaenge(laengeDb); zyklus.setStart(df.format(date1)); zyklus.setEnde(df.format(date2)); // 插入数据库或传递数据 } else { // 首次使用,提示用户设置初始日期,或者跳过本次周期计算 Toast.makeText(this, "请先设置初始周期日期", Toast.LENGTH_SHORT).show(); }
内容的提问来源于stack exchange,提问作者Chig Bungus

