房间数据库和viewmodel如何工作?

时间:2019-02-08 18:10:16

标签: android-room android-database android-viewmodel viewmodelproviders

我有一个students_table,并且存储了不同级别的学生。我想按一个级别显示学生,而隐藏其他级别。 我选择学生显示如下:

    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);

第一次运行,它工作正常,转到StudentViewModel.class来执行应做的工作,但是第二次只是跳转到下一行代码,而无需转到StudentViewModel.class。 我究竟做错了什么?预先谢谢你!

2 个答案:

答案 0 :(得分:0)

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

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;
}

StudentRepository:

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

在StudentDao中,我有:

                io.emit('match-found', {
                    lobbyID: lobby._id,
                    enemyID: enemyLobby._id,
                    matchID: newMatch._id
                });

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

答案 1 :(得分:0)

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

  

每个组件仅取决于其下一级的组件。

这也意味着每个组件都不应依赖于其上方的组件。例如,存储库不应既不依赖于ViewModel,也不依赖于Activity。您的代码可以通过以下方式重构:

StudentRepository:

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。实际上,您可以拥有其他数据源,包括网络客户端和缓存。存储库的工作是抽象所有数据源逻辑。

ViewModel:

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中,并使视图层尽可能简单。

最后,活动:

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.
}

上面的代码将显示所有学生,因为我们在viewmodel中将默认值设置为0。致电studentViewModel.setValue(/*any integer*/),将列表切换到任意级别。