You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用Firebase实时数据库变动时后台通知异常排查

问题:Firebase实时数据库变动时无法触发推送通知,仅控制台活动可正常推送

需求:Firebase实时数据库数据变动时,仅在应用未处于前台(未使用/未打开)时推送通知,前台时不推送。
现状:已创建MyFirebaseMessagingService类并编写代码,配置好Manifest及build.gradle依赖,但数据库变动时收不到通知,Logcat无Firebase Messaging相关日志;仅Firebase控制台创建推送活动时可正常收到通知。

用户提供代码:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";
    private DatabaseReference mDatabase;

    @Override
    public void onCreate() {
        super.onCreate();
        mDatabase = FirebaseDatabase.getInstance("XXXXx my url XXXXXX").getReference();

    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i(TAG, "From: " + remoteMessage.getFrom());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());

            // Get the value of the "attribute" key from the data payload
            String attributeValue = remoteMessage.getData().get("attribute");

            // Check if the app is not running or being used
            if (!isAppInForeground()) {

                // Send notification only if the attribute value has changed
                mDatabase.child("data").addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        String currentValue = dataSnapshot.getValue(String.class);
                        if (currentValue != null && !currentValue.equals(attributeValue)) {
                            sendNotification();
                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                        Log.w(TAG, "onCancelled", databaseError.toException());
                    }
                });
            }
        }
    }

    public boolean isAppInForeground() {
        // Check if the app is running in the foreground
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses();
        if (runningProcesses != null) {
            for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
                if (processInfo.processName.equals(getPackageName()) && processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                    return true;
                }
            }
        }
        return false;
    }

    public void sendNotification() {
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "channel_id")
                .setSmallIcon(R.drawable.notlogo)
                .setContentTitle("hi")
                .setContentText("test")
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_HIGH);

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        notificationBuilder.setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager != null) {
            notificationManager.notify(0, notificationBuilder.build());
        }
    }
}

问题根源分析

  1. 核心逻辑错误:你混淆了FCM消息与数据库监听的触发场景——数据库变动不会自动触发FCM消息,当前代码把数据库监听放在onMessageReceived(FCM消息回调)里,只有收到FCM推送时才会检查数据库,完全不符合“数据库变动触发通知”的需求。
  2. 前台判断方法过时:getRunningAppProcesses()在Android 8.0+已标记为过时,且准确性不足。
  3. 通知通道未初始化:Android 8.0+必须创建通知通道才能显示通知,代码直接使用channel_id但无通道创建逻辑。
  4. 日志无输出原因:数据库变动根本没触发onMessageReceived,自然不会产生相关日志,只有控制台发送FCM消息时才会进入该方法。

修复步骤

1. 正确监听Firebase数据库变动

将数据库监听逻辑移到Application类(全局生效),确保数据库一变动就触发检查:

public class MyApp extends Application {
    private DatabaseReference mDatabase;
    private String lastKnownValue;

    @Override
    public void onCreate() {
        super.onCreate();
        mDatabase = FirebaseDatabase.getInstance("你的数据库URL").getReference("data");
        
        // 初始化时获取当前值,避免首次监听误触发通知
        mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                lastKnownValue = dataSnapshot.getValue(String.class);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.w("MyApp", "初始化获取数据失败", databaseError.toException());
            }
        });

        // 实时监听数据库变动
        mDatabase.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                String currentValue = dataSnapshot.getValue(String.class);
                // 检查值是否变化且应用在后台
                if (currentValue != null && !currentValue.equals(lastKnownValue) && !isAppInForeground()) {
                    sendNotification();
                    lastKnownValue = currentValue; // 更新记录值,避免重复通知
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.w("MyApp", "数据库监听失败", databaseError.toException());
            }
        });
    }

    // 更可靠的前台判断逻辑
    private boolean isAppInForeground() {
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        if (am == null) return false;
        List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
        if (processes == null) return false;
        for (ActivityManager.RunningAppProcessInfo processInfo : processes) {
            if (processInfo.processName.equals(getPackageName())) {
                return processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                        || processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
            }
        }
        return false;
    }

    private void sendNotification() {
        // Android 8.0+必须创建通知通道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "channel_id",
                    "数据库变动通知",
                    NotificationManager.IMPORTANCE_HIGH
            );
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
            }
        }

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "channel_id")
                .setSmallIcon(R.drawable.notlogo)
                .setContentTitle("数据更新提醒")
                .setContentText("数据库内容已变动")
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_HIGH);

        Intent intent = new Intent(this, MainActivity.class);
        // Android 12+必须添加FLAG_IMMUTABLE/FLAG_MUTABLE
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );
        notificationBuilder.setContentIntent(pendingIntent);

        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        if (notificationManager != null) {
            notificationManager.notify(1, notificationBuilder.build()); // 用不同ID避免覆盖通知
        }
    }
}

2. 配置Manifest注册Application类

<application
    android:name=".MyApp"
    ...>
    <!-- 其他组件配置 -->
</application>

3. 优化FCM服务(仅处理控制台推送)

保留MyFirebaseMessagingService用于处理控制台发送的FCM消息,移除数据库监听逻辑:

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i(TAG, "收到FCM消息: " + remoteMessage.getFrom());
        // 仅后台时显示控制台推送
        if (!isAppInForeground()) {
            sendNotification();
        }
    }

    private boolean isAppInForeground() {
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        if (am == null) return false;
        List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
        if (processes == null) return false;
        for (ActivityManager.RunningAppProcessInfo processInfo : processes) {
            if (processInfo.processName.equals(getPackageName())) {
                return processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                        || processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
            }
        }
        return false;
    }

    private void sendNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "channel_id",
                    "FCM推送通知",
                    NotificationManager.IMPORTANCE_HIGH
            );
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
            }
        }

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "channel_id")
                .setSmallIcon(R.drawable.notlogo)
                .setContentTitle("FCM推送")
                .setContentText("控制台发送的通知")
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_HIGH);

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );
        notificationBuilder.setContentIntent(pendingIntent);

        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        if (notificationManager != null) {
            notificationManager.notify(2, notificationBuilder.build());
        }
    }
}

4. 关键注意事项

  • 后台持久监听:Android 12+后台限制严格,若需应用后台持续监听数据库,需结合WorkManager或前台服务实现,否则应用后台一段时间后会被系统杀死,监听失效。
  • 日志调试:在数据库监听的onDataChange中添加日志(如Log.d("MyApp", "数据库值变动: " + currentValue)),确认回调是否触发。

内容的提问来源于stack exchange,提问作者Sanjith Kumar M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:35:06