how to get the first or (any) element from a LiveData List in Android MVVM architecture?

淺唱寂寞╮ 提交于 2020-07-05 12:27:07

问题


I used MVVM architecture to build an Android application with a Repository as a mediation between the ViewModel and Room database. In one of the functions, I retrieve a list of objects from a table in the repository class so that I can call it from the ViewModel class.

how to retrieve the first element in the list from the repository class instead of observing the LiveData in any one of the activities?

here is my repository class:

public class StudentRepository {

private StudentDAO mStudentDAO;
private LiveData<List<Student>> mAllStudents;

public StudentRepository(Application application){
    StudentRoomDatabase db = StudentRoomDatabase.getDatabase(application);
    mStudentDAO= db.StudentDAO();
    mAllStudents= mStudentDAO.getAllStudents();
}



public LiveData<List<Word>> getAllStudents(){

    // What I need to return the first element in the mAllStudents list
    // in order to type the first student name in the Log.d 

Log.d("First_Name",mAllStudent.get(0)); // I want to type the student name in the Log without adding a function in the viewModel and observe that in any Activity

    return mAllStudents;
}

}


回答1:


how to get the first or (any) element from a LiveData List in Android MVVM architecture

If you want to get a particular element from a LiveData list, then you need to limit your query with an offset.

By default limiting a query doesn't consider an offset to it; so the default offset value is 0.

For instance, in your Dao:

The below queries of Example 1 & 2 are equivalent, because the default offset value is 0.

Example

@Query("SELECT * FROM students LIMIT  :limit")
LiveData<List<Student>> getStudents(int limit);

// Query
getStudents(1); // returns the first row of the list

Example 2

@Query("SELECT * FROM students LIMIT  :limit OFFSET :offset")
LiveData<List<Student>> getStudents(int limit, int offset);

// Query
getStudents(1, 0); // returns the first row of the list

Note: Here I am assuming your model class is Student

This is about the first row; but to return row number x then you need to manipulate the offset to be: x-1, as the offset is 0-based value

Example 3 (Same Dao query as Example 2)

getStudents(1, 1); // returns the second row
getStudents(1, 4); // returns the fifth row

If you want to return more than one row, then you need to manipulate the LIMIT value, so to return x rows from the results, then limit the query with x.

getStudents(2, 1); // returns the second and third rows
getStudents(3, 4); // returns the fifth, sixth, and seventh rows

Hope this addresses your question

Edit as per comments

I already have a list returned by another query @Query("SELECT * FROM students) LiveData<List<Student>> getStudents(); So the returned value is a list. I want to get the first element from the list. This answer returns the first element truly, but I need to pass all the steps (to define this method in the ViewModel class and observe it in the MainActivity in order to get the list or any element in the list). What I need is to type the first value in the list while I am using the function in the repository class. –

Now you are using below query

@Query("SELECT * FROM students")
LiveData<List<Student>> getStudents();

And you want to:

  1. Get the first or any element in the list. and to do so according to what is mentioned above
  2. Pass all the steps (to define this method in the ViewModel class and observe it in the MainActivity in order to get the list or any element in the list).

So to do that:

In Dao:: Change your query to

@Query("SELECT * FROM students LIMIT  :limit OFFSET :offset")
LiveData<List<Student>> getAllStudents(int limit, int offset);

In Repository:

public class StudentRepository {

    ...

    public LiveData<List<Student>> getAllStudents(final int limit, final int offset) {
        return mDAO.getAllStudents(limit, offset);
    }
}

In ViewModel:

public LiveData<List<Student>> getAllStudents(final int limit, final int offset) {
    return mRepository.getAllStudents(limit, offset);
}

In Activity:

private void getAllStudents(int limit, int offset) {
    mViewModel.getAllStudents(limit, offset).observe(this, new Observer<List<Student>>() {
        @Override
        public void onChanged(List<Student> students) {
            if (students != null) {
                // Here you can set RecyclerView list with `students` or do whatever you want

            }
        }
    });
}

And to test that:

getAllStudents(1, 0); // return first row from the table.
getAllStudents(2, 0); // return first 2 rows from the table.
getAllStudents(2, 1); // return 2nd and 3rd rows from the table.
getAllStudents(-1, 5); // remove first 5 rows from the table.

And to return the first element in the mAllStudents list in order to type the first student name in the Log.d

So, In your Activity

mViewModel.getAllStudents(1, 0).observe(this, new Observer<List<Student>>() {
    @Override
    public void onChanged(List<Student> students) {
        if (students != null) {
            Student student = students.get(0);
            Log.d("First_Name", student.getName());
        }
    }
});

Edit is it possible to return any element of the list without following all the steps such as writing a function in the ViewModel and observe that in the MainActivity? My question is not to follow all the steps.

Yes it's possible, but the above model is the recommended model by Google, You can return a List<Student> from Dao query instead of LiveData<List<Student>>, but the bad news are:

  1. You have to handle that in a separate background thread; because the LiveData do that for free.
  2. You will lose the value of the LiveData; so you have to manually refresh the list to check any update as you won't be able to use the observer pattern.

So, you can omit using ViewModel and Repository, and do all the stuff from the activity as follows:

private Executor mExecutor = Executors.newSingleThreadExecutor();

public void getAllStudents(final int limit, final int offset) {

    final StudentDAO mDAO = StudentDatabase.getInstance(getApplicationContext()).getStudentDAO();

    mExecutor.execute(new Runnable() {
        @Override
        public void run() {
            List<Student> students = mDAO.getAllStudents(limit, offset);
            Student student = students.get(0);
            Log.d("First_Name", student.getName());
        }
    });
}

// Usage: getAllStudents(1, 0);

And the query for the Dao:

@Query("SELECT * FROM students LIMIT  :limit OFFSET :offset")
List<Student> getAllStudents(int limit, int offset);


来源:https://stackoverflow.com/questions/61200289/how-to-get-the-first-or-any-element-from-a-livedata-list-in-android-mvvm-archi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!