我正在我的应用程序中构建一个聊天部分。当我完成从服务器发送到设备的数据消息的处理时,我意外地遇到了一个严重的问题,即 firebase 打开一个新的隔离来运行后台任务。我使用 GetX 控制器
ChatController
,它有一个 chats
类型的 RxList<Chat>
变量。每个聊天都有一个消息列表。通常,当有人发送消息并且设备位于前台时,我会获取新消息,到处进行一些序列化,然后将其添加到 ChatController
的 chats
中相应的聊天中。当在后台做同样的事情时,它只是重新初始化一个没有数据的新消息,这会停止添加新消息的过程。
我尝试让聊天控制器永久存在,但没有成功。如何使 firebase 的后台隔离利用现有的聊天控制器?即使用户从顶部拖动来查看通知,我也无法更新
chats
。这真是荒唐至极。
if (Get.isRegistered<ChatController>()) {
// If the controller is already registered, reuse it
chatController = Get.find<ChatController>();
print("Chat Controller Found");
} else {
// If the controller is not registered, initialize it
chatController = Get.put(ChatController());
await chatController
.getChats(); // Only fetch chats on the first initialization
print("Chat Controller Created!");
}
chatController.addMessageToChat(
int.parse(message.data["chat_id"]),
chatMessage,
);
ChatController.dart:
class ChatController extends GetxController with WidgetsBindingObserver {
final DioClient _dioClient = DioClient();
RxInt currentChat = (-1).obs;
RxList<Chat> chats = <Chat>[].obs;
RxBool isInBackground = false.obs;
RxList<ChatMessage> backgroundMessages = <ChatMessage>[].obs;
RxList<ChatMessage> chatMessages = <ChatMessage>[].obs;
@override
void onInit() {
super.onInit();
getChats();
WidgetsBinding.instance.addObserver(this); // Add observer for app lifecycle
}
@override
void onClose() {
WidgetsBinding.instance
.removeObserver(this); // Remove observer when controller is destroyed
super.onClose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
// App comes back to foreground, refresh data
isInBackground.value = false;
for (ChatMessage message in backgroundMessages) {
print("Message added from backgroundMessages");
addMessageToChat(message.chatId, message);
}
backgroundMessages.clear();
} else if (state == AppLifecycleState.paused) {
isInBackground.value = true;
}
print("isInBackground from life cycle: ${isInBackground.value}");
}
void addMessageToChat(int chatId, ChatMessage message) {
print("isInBackground from add message: ${isInBackground.value}");
// if (isInBackground.value) {
// backgroundMessages.add(message);
// print("Message added to backgroundMessages");
// return;
// } else {
// print("Message added to chatMessages");
// }
// Find the chat
Chat chat = chats.firstWhere((chat) => chat.id == chatId);
if (chat.id != -1) {
chat.messages.add(message);
Map messageMap = message.toMap();
messageMap['created_at'] = formatMessageDate(
message.createdAt.toLocal().toIso8601String(),
Global.activeUser!.timezone ?? "UTC");
messageMap['sender']['name'] =
messageMap['sender']['member_id'] == chat.userId
? "You"
: messageMap['sender']['name'];
if (messageMap['sender']['member_id'] != chat.userId) {
chat.counter = currentChat.value != chatId ? chat.counter + 1 : 0;
}
chat.lastMessageMap = messageMap;
// Update the list by reordering the chat without rebuilding the entire list
int currentIndex = chats.indexOf(chat);
if (currentIndex != 0) {
chats.removeAt(currentIndex);
chats.insert(0, chat);
chats.refresh(); // This will trigger a partial rebuild
}
}
}
根据我的经验,最简单的方法是使用数据库;
您必须考虑两种情况:
应用程序完全关闭,Firebase 系统会启动您的操作几秒钟,此时它将在数据库中保存信息。
应用程序位于后台,但系统仍然保持其活动状态,在这种情况下,我将使用 WidgetsBindingObserver 将数据库中的信息与您需要的信息同步。
我的建议是使用 Hive,它很简单,对于这样的同步任务我已经使用过它,它对我来说效果很好。
请记住,在后台隔离无法修改 UI 组件。