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

如何在Room DB+MVVM架构下用Executors获取插入数据ID

Room+MVVM架构下获取插入数据自增ID及异步查询实现方案

一、修改StudentDao,支持返回自增ID与单条查询

首先调整Dao层的插入方法,使其返回自动生成的ID,并添加根据ID查询学生的方法:

@Dao
public interface StudentDao {

    @Insert
    long insert(Student student); // 修改为返回long类型的自增ID

    @Update
    void update(Student student);

    @Delete
    void delete(Student student);

    @Query("DELETE FROM students_table")
    void deleteAll();

    @Query("SELECT * FROM students_table ORDER BY name, father_name COLLATE NOCASE")
    LiveData<List<Student>> getAll();

    // 添加根据ID查询单条学生数据的方法
    @Query("SELECT * FROM students_table WHERE id = :studentId")
    Student getStudentById(long studentId);
}

二、在Repository中实现异步回调机制

由于Executors.execute()是异步执行的,无法直接返回结果,因此需要通过回调接口来传递异步操作的结果:

  1. 在StudentsRepo中定义回调接口并修改相关方法:
package ask2784.studentsdetails;

import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import androidx.lifecycle.LiveData;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class StudentsRepo {
    private StudentDao studentDao;
    private LiveData<List<Student>> allStudents;
    private Executor service = Executors.newSingleThreadExecutor();

    // 插入结果回调接口
    public interface InsertCallback {
        void onInsertSuccess(long insertedId);
        void onInsertFailed(Exception e);
    }

    // 单条学生查询回调接口
    public interface GetStudentCallback {
        void onStudentLoaded(Student student);
        void onLoadFailed(Exception e);
    }

    public StudentsRepo(Application application) {
        StudentsDatabase db = StudentsDatabase.getInstance(application.getApplicationContext());
        studentDao = db.studentDao();
        allStudents = studentDao.getAll();
    }

    // 修改插入方法,通过回调返回自增ID
    public void insert(Student student, InsertCallback callback) {
        service.execute(() -> {
            try {
                long insertedId = studentDao.insert(student);
                // 切换回主线程回调结果(确保UI操作安全)
                new Handler(Looper.getMainLooper()).post(() -> callback.onInsertSuccess(insertedId));
            } catch (Exception e) {
                new Handler(Looper.getMainLooper()).post(() -> callback.onInsertFailed(e));
            }
        });
    }

    // 实现根据ID查询学生的异步方法
    public void getStudentById(long studentId, GetStudentCallback callback) {
        service.execute(() -> {
            try {
                Student student = studentDao.getStudentById(studentId);
                new Handler(Looper.getMainLooper()).post(() -> callback.onStudentLoaded(student));
            } catch (Exception e) {
                new Handler(Looper.getMainLooper()).post(() -> callback.onLoadFailed(e));
            }
        });
    }

    // 保留原有其他方法
    public void update(Student student) {
        service.execute(() -> studentDao.update(student));
    }

    public void delete(Student student) {
        service.execute(() -> studentDao.delete(student));
    }

    public void deleteAllStudents() {
        service.execute(() -> studentDao.deleteAll());
    }

    public LiveData<List<Student>> getAllStudents() {
        return allStudents;
    }
}

三、更新ViewModel层,传递回调接口

调整StudentViewModel,让其暴露带回调的插入和查询方法:

import android.app.Application;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.List;

public class StudentViewModel extends AndroidViewModel {
    private StudentsRepo repo;
    private LiveData<List<Student>> allStudents;

    public StudentViewModel(Application application) {
        super(application);
        repo = new StudentsRepo(application);
        allStudents = repo.getAllStudents();
    }

    // 带回调的插入方法
    public void insert(Student student, StudentsRepo.InsertCallback callback) {
        repo.insert(student, callback);
    }

    // 带回调的单条查询方法
    public void getStudentById(long studentId, StudentsRepo.GetStudentCallback callback) {
        repo.getStudentById(studentId, callback);
    }

    // 保留原有其他方法
    public void update(Student student) {
        repo.update(student);
    }

    public void delete(Student student) {
        repo.delete(student);
    }

    public void deleteAllStudents() {
        repo.deleteAllStudents();
    }

    public LiveData<List<Student>> getAllStudents() {
        return allStudents;
    }
}

四、在UI层(Activity/Fragment)中使用

在界面代码中调用ViewModel的方法,通过回调获取结果:

// 示例:插入新学生并获取自增ID
Student newStudent = new Student("张三", "张建国", "三年级二班");
studentViewModel.insert(newStudent, new StudentsRepo.InsertCallback() {
    @Override
    public void onInsertSuccess(long insertedId) {
        // 成功获取自增ID,执行后续操作
        Toast.makeText(MainActivity.this, "插入成功,学生ID:" + insertedId, Toast.LENGTH_SHORT).show();
        
        // 可选:用刚获取的ID查询该学生
        studentViewModel.getStudentById(insertedId, new StudentsRepo.GetStudentCallback() {
            @Override
            public void onStudentLoaded(Student student) {
                // 处理查询到的学生数据
            }

            @Override
            public void onLoadFailed(Exception e) {
                // 处理查询失败逻辑
                Toast.makeText(MainActivity.this, "查询失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onInsertFailed(Exception e) {
        // 处理插入失败逻辑
        Toast.makeText(MainActivity.this, "插入失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }
});

关键说明

  • 不能直接从Executors.execute()中返回值的原因:该方法是在子线程异步执行的,主线程调用方法时,子线程的数据库操作尚未完成,直接返回会得到无效结果。
  • 使用Handler(Looper.getMainLooper())切换回主线程:确保回调中的UI操作(如Toast、更新界面)在主线程执行,避免线程异常。

内容的提问来源于stack exchange,提问作者Arvind Kaushik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:38:12