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

在SharedPreference中存储全局布尔值失效问题求助

问题分析与解决方案

兄弟,我太懂你一下午折腾无果的崩溃了——刚上手Firebase推送确实容易踩这些隐蔽的小坑!咱们来拆解一下你遇到的问题:

核心可能原因:FCM通知类型的“隐形规则”

这是新手最容易踩的坑:Firebase Cloud Messaging(FCM)分两种消息类型,通知消息和数据消息,它们的处理逻辑完全不同:

  • 如果是从Firebase控制台发送的纯通知消息(只填了Notification标签的内容),当你的App在后台时,FCM会直接把通知推送到系统托盘,根本不会经过你的FirebaseMessagingService的onMessageReceived()方法!这时候你在Service里写的SharedPreferences判断完全没机会执行。
  • 只有数据消息(只填Data标签),或者组合消息(同时填了Notification和Data),才会让onMessageReceived()触发,你的判断逻辑才能生效。

其他可能的排查点

  1. SharedPreferences的上下文一致性
    你在Activity里用mContext.getSharedPreferences("notifications", MODE_PRIVATE)存储,在Service里用getApplicationContext().getSharedPreferences(...)获取,理论上是同一个实例,但保险起见,在Service里直接用getSharedPreferences("notifications", MODE_PRIVATE)试试(Service本身就是Context子类),避免上下文差异导致的读取问题。

  2. apply()的异步特性
    editor.apply()是异步写入磁盘的,如果存储后立刻发送测试通知,可能还没完成写入。排查时可以临时换成editor.commit()(同步写入)测试,确认写入后再改回apply()(推荐用apply,因为不阻塞主线程)。

修复后的完整示例代码

1. 确保存储逻辑正确

// 存储布尔值的代码(Activity中)
SharedPreferences notificationsPref = getSharedPreferences("notifications", MODE_PRIVATE);
SharedPreferences.Editor editor = notificationsPref.edit();
editor.putBoolean("receiveNotifications", false);
editor.apply(); // 测试时可临时换成editor.commit()

2. FirebaseMessagingService中的正确处理

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // 处理数据消息(无论App前后台都会触发)
        if (remoteMessage.getData().size() > 0) {
            String contentTitle = remoteMessage.getData().get("title");
            String messageBody = remoteMessage.getData().get("body");
            handleNotification(contentTitle, messageBody);
        }

        // 处理通知消息(只有App在前台时才会走到这里)
        if (remoteMessage.getNotification() != null) {
            String contentTitle = remoteMessage.getNotification().getTitle();
            String messageBody = remoteMessage.getNotification().getBody();
            handleNotification(contentTitle, messageBody);
        }
    }

    private void handleNotification(String title, String body) {
        // 读取SharedPreferences的开关状态
        SharedPreferences sharedPreferences = getSharedPreferences("notifications", MODE_PRIVATE);
        Boolean areNotificationsAllowed = sharedPreferences.getBoolean("receiveNotifications", true);
        
        if (areNotificationsAllowed) {
            sendNotification(title, body);
        }
    }

    // 适配Android O及以上的通知发送逻辑
    private void sendNotification(String title, String body) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this, 
                0, 
                intent, 
                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE
        );

        String channelId = "app_notification_channel";
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this, channelId)
                        .setSmallIcon(R.drawable.ic_notification)
                        .setContentTitle(title)
                        .setContentText(body)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // 创建通知渠道(Android O及以上必需)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    channelId,
                    "应用通知",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0, notificationBuilder.build());
    }
}

测试注意事项

测试时一定要发送数据消息或者组合消息,比如用接口工具调用FCM的API发送:

{
  "to": "你的设备推送Token",
  "data": {
    "title": "测试标题",
    "body": "测试内容"
  }
}

这样才能确保你的onMessageReceived()被触发,开关逻辑生效。

内容的提问来源于stack exchange,提问作者Mwikala Kangwa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:48:34