Android Room:如何将来自多个SQL查询的数据合并到一个ViewModel中

时间:2019-11-28 07:02:38

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

上下文:我正在使用Android Room和Android体系结构组件在Recyclerview中加载数据。我正在加载的数据是Message对象的表,其中包含日期和消息内容。


目标:进入消息收发室后,将保存当前时间的时间戳,我希望Recyclerview显示在该时间戳之前在Room数据库中找到的10条最新消息。 查询将类似于以下内容,其中offset为10,my_date为时间戳:

@Query("SELECT * from message_table WHERE date<:my_date ORDER BY date DESC LIMIT :offset")
LiveData<List<Message>> getOldMessages(long my_date, int offset);

在进入消息传递室时,我还想实例化一个LiveData对象,该行为由我的消息传递页面“活动”观察到,每次新消息到达存储库时都会更新该活动。 实时消息查询看起来像这样:

@Query("SELECT * from message_table WHERE date>:my_date ORDER BY date DESC")
LiveData<List<Message>> getNewMessages(long my_date);

此外,稍后我将需要创建一个功能,该功能允许用户滚动到recyclerview的顶部时加载更多旧消息。


我的尝试

  1. 组合查询:最简单的方法是编写一个单个查询,以同时获取实时消息和10条较旧的消息。不幸的是,虽然我了解到SQL具有“ UNION”运算符,但我仍无法弄清楚如何在Java DAO中将其与特定语法一起使用。
  2. MediatorLiveData :或者,我可以通过DAO创建两个LiveData,每个查询一个,然后将它们与MediatorLiveData一起加入。我猜想这在技术上是可行的,然后我可以将中介的数据馈送到recyclerview适配器,但是使用LiveData进行数据本质上是静态的旧消息查询是不合适的。
  3. 旧消息的非实时数据:我能想到的最后一个选择是从新消息查询中获取LiveData对象并对其进行观察,并创建一个函数以获取简单列表(列表而不是LiveData>),并在新消息LiveData的onChanged函数中,我可以手动组合这两个消息列表。

代码源

在我的消息收发室活动中,我通过以下方式观察LiveData:

    LiveData<List<Message>> newMessagesLiveData = mMessageViewModel.getNewMessages();
    newMessagesLiveData.observe(this, new Observer<List<Message>>() {
        @Override
        public void onChanged(@Nullable final List<Message> messages) {
            adapter.setMessages(messages);
            RecyclerView recyclerView = findViewById(R.id.recyclerview);
            recyclerView.scrollToPosition(adapter.getItemCount()-1);
        }
    });

然后适配器接收更改并自行更新:

public void setMessages(List<Message> messages){
    mMessages = messages;
    notifyDataSetChanged();
}
@Override
public void onBindViewHolder(MessageViewHolder holder, int position) {
    position = mMessages.size()-1-position;
    if (mMessages != null) {
        Message current = mMessages.get(position);
        holder.messageItemView.setText(current.getMessage());
    } else {
        holder.messageItemView.setText("No messages to display");
    }
}

2 个答案:

答案 0 :(得分:2)

我正在为您提供选项1。您可以合并同一张表。

输入聊天内容后,将当前时间保存在本地变量中,例如

long currentTime = System.currentTimeMillis();

现在,您需要合并两个查询。一个查询来自currentTime的最后偏移量消息,一个查询大于currentTime的消息。

       @Query("SELECT * FROM (" +
        "SELECT * from message_table WHERE date<:my_date ORDER BY date DESC LIMIT :offset) UNION SELECT * from (SELECT * from message_table WHERE date>=:my_date ORDER BY date DESC)")
LiveData<List<Message>> getMessages(long my_date, int offset);

如果您需要任何更改,请告诉我。

答案 1 :(得分:0)

我建议您使用“UNION ALL”代替 UNION,如下所示

SELECT * FROM (SELECT * from table WHERE id == 2)
UNION ALL
SELECT * from (SELECT * from table WHERE id == 3)
UNION ALL
SELECT * from (SELECT * from table WHERE id == 5)