Android Room:如何将来自多个 SQL 查询的数据合并到一个 ViewModel
Android Room: How to combine data from multiple SQL queries into one ViewModel
Context:我正在使用 Android Room 和 Android Architecture Components 在 Recyclerview 中加载数据。我正在加载的数据是 table 个 Message 对象,它有日期和消息内容。
目标:进入消息室后,保存当前时间的时间戳,我希望Recyclerview显示在房间数据库中找到的最近10条消息在该时间戳之前发送。
查询看起来像这样,偏移量是 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 对象,由我的消息页面 Activity 观察,每次新消息到达存储库时都会更新该对象。
实时消息的查询看起来像这样:
@Query("SELECT * from message_table WHERE date>:my_date ORDER BY date DESC")
LiveData<List<Message>> getNewMessages(long my_date);
此外,我稍后需要创建一个功能,允许用户在滚动到回收站视图顶部时加载更多旧消息。
我的尝试:
- 组合查询:最简单的方法是编写一个查询来获取实时消息和 10 条旧消息。不幸的是,虽然我了解到 SQL 有一个 "UNION" 运算符,但我无法弄清楚如何使用我的 java DAO 中的特定语法来使用它。
- MediatorLiveData:或者,我可以通过 DAO 创建两个 LiveData,每个查询一个,然后我可以将它们与 MediatorLiveData 连接在一起。我想这在技术上可行,然后我可以将我的中介数据提供给 recyclerview 适配器,但是将 LiveData 用于数据本质上是静态的旧消息查询感觉不对。
- 旧消息的非实时数据:我能想到的最后一个选择是从新消息查询中获取LiveData对象并观察它,并创建一个函数获取旧消息的简单列表(列表而不是 LiveData>),并在新消息 LiveData 的 onChanged 函数中,我可以手动组合两个消息列表。
代码来源:
在我的聊天室activity,我通过以下方式观察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");
}
}
我正在帮助您解决选项 1。您可以合并相同的 table。
当您输入聊天时,将当前时间保存在本地变量中,例如
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);
如果您需要任何更改,请告诉我。
我建议您使用“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)
Context:我正在使用 Android Room 和 Android Architecture Components 在 Recyclerview 中加载数据。我正在加载的数据是 table 个 Message 对象,它有日期和消息内容。
目标:进入消息室后,保存当前时间的时间戳,我希望Recyclerview显示在房间数据库中找到的最近10条消息在该时间戳之前发送。 查询看起来像这样,偏移量是 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 对象,由我的消息页面 Activity 观察,每次新消息到达存储库时都会更新该对象。 实时消息的查询看起来像这样:
@Query("SELECT * from message_table WHERE date>:my_date ORDER BY date DESC")
LiveData<List<Message>> getNewMessages(long my_date);
此外,我稍后需要创建一个功能,允许用户在滚动到回收站视图顶部时加载更多旧消息。
我的尝试:
- 组合查询:最简单的方法是编写一个查询来获取实时消息和 10 条旧消息。不幸的是,虽然我了解到 SQL 有一个 "UNION" 运算符,但我无法弄清楚如何使用我的 java DAO 中的特定语法来使用它。
- MediatorLiveData:或者,我可以通过 DAO 创建两个 LiveData,每个查询一个,然后我可以将它们与 MediatorLiveData 连接在一起。我想这在技术上可行,然后我可以将我的中介数据提供给 recyclerview 适配器,但是将 LiveData 用于数据本质上是静态的旧消息查询感觉不对。
- 旧消息的非实时数据:我能想到的最后一个选择是从新消息查询中获取LiveData对象并观察它,并创建一个函数获取旧消息的简单列表(列表而不是 LiveData>),并在新消息 LiveData 的 onChanged 函数中,我可以手动组合两个消息列表。
代码来源:
在我的聊天室activity,我通过以下方式观察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");
}
}
我正在帮助您解决选项 1。您可以合并相同的 table。
当您输入聊天时,将当前时间保存在本地变量中,例如
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);
如果您需要任何更改,请告诉我。
我建议您使用“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)