
本教程详细介绍了如何在android应用中,当用户处于特定activity时,有效阻止firebase推送通知的显示。通过引入一个静态布尔标志,并在目标activity的生命周期方法中动态管理该标志,结合`firebasemessagingservice`中的条件判断,开发者可以实现对通知行为的精细控制,从而优化用户体验,避免在用户已在聊天界面时收到重复通知。
在开发实时通信或聊天类应用时,一个常见的需求是当用户当前正在浏览某个聊天界面时,避免显示该聊天的新消息推送通知。因为用户已经身处消息流中,额外的通知会显得冗余且可能打扰用户体验。本教程将详细指导您如何实现这一功能,通过一个简单的静态标志来控制通知的显示。
核心思路
解决方案的核心是利用一个全局可访问的静态布尔变量来标记用户是否处于“不应显示通知”的特定Activity。当用户进入该Activity时,将标志设置为false;当用户离开该Activity时,将标志重置为true。然后在处理接收到的推送消息时,检查这个标志,决定是否构建并显示通知。
实现步骤
1. 创建通知辅助类 (NotificationHelper)
首先,创建一个简单的Java类,其中包含一个静态的布尔变量。这个变量将作为控制通知显示与否的开关。
public class NotificationHelper {
// 默认为true,表示通常情况下应该显示通知
public static boolean shouldShowNotification = true;
}说明:
- shouldShowNotification 变量的默认值设置为 true,意味着在应用的大多数状态下,通知都应该正常显示。只有当用户进入特定Activity时,我们才会临时将其设置为 false。
2. 在目标Activity中管理标志状态
接下来,您需要在不希望显示通知的特定Activity(例如,您的聊天Activity)中,利用Activity的生命周期方法来动态更新 NotificationHelper.shouldShowNotification 的值。
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class YourChatActivity extends AppCompatActivity { // 替换为您的聊天Activity名称
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_your_chat); // 替换为您的布局文件
// 其他初始化代码
}
@Override
protected void onResume() {
super.onResume();
// 当Activity进入前台并可见时,将标志设置为false,阻止通知显示
NotificationHelper.shouldShowNotification = false;
}
@Override
protected void onPause() {
super.onPause();
// 当Activity离开前台或不再可见时,将标志重置为true,允许通知显示
NotificationHelper.shouldShowNotification = true;
}
// 注意:如果您的应用有复杂的Activity栈管理,
// 确保在适当的生命周期方法中(例如onDestroy或onStop)正确处理标志,
// 以防止在用户切换到其他屏幕时通知仍被禁用。
// 对于大多数简单场景,onResume/onPause的配对是足够的。
}说明:
- onResume() 方法在Activity变为可见并与用户交互时调用。此时,用户正在查看聊天内容,因此应禁用通知。
- onPause() 方法在Activity即将被另一个Activity覆盖或部分不可见时调用。此时,用户可能不再直接查看聊天,因此应重新启用通知。
- 这种方法确保了只有当用户真正与该特定Activity交互时,通知才会被抑制。
3. 在FirebaseMessagingService中集成条件判断
最后一步是在您的 MyFirebaseMessagingService 类中,在处理接收到的推送消息时,检查 NotificationHelper.shouldShowNotification 标志。只有当该标志为 true 时,才执行构建和显示通知的代码。
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Objects;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(@NonNull RemoteMessage message) {
super.onMessageReceived(message);
// 只有当shouldShowNotification为true时才构建并显示通知
if (NotificationHelper.shouldShowNotification) {
int requestID = (int) System.currentTimeMillis();
String title = message.getNotification().getTitle();
String body = message.getNotification().getBody();
String click_action = message.getNotification().getClickAction();
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), "Notification");
builder.setContentTitle(title);
builder.setContentText(body);
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
builder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
builder.setLights(getResources().getColor(R.color.chitchat), 3000, 3000); // 确保chitchat颜色资源存在
builder.setSmallIcon(R.drawable.logowhite); // 确保logowhite图片资源存在
Intent intent = null;
if (Objects.requireNonNull(message.getData().get("type")).equalsIgnoreCase("privatechat")) {
intent = new Intent(click_action);
// 原始代码中的intent flag设置可能存在冗余或冲突,实际开发中应根据需求优化。
// 例如,如果目标是启动新任务并清除旧任务栈,则使用 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK。
// 如果目标是带回已存在的Activity到前台,则使用 FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP。
// 这里的第二次setFlags会覆盖第一次,导致最终只有 FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP 生效。
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("GCKey", message.getData().get("GCKey"));
intent.putExtra("GCNameKey", message.getData().get("GCNameKey"));
}
// PendingIntent.FLAG_IMMUTABLE 是Android S (API 31) 后的推荐做法
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestID, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE );
builder.setAutoCancel(true);
builder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("Notification", "Default channel", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(69, builder.build()); // 通知ID 69 可以替换为更具意义的ID
}
}
}说明:
- 在 onMessageReceived 方法的开头,我们添加了 if (NotificationHelper.shouldShowNotification) 条件判断。
- 只有当这个条件为真时,才会执行后续的通知构建和显示逻辑。如果条件为假(即用户正在目标Activity中),则消息会被接收但不会显示为通知。
注意事项与最佳实践
- 多Activity场景: 如果您有多个Activity都不希望显示通知,您可以在每个这样的Activity的 onResume() 和 onPause() 方法中重复上述逻辑。
- 应用进程被杀死: 这种静态变量的方法在应用进程被杀死后会失效。当应用进程被杀死时,静态变量会重置为默认值。如果您的应用在后台被杀死,然后收到消息,通知会正常显示。这通常是可接受的行为,因为用户已经离开了应用。
- 用户体验: 这种方法能够有效提升用户体验,避免不必要的打扰。但请确保在用户离开相关Activity后,通知能够及时恢复,以免错过重要信息。
- 线程安全: 对于简单的布尔标志,在主线程(UI线程)中访问通常不会有严重的线程安全问题。FirebaseMessagingService 的 onMessageReceived 方法通常在后台线程执行,而Activity生命周期方法在主线程执行。在大多数情况下,这种简单的静态布尔值操作是安全的。如果涉及到更复杂的共享状态,可能需要考虑 AtomicBoolean 或其他同步机制。
- Intent Flags: 原始代码中 Intent 的 setFlags 调用存在一些冗余和潜在冲突。FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK 通常用于启动一个全新的任务栈并清除旧的,而 FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP 则用于将现有任务栈中的指定Activity带到顶部并重用。当它们被连续调用时,后面的调用会覆盖前面的。在实际项目中,应根据具体导航需求选择合适的 Intent 标志组合。
总结
通过引入一个简单的静态辅助类和在Activity生命周期中对其进行管理,您可以有效地控制Android应用中Firebase推送通知的显示行为。这种方法简单、直接且易于实现,能够显著提升用户在特定场景下的应用体验,避免了冗余通知的干扰。










