You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Room数据库与RecyclerView数据不显示问题求助

问题: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 09:17:05