房间数据库和视图模型如何工作?

How room database and viewmodel works?

我有一个students_table,存储了不同级别的学生。我想按一个级别显示学生并隐藏其他级别。 我select学生这样显示:

    if (id == R.id.beginners) {
        stLvl = 0;
    }else if (id == R.id.intermediate) {
        stLvl = 1;
    }else if (id == R.id.advanced) {
        stLvl = 2;
    }else if (id == R.id.high_level) {
        stLvl = 3;
    }

    showStud();

这里是showStud();

public void showStud() {

    RecyclerView recyclerView = findViewById(R.id.recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setHasFixedSize(true);

    final StudentAdapter adapter = new StudentAdapter();
    recyclerView.setAdapter(adapter);

    setStLvl(stLvl);

    if (stLvl == 0) {

        studentViewModel = ViewModelProviders.of(this).get(StudentViewModel.class);

        studentViewModel.getAllStudents().observe(this, new Observer<List<Student>>() {
            @Override
            public void onChanged(@Nullable List<Student> students) {
                // update RecyclerView
                adapter.submitList(students);
            }
        });

    }else {

        studentViewModel = ViewModelProviders.of(this).get(StudentViewModel.class);

        studentViewModel.getStudentsByLevel().observe(this, new Observer<List<Student>>() {
            @Override
            public void onChanged(@Nullable List<Student> students) {
                // update RecyclerView
                adapter.submitList(students);
            }
        });

    }
}

第一次当代码 运行 工作完美时,无论 stLvl 的值如何,但是当我更改它的值时,它的值没有显示我想要的,或者根本没有显示。 我认为问题出在这一行:

studentViewModel = ViewModelProviders.of(this).get(StudentViewModel.class);

第一次 运行s,它工作正常,去 StudentViewModel.class 做应该做的,但第二次只是跳到下一行代码,没有去 StudentViewModel.class。 我究竟做错了什么?提前致谢!

是的,你是对的,事实上我是 android 编程的初学者。这是 StudentViewModel:

private StudentRepository repository;

private LiveData<List<Student>> allStudents;

private LiveData<List<Student>> studentsByLevel;

public StudentViewModel(@NonNull Application application) {
    super(application);
    repository = new StudentRepository(application);

    int stLevel = 0;
    studentsByLevel = repository.getStudentsByLevel(stLevel);
    allStudents = repository.getAllStudents();
}

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

public LiveData<List<Student>> getStudentsByLevel() {
    return studentsByLevel;
}

学生资料库:

private StudentDao studentDao;
private LiveData<List<Student>> allStudents;

private LiveData<List<Student>> studentsByLevel;

public int stLevel;

public void setStLvl() {
    MainActivity mainActivity = new MainActivity();
    stLevel = mainActivity.getStLvl();
}

public StudentRepository(Application application) {
    AppDatabase database = AppDatabase.getInstance(application);
    studentDao = database.studentDao();


    setStLvl();
    studentsByLevel = studentDao.getStudentsByLevel(stLevel);

    allStudents = studentDao.getAllStudents();
}
.
.
.
public LiveData<List<Student>> getAllStudents() {
    return allStudents;
}
public LiveData<List<Student>> getStudentsByLevel(int stLevel) {
    return studentsByLevel;
}

在 StudentDao 中我有:

@Query("SELECT * FROM student_table WHERE level = :level")
LiveData<List<Student>> getStudentsByLevel(int level);

希望我提供了足够的数据。

首先,阅读本文 Guide to app architecture 将帮助您大致了解这些体系结构组件应如何协同工作。经验法则是,

each component depends only on the component one level below it.

这也意味着每个组件不应该依赖于它上面的组件。例如,存储库不应依赖于 ViewModel 或 Activity。您的代码可以这样重构:

学生资料库:

private StudentDao studentDao;

// public int stLevel; 

// public void setStLvl() {  // Do not read view components. Do not store their states.
//     MainActivity mainActivity = new MainActivity();
//     stLevel = mainActivity.getStLvl();
// }

public StudentRepository(Application application) {
    AppDatabase database = AppDatabase.getInstance(application);
    studentDao = database.studentDao();

    // setStLvl();
}
.
.
.
public LiveData<List<Student>> getAllStudents() {
    return studentDao.getAllStudents();
}

public LiveData<List<Student>> getStudentsByLevel(int stLevel) {
    return studentDao.getStudentsByLevel(stLevel);
}

在上面的示例中,存储库看起来并没有做太多事情,这很正常,因为它下面只有一层,Room。在实际实践中,您可以拥有其他数据源,包括网络客户端和缓存。存储库的工作是抽象所有数据源逻辑。

视图模型:

private MutableLiveData<Integer> studentLevel;  // This will store the student level
private LiveData<List<Student>> studentsByLevel; // This will store the list of students

public StudentViewModel(@NonNull Application application) {
    super(application);
    repository = new StudentRepository(application);

    studentLevel = new MutableLiveData<>();

    // Place your logic inside the ViewModel
    // Change in studentLevel will be reflected to studentsByLevel
    studentsByLevel = Transformations.switchMap(studentLevel, lvl -> {
        if (studentLevel == 0) {
            return repository.getAllStudents();
        } else {
            repository.getStudentsByLevel(stLevel);
        }
    });

    studentLevel.setValue(0) // Set initial student level.
}

.
.
.
public void setStudentLevel(int level) { // Change studentLevel anytime.
    return studentLevel.setValue(level); 
}

public LiveData<List<Student>> getStudentList() {
    return studentsByLevel;
}

我不是 LiveData 的粉丝,但我会这样做。将所有逻辑保留在 ViewModel 中,并使视图层尽可能简单。

最后,Activity:

private StudentViewModel studentViewModel

protected void onCreate(Bundle savedInstanceState) {

    ...

    RecyclerView recyclerView = findViewById(R.id.recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setHasFixedSize(true);

    final StudentAdapter adapter = new StudentAdapter();
    recyclerView.setAdapter(adapter);

    studentViewModel = ViewModelProviders.of(this).get(StudentViewModel.class);
    studentViewModel.observe(this, students -> {
        adapter.submitList(students);
    });

    // studentViewModel.setValue(1) // call this function anywhere you like.
}

以上代码将显示所有学生,因为我们在视图模型中将默认值设置为 0。调用 studentViewModel.setValue(/*any integer*/) 将列表切换到任意级别。