如何从 LiveData 加载 LiveData?
How to load a LiveData from a LiveData?
在我的数据库中有两个列表:聊天列表和用户列表。聊天列表中的每个项目都包含其各自用户的 ID。我需要将每个聊天与用户数据一起加载,以将其显示为 recyclerview 中的实时数据。如何在不破坏 MVVM 模式的情况下做到这一点?
数据库:
{
"chats" : {
"abc" : {
"userId" : "123",
"chatId" : "abc",
"lastMessage" : "message1"
},
"cde" : {
"userId" : "456",
"chatId" : "def",
"lastMessage" : "message2"
}
},
"users" : {
"abc" : {
"name" : "Name1",
"photo" : "photo.jpg",
"userId" : "abc",
"email" : "name1@gmail.com"
},
"def" : {
"name" : "Name2",
"photo" : "photo.jpg",
"userId" : "def",
"email" : "name2@gmail.com"
}
}
}
视图模型:
class ChatsViewModel:ViewModel() {
private val chatsRepository = ChatsRepository()
private var userRepository = UserRepository()
fun fetchChatsData(): LiveData<MutableList<Chat>> {
val mutableData = MutableLiveData<MutableList<Chat>>()
chatsRepository.getChatsData().observeForever { chatsList ->
mutableData.value = chatsList
}
return mutableData
}
fun fetchUserData(): LiveData<User> {
val mutableData = MutableLiveData<User>()
userRepository.getUserData("USER_ID_HERE").observeForever { user ->
mutableData.value = user
}
return mutableData
}
}
片段:
class ChatTabFragment2 : Fragment() {
private lateinit var fragmentView: View
private val viewModel by lazy { ViewModelProvider(this).get(ChatsViewModel::class.java) }
private lateinit var adapter:ChatsAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
fragmentView = inflater.inflate(R.layout.fragment_chat_tab, container, false)
adapter = ChatsAdapter{
openChat(it.userId)
}
fragmentView.recycler_view.setHasFixedSize(true)
fragmentView.recycler_view.adapter = adapter
observeData()
return fragmentView
}
private fun observeData() {
viewModel.fetchChatsData().observe(viewLifecycleOwner, { chatsList ->
chatsList.let {
adapter.submitList(it)
}
})
}
聊天存储库:
class ChatsRepository {
private var chatsReference = FirebaseDatabase.getInstance().reference
.child(UserFirebase.id)
private lateinit var valueEventListener: ValueEventListener
fun getChatsData(): LiveData<MutableList<Chat>> {
val mutableData = MutableLiveData<MutableList<Chat>>()
valueEventListener = object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
val chatsList = mutableListOf<Chat>()
for (ds in snapshot.children) {
ds.getValue(Chat::class.java)?.let { chat ->
chatsList.add(chat)
}
}
mutableData.value = chatsList
}
override fun onCancelled(error: DatabaseError) {
}
}
chatsReference.addValueEventListener(valueEventListener)
return mutableData
}
}
用户存储库
class UserRepository {
fun getUserData(userId:String): LiveData<User> {
val mutableData = MutableLiveData<User>()
FirebaseDatabase.getInstance().reference.child("usersRef").child(userId)
.addListenerForSingleValueEvent(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
mutableData.value = snapshot.getValue(User::class.java)
}
override fun onCancelled(error: DatabaseError) {}
})
return mutableData
}
}
我的建议是对数据层(firebase 数据库)和表示层(前端)使用不同的模型。例如:
让我们调用数据库中的模型 ChatRemoteModel
和 UserRemoteModel
。
data class ChatRemoteModel() {
val userId: String,
val chatId: String,
val lastMessage: String
}
data class UserRemoteModel() {
val name: String,
val photo: String,
val userId: String,
val email: String
}
我们将演示文稿所需的模型称为 Chat
和 User
data class Chat() {
val user: User,
val chatId: String,
val lastMessage: String
}
data class User() {
val name: String,
val photo: String,
val userId: String,
val email: String
}
现在在您的存储库 classes 中,您从数据库中检索数据并将它们映射到表示模型。
class ChatsRepository {
...
private val userRepository = UserRepository()
fun getChatsData(): LiveData<MutableList<Chat>> {
val mutableData = MutableLiveData<MutableList<Chat>>()
valueEventListener = object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
val chatsList = mutableListOf<Chat>()
for (ds in snapshot.children) {
ds.getValue(ChatRemoteModel::class.java)?.let { chat ->
userRepository.getUser(chat.userId).observeForever { user ->
chatsList.add(
Chat(user, chat.chatId, chat.lastMessage)
)
}
}
}
mutableData.value = chatsList
}
override fun onCancelled(error: DatabaseError) {
}
}
chatsReference.addValueEventListener(valueEventListener)
return mutableData
}
}
您也可以 return User
而不是 UserRepository
class 中的 UserRemoteModel
。这看起来有点矫枉过正,因为这两个模型实际上是相同的,但它使您可以根据 ViewModel 的需要灵活地设计表示模型。
所以我的意思是,如果你对不同的层有不同的模型,那么你可以为数据层设计模型以有效地存储数据和传输数据,并为表现层设计模型以有效地显示UI.你可能想改进代码,(命名,防止重复值,使用映射器,
使用 LiveData 转换等),我提供的是支持我的观点的最小示例。
在我的数据库中有两个列表:聊天列表和用户列表。聊天列表中的每个项目都包含其各自用户的 ID。我需要将每个聊天与用户数据一起加载,以将其显示为 recyclerview 中的实时数据。如何在不破坏 MVVM 模式的情况下做到这一点?
数据库:
{
"chats" : {
"abc" : {
"userId" : "123",
"chatId" : "abc",
"lastMessage" : "message1"
},
"cde" : {
"userId" : "456",
"chatId" : "def",
"lastMessage" : "message2"
}
},
"users" : {
"abc" : {
"name" : "Name1",
"photo" : "photo.jpg",
"userId" : "abc",
"email" : "name1@gmail.com"
},
"def" : {
"name" : "Name2",
"photo" : "photo.jpg",
"userId" : "def",
"email" : "name2@gmail.com"
}
}
}
视图模型:
class ChatsViewModel:ViewModel() {
private val chatsRepository = ChatsRepository()
private var userRepository = UserRepository()
fun fetchChatsData(): LiveData<MutableList<Chat>> {
val mutableData = MutableLiveData<MutableList<Chat>>()
chatsRepository.getChatsData().observeForever { chatsList ->
mutableData.value = chatsList
}
return mutableData
}
fun fetchUserData(): LiveData<User> {
val mutableData = MutableLiveData<User>()
userRepository.getUserData("USER_ID_HERE").observeForever { user ->
mutableData.value = user
}
return mutableData
}
}
片段:
class ChatTabFragment2 : Fragment() {
private lateinit var fragmentView: View
private val viewModel by lazy { ViewModelProvider(this).get(ChatsViewModel::class.java) }
private lateinit var adapter:ChatsAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
fragmentView = inflater.inflate(R.layout.fragment_chat_tab, container, false)
adapter = ChatsAdapter{
openChat(it.userId)
}
fragmentView.recycler_view.setHasFixedSize(true)
fragmentView.recycler_view.adapter = adapter
observeData()
return fragmentView
}
private fun observeData() {
viewModel.fetchChatsData().observe(viewLifecycleOwner, { chatsList ->
chatsList.let {
adapter.submitList(it)
}
})
}
聊天存储库:
class ChatsRepository {
private var chatsReference = FirebaseDatabase.getInstance().reference
.child(UserFirebase.id)
private lateinit var valueEventListener: ValueEventListener
fun getChatsData(): LiveData<MutableList<Chat>> {
val mutableData = MutableLiveData<MutableList<Chat>>()
valueEventListener = object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
val chatsList = mutableListOf<Chat>()
for (ds in snapshot.children) {
ds.getValue(Chat::class.java)?.let { chat ->
chatsList.add(chat)
}
}
mutableData.value = chatsList
}
override fun onCancelled(error: DatabaseError) {
}
}
chatsReference.addValueEventListener(valueEventListener)
return mutableData
}
}
用户存储库
class UserRepository {
fun getUserData(userId:String): LiveData<User> {
val mutableData = MutableLiveData<User>()
FirebaseDatabase.getInstance().reference.child("usersRef").child(userId)
.addListenerForSingleValueEvent(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
mutableData.value = snapshot.getValue(User::class.java)
}
override fun onCancelled(error: DatabaseError) {}
})
return mutableData
}
}
我的建议是对数据层(firebase 数据库)和表示层(前端)使用不同的模型。例如:
让我们调用数据库中的模型 ChatRemoteModel
和 UserRemoteModel
。
data class ChatRemoteModel() {
val userId: String,
val chatId: String,
val lastMessage: String
}
data class UserRemoteModel() {
val name: String,
val photo: String,
val userId: String,
val email: String
}
我们将演示文稿所需的模型称为 Chat
和 User
data class Chat() {
val user: User,
val chatId: String,
val lastMessage: String
}
data class User() {
val name: String,
val photo: String,
val userId: String,
val email: String
}
现在在您的存储库 classes 中,您从数据库中检索数据并将它们映射到表示模型。
class ChatsRepository {
...
private val userRepository = UserRepository()
fun getChatsData(): LiveData<MutableList<Chat>> {
val mutableData = MutableLiveData<MutableList<Chat>>()
valueEventListener = object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
val chatsList = mutableListOf<Chat>()
for (ds in snapshot.children) {
ds.getValue(ChatRemoteModel::class.java)?.let { chat ->
userRepository.getUser(chat.userId).observeForever { user ->
chatsList.add(
Chat(user, chat.chatId, chat.lastMessage)
)
}
}
}
mutableData.value = chatsList
}
override fun onCancelled(error: DatabaseError) {
}
}
chatsReference.addValueEventListener(valueEventListener)
return mutableData
}
}
您也可以 return User
而不是 UserRepository
class 中的 UserRemoteModel
。这看起来有点矫枉过正,因为这两个模型实际上是相同的,但它使您可以根据 ViewModel 的需要灵活地设计表示模型。
所以我的意思是,如果你对不同的层有不同的模型,那么你可以为数据层设计模型以有效地存储数据和传输数据,并为表现层设计模型以有效地显示UI.你可能想改进代码,(命名,防止重复值,使用映射器, 使用 LiveData 转换等),我提供的是支持我的观点的最小示例。