简体   繁体   English

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

[英]How room database and viewmodel works?

I have a students_table and there are stored students of different levels. 我有一个students_table,并且存储了不同级别的学生。 I want to display students by one level and hide other levels. 我想按一个级别显示学生,而隐藏其他级别。 I select student to show like this: 我选择学生显示如下:

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

And here it is 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);
            }
        });

    }
}

First time when the code run it works perfect, no matter the value of stLvl, but when I change it's value is not displaying what I want, or nothing at all. 第一次运行代码时,无论stLvl的值如何,它都能完美运行,但是当我更改代码时,它的值没有显示我想要的东西,或者根本没有显示。 I think the problem is at this line: 我认为问题出在这一行:

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

First time it runs, it is working ok, going to StudentViewModel.class doing what is supposed to do, but second time just jumps to next line of code, without going to StudentViewModel.class. 第一次运行时,它工作正常,转到StudentViewModel.class来执行应做的工作,但是第二次只是跳转到下一行代码,而无需转到StudentViewModel.class。 What am I doing wrong? 我究竟做错了什么? Thank you in advance! 先感谢您!

Yes, you are right, in fact I am a beginner in android programming. 是的,您是对的,实际上我是android编程的初学者。 Here is StudentViewModel: 这是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;
}

StudentRepository: StudentRepository:

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

In StudentDao I have: 在StudentDao中,我有:

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

I hope that I provided enough data. 我希望我提供了足够的数据。

First of all, reading this Guide to app architecture will help you get the general idea of how these architectural components should work together. 首先,阅读本《应用程序体系结构指南》将帮助您大致了解这些体系结构组件应如何协同工作。 The rule of thumb is, 经验法则是

each component depends only on the component one level below it. 每个组件仅取决于其下一级的组件。

This also means that each component should not depend on the components above it. 这也意味着每个组件都不应依赖于其上方的组件。 For example, the repository should not depend on neither ViewModels nor Activities. 例如,存储库不应既不依赖于ViewModel,也不依赖于Activity。 Your code can be refactored in this way: 您的代码可以通过以下方式重构:

StudentRepository: 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);
}

In the above example, the repository looks like it doesn't do much, and that is normal because there is only one layer below it, Room. 在上面的示例中,存储库看起来并没有做很多事情,这是正常的,因为它下面只有一层,即Room。 In real practice you can have other data sources including network clients and cache. 实际上,您可以拥有其他数据源,包括网络客户端和缓存。 The repository's job is to abstract all data source logics. 存储库的工作是抽象所有数据源逻辑。

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

I am not a fan of LiveData , but here's what I would do. 我不是LiveData的粉丝,但是我会这样做。 Keep all of your logic in ViewModel and make the view layer as simple as possible. 将所有逻辑保留在ViewModel中,并使视图层尽可能简单。

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

Above code will show all students because we set the default value to 0 in the viewmodel. 上面的代码将显示所有学生,因为我们在viewmodel中将默认值设置为0。 Call studentViewModel.setValue(/*any integer*/) to switch the list to any level. 调用studentViewModel.setValue(/*any integer*/)将列表切换到任何级别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM