【问题标题】:how to get the first or (any) element from a LiveData List in Android MVVM architecture?如何从 Android MVVM 架构中的 LiveData 列表中获取第一个或(任何)元素?
【发布时间】:2020-07-26 17:51:22
【问题描述】:

我使用 MVVM 架构构建了一个带有 Repository 的 Android 应用程序,作为 ViewModel 和 Room 数据库之间的中介。在其中一个函数中,我从存储库类中的表中检索对象列表,以便可以从 ViewModel 类中调用它。

如何从存储库类中检索列表中的第一个元素,而不是在任何一个活动中观察LiveData

这是我的存储库类:

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

}

【问题讨论】:

  • 您好,您是否尝试过限制查询的输出?
  • 查询的输出是一个列表。我想从任何元素中检索详细信息。
  • @Zain 我想从列表中的任何元素获取蚂蚁信息。

标签: android android-sqlite android-room android-livedata android-architecture-components


【解决方案1】:

如何从 Android 中的 LiveData 列表中获取第一个或(任何)元素 MVVM 架构

如果您想从 LiveData 列表中获取特定元素,则需要使用偏移量限制查询。

默认情况下,限制查询不会考虑到它的偏移量;所以默认偏移值为0。

例如,在你的Dao:

示例 1 和示例 2 的以下查询是等效的,因为默认偏移值为 0。

示例

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

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

示例 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

注意:这里我假设你的模型类是Student

这是关于第一行的;但是要返回行号x,那么您需要将偏移量操作为:x-1,因为偏移量是从 0 开始的值

示例 3(与示例 2 相同的 Dao 查询)

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

如果要返回多行,则需要操作LIMIT值,所以要从结果中返回x行,然后用限制查询x.

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

希望这能解决您的问题

根据 cmets 编辑

我已经有另一个查询返回的列表@Query("SELECT * FROM students) LiveData&lt;List&lt;Student&gt;&gt; getStudents(); 所以返回值 是一个列表。我想从列表中获取第一个元素。 这个答案真正返回第一个元素,但我需要通过所有 步骤(在ViewModel 类中定义此方法并观察它 在MainActivity 中以获取列表或任何元素 列表)。我需要的是在我输入列表中的第一个值 使用存储库类中的函数。 ——

现在您正在使用以下查询

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

你想:

  1. 获取列表中的第一个或任何元素。并根据 上面提到的
  2. 通过所有步骤(在ViewModel类中定义这个方法 并在MainActivity 中观察它以获取列表或任何 列表中的元素)。

所以这样做:

In Dao::将查询更改为

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

在存储库中:

public class StudentRepository {

    ...

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

在 ViewModel 中:

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

活动中:

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

            }
        }
    });
}

并进行测试:

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.

并返回 mAllStudents 列表中的第一个元素,以便在 Log.d 中键入第一个学生姓名

所以,在你的活动中

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

编辑是否可以返回列表中的任何元素而不 遵循所有步骤,例如在 ViewModel 中编写函数 并在 MainActivity 中观察?我的问题是不要跟随所有 步骤。

是的,这是可能的,但上述模型是 Google 推荐的模型,您可以从 Dao 查询返回 List&lt;Student&gt; 而不是 LiveData&lt;List&lt;Student&gt;&gt;,但坏消息是:

  1. 您必须在单独的后台线程中处理它;因为 LiveData 这样做是免费的。
  2. 您将失去LiveData 的值;所以你必须手动 刷新列表以检查任何更新,因为您将无法使用观察者模式。

因此,您可以省略使用 ViewModelRepository,并按照以下方式从活动中执行所有操作:

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

以及对道的查询:

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

【讨论】:

  • 我已经有另一个查询返回的列表 @Query("SELECT * FROM students) LiveData> getStudents(); 所以返回的值是一个列表。我想得到列表中的第一个元素。
  • 我已经更新了我的问题并分享了我的存储库类。
  • @Abdulwahid 请检查更新后的答案.. 希望针对您的查询
  • @Abdulwahid 是的,这是可能的,但上述模型是 Google 推荐的模型,您可以从 Dao 方法返回 List 而不是 LiveData 列表,但您必须在单独的后台线程;因为 LiveData 是免费的。在这种情况下,除非您手动刷新列表,否则数据库中的任何更新都不会反映在您的列表中。您可以省略使用 ViewModel 和存储库,并从活动中执行所有操作...如果您觉得这解决了您的问题,请采纳答案..谢谢
  • @Abdulwahid 请找到更新的答案..如果您需要进一步的帮助,请告诉我:)
猜你喜欢
  • 1970-01-01
  • 2011-01-30
  • 2012-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-05
  • 1970-01-01
相关资源
最近更新 更多