我正在尝试使用 Xamarin Forms 创建跨平台应用程序。我决定使用 Firestore 作为我应用的数据库。
我正在尝试将聊天功能添加到我的应用程序中,但我正在努力实现实时收听功能。我已经创建了一个 ViewModel 类,其中包含一个由 UI 中的 ListView 使用的 ObservableCollection 聊天。
public class ChatsVM
{
public ObservableCollection<Chat> Chats { get; set; }
public ChatsVM()
{
Chats = new ObservableCollection<Chat>();
ReadMessages();
}
public async void ReadMessages()
{
User currentUser = await DependencyService.Get<IFirebaseAuthenticationService>().GetCurrentUserProfileAsync();
IList<Chat> chatList = await DependencyService.Get<IChatService>().GetChatsForUserAndListenAsync(currentUser.IsLandlord, currentUser.Id);
foreach (var chat in chatList)
{
Chats.Add(chat);
}
}
}
我还创建了从 Firestore 获取数据的服务。在服务方面(示例显示 Android 服务)我使用标准列表来保存聊天对象
List<Chat> Chats;
bool hasReadChats;
GetChatsForUserAndListenAsync 方法向我的查询添加了一个快照侦听器,并将事件传递给 OnEvent 方法。
public async Task<IList<Chat>> GetChatsForUserAndListenAsync(bool isLandlord, string userId)
{
string fieldToSearch;
if (isLandlord)
{
fieldToSearch = "landlordId";
}
else
{
fieldToSearch = "tenantId";
}
try
{
// Reset the hasReadChats value.
hasReadChats = false;
CollectionReference collectionReference = FirebaseFirestore.Instance.Collection(Constants.Chats);
// Get all documents in the collection and attach a OnCompleteListener to
// provide a callback function.
collectionReference.WhereEqualTo(fieldToSearch, userId).AddSnapshotListener(this);
// Wait until the callback has finished reading and formatting the returned
// documents.
for (int i = 0; i < 10; i++)
{
await System.Threading.Tasks.Task.Delay(100);
// If the callback has finished, continue rest of the execution.
if (hasReadChats)
{
break;
}
}
return Chats;
}
catch (FirebaseFirestoreException ex)
{
throw new Exception(ex.Message);
}
catch (Exception)
{
throw new Exception("An unknown error occurred. Please try again.");
}
}
public void OnEvent(Java.Lang.Object value, FirebaseFirestoreException error)
{
var snapshot = (QuerySnapshot) value;
if (!snapshot.IsEmpty)
{
var documents = snapshot.Documents;
Chats.Clear();
foreach (var document in documents)
{
Chat chat = new Chat
{
Id = document.Id,
LandlordId = document.Get("landlordId") != null ? document.Get("landlordId").ToString() : "",
TenantId = document.Get("tenantId") != null ? document.Get("tenantId").ToString() : ""
};
//JavaList messageList = (JavaList) document.Get("messages");
//List<Message> messages = new List<Message>();
// chat.Messages = messages;
Chats.Add(chat);
}
hasReadChats = true;
}
}
我如何将事件处理程序对此列表所做的任何更改传播到我的 VM 类中的 ObservableCollection?
答案 0 :(得分:1)
感谢 Jason 提出这个答案。
所以我修改了事件处理程序以在 Firestore 中查找文档更改。根据这些变化,服务将使用 MessagingCenter 发送不同的消息。
public async void OnEvent(Java.Lang.Object value, FirebaseFirestoreException error)
{
var snapshot = (QuerySnapshot) value;
if (!snapshot.IsEmpty)
{
var documentChanges = snapshot.DocumentChanges;
IFirebaseAuthenticationService firebaseAuthenticationService = DependencyService.Get<IFirebaseAuthenticationService>();
Chats.Clear();
foreach (var documentChange in documentChanges)
{
var document = documentChange.Document;
string memberOne = document.Get(Constants.MemberOne) != null ? document.Get(Constants.MemberOne).ToString() : "";
string memberTwo = document.Get(Constants.MemberTwo) != null ? document.Get(Constants.MemberTwo).ToString() : "";
Chat chat = new Chat
{
Id = document.Id,
MemberOne = memberOne,
MemberTwo = memberTwo,
};
var documentType = documentChange.GetType().ToString();
switch (documentType)
{
case Constants.Added:
MessagingCenter.Send<IChatService, Chat>(this, Constants.Added, chat);
break;
case Constants.Modified:
MessagingCenter.Send<IChatService, Chat>(this, Constants.Modified, chat);
break;
case Constants.Removed:
MessagingCenter.Send<IChatService, Chat>(this, Constants.Removed, chat);
break;
default:
break;
}
Chats.Add(chat);
}
hasReadChats = true;
}
}
在 VM 的构造函数中,我订阅了这些消息的侦听器,并相应地更新了 ObservableCollection。
public class ChatsVM
{
public ObservableCollection<Chat> Chats { get; set; }
public ChatsVM()
{
Chats = new ObservableCollection<Chat>();
ReadChats();
}
public async void ReadChats()
{
IFirebaseAuthenticationService firebaseAuthenticationService = DependencyService.Get<IFirebaseAuthenticationService>();
MessagingCenter.Subscribe<IChatService, Chat>(this, Constants.Added, (sender, args) =>
{
Chat chat = args;
Chats.Add(chat);
});
MessagingCenter.Subscribe<IChatService, Chat>(this, Constants.Modified, (sender, args) =>
{
Chat updatedChat = args;
Chats.Any(chat =>
{
if (chat.Id.Equals(updatedChat.Id))
{
int oldIndex = Chats.IndexOf(chat);
Chats.Move(oldIndex, 0);
return true;
}
return false;
});
});
MessagingCenter.Subscribe<IChatService, Chat>(this, Constants.Removed, (sender, args) =>
{
Chat removedChat = args;
Chats.Any(chat =>
{
if (chat.Id.Equals(removedChat.Id))
{
Chats.Remove(chat);
return true;
}
return false;
});
});
User currentUser = await firebaseAuthenticationService.GetCurrentUserProfileAsync();
await DependencyService.Get<IChatService>().GetChatsForUserAndListenAsync(currentUser.Id);
}
}