使用Firebase的聊天应用程序:收到新消息时收到通知 – Android

我正在开发一个使用Firebase实时数据库的聊天应用程序。 我已经能够正确地发送和接收消息。 现在,我希望在收到新消息时执行通知。 为此,我创build了一个使用ChildEventListener监听数据库更改的Service并创build通知。 问题是,我在onChildAdded方法中创build通知,并且此方法触发数据库中的现有节点和新的节点。 当用户从应用程序来回导航时,这会导致为相同的消息创build多次通知。

以下是我如何实施它:

 chatMsgsRef.orderByChild(FirebaseDBKeys.LOCATION_LAST_UPDATED).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) { ChatMessage message = dataSnapshot.getValue(ChatMessage.class); if (!message.getSenderId().equals(currentUserId)) { mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(NotificationsService.this) .setSmallIcon(R.drawable.message) .setContentTitle("New Message from " + message.getReceipientName()) .setContentText(message.getMessage()) .setOnlyAlertOnce(true) .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); mBuilder.setAutoCancel(true); mBuilder.setLocalOnly(false); mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build()); } } @Override public void onChildChanged(DataSnapshot dataSnapshot, String s) { } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { } @Override public void onChildMoved(DataSnapshot dataSnapshot, String s) { } @Override public void onCancelled(DatabaseError databaseError) { } }); 

我怎样才能以其他聊天应用程序如whatsapp等工作方式实现通知?

Solutions Collecting From Web of "使用Firebase的聊天应用程序:收到新消息时收到通知 – Android"

正确的方法是在发送新的聊天消息时,通过聊天向客户端推送数据消息。

这篇博文解释了如何完成这个。 基本上,您需要设置一个服务器来侦听聊天的firebase ref,并在更新时发送推送通知。 这样你的客户可以在应用程序中,或者在应用程序之外,仍然可以得到推动。

如果您使用服务,则存在一些潜在的问题。

首先你必须保持电话的清醒。 这会消耗电池。

其次,Android可以随时杀死你的后台服务,所以你的应用程序可能会突然停止工作。

第三,在打盹模式下,Android会阻止networking活动并阻止你的应用在后台运行。

对我来说有一个更好的答案:

你想在这种情况下,不一定知道新的消息。 这是知道UNREAD消息。

在ChatMessage对象中设置一个“读取”标志(或者相反,有一个值给出了最近读取消息的时间戳或ID)。

现在每当onChildAdded被触发时,检查是否读取== false。 如果是这样,显示通知消息是未读的(记得更新通知,如果它存在,所以只有一个通知将被显示,它会显示最近的一个 – 哦,还记得当孩子删除通知被改为阅读。)

如果用户在多个设备上使用您的应用程序,则会正确检查读取状态。 如果他在手机上看到最新消息,然后转到平板电脑,则不会显示新消息通知。

如果你想,你甚至可以使用这个function来表明收件人读你的消息给他们。

你怎么知道什么时候被读取? 也许只是当你把它添加到屏幕上。 也许你确定它是在视图中(而不是从屏幕上滚动出来),并且可以看到几秒钟。

你有没有尝试addValueEventListener?

https://www.firebase.com/docs/android/guide/retrieving-data.html#section-start

 // Get a reference to our posts Firebase ref = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog/posts"); // Attach an listener to read the data at our posts reference ref.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { System.out.println(snapshot.getValue()); } @Override public void onCancelled(FirebaseError firebaseError) { System.out.println("The read failed: " + firebaseError.getMessage()); } }); 

“随时将新的数据添加到我们的Firebase参考中,这种方法将被调用,我们不需要编写任何额外的代码来实现这一点。”

编辑:“它被触发一次的初始数据,每次数据更改。 我没有尝试过,但是我的想法是在方法第一次触发时设置一个标志。 然后,无论何时设置方法和该标志(换句话说,第二次,第三次,第四次等),都可以从快照中获取最近的对象。

@Chad Shultz的答案和你原来的代码的结合,加上一些数据库结构。

您将按照最初的devise使用查询

 chatMsgsRef.orderByChild(...) 

但是,将数据结构更改为具有以下布局

 >root > users > userID_001 > chats > chat_001:true > userID_002 > chats > chat_001:true > chats > chat_001 > participants > userID_001:true > userID_002:true > messages > msg_001 > sender:"userID_001" > text:"some message" > time:"some time" > message_read_states > chat_001 > msg_001 > userID_001:true > userID_002:false 

所以无论何时发送消息,它都会被推送到“消息”节点。 接下来,系统获取所有“参与者”,并将其推送到该聊天/消息的“message_read_states”节点下,除了发送者之外,每个人的值都为false。 当有人读这条消息时,他们的价值在那里改变。

现在服务需要确定哪些消息通知用户。 该服务将在message_read_states / chat_X上放置一个监听器,并根据子字段“userID_X”的值(取决于当前用户是谁)对其进行sorting。 我们将使Query仅返回消息ID,对于每个聊天,在其下有一个值为“userID_X:false”的消息ID

因此,在这个例子中,对于“userID_002”,查询将返回“msg_001”,但是对于“userID_001”,它将不返回任何内容,因为没有find该键的必需值(他/她是发件人)。

查询将被构build如下,在您的服务的onStartCommand中:

  //TODO: Get the ID of the chat the user is taking part in String chatID = "chat_001"; // Check for new messages FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); if (currentUser != null){ String UID = currentUser.getUid(); DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference(); Query query = rootRef.child("message_read_states").child(chatID).orderByChild(UID).equalTo(false); query.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) { String messageID = dataSnapshot.getKey(); //TODO: Handle Notification here, using the messageID // A datasnapshot received here will be a new message that the user has not read // If you want to display data about the message or chat, // Use the chatID and/or messageID and declare a new // SingleValueEventListener here, and add it to the chat/message DatabaseReference. } @Override public void onChildChanged(DataSnapshot dataSnapshot, String s) { String messageID = dataSnapshot.getKey(); //TODO: Remove the notification // If the user reads the message in the app, before checking the notification // then the notification is no longer relevant, remove it here. // In onChildAdded you could use the messageID(s) to keep track of the notifications } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { } @Override public void onChildMoved(DataSnapshot dataSnapshot, String s) { } @Override public void onCancelled(DatabaseError databaseError) { } }); } 

当然,现在很可能用户会参与多个聊天。 您必须遍历与用户关联的所有聊天,并为每个聊天实施查询。

来源:我目前正在使用聊天系统开发Firebase应用