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

Android纪念日应用定时通知失效问题求助

问题分析与解决方案

你的代码存在多个关键问题,导致通知无法正常触发,下面逐一拆解并给出修正方案:

核心问题梳理

  1. 语法错误:startAlarmBroadcastReceiver方法嵌套在onCreate内部,Java不允许方法嵌套定义。
  2. 未执行闹钟设置:定义了启动闹钟的方法,但没有在任何地方调用,导致闹钟从未被初始化。
  3. 通知渠道缺失:Android 8.0+必须创建通知渠道,否则通知完全无法显示。
  4. 闹钟触发可靠性不足:使用的AlarmManager.set()在系统Doze模式下会被延迟/忽略,且当前代码仅设置单次触发,未处理年度重复逻辑。
  5. 重启后闹钟失效:设备重启后,之前设置的闹钟会被清除,需添加开机广播接收器恢复闹钟。

修正后的完整代码

1. MainActivity 修正

package fr.me.ephemeride;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.util.Calendar;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 调用闹钟设置方法
        startAlarmBroadcastReceiver(this);
        Toast.makeText(this, "纪念日闹钟已设置", Toast.LENGTH_SHORT).show();
    }

    // 移至类内部,避免方法嵌套
    public static void startAlarmBroadcastReceiver(Context context) {
        Intent intent = new Intent(context, AlarmBroadcastReceiver.class);
        // 使用唯一requestCode,防止重复设置时覆盖原有闹钟
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        
        // 先取消旧闹钟,避免重复触发
        alarmManager.cancel(pendingIntent);
        
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        // 设置触发规则:每年12月25日9:00
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH, 25);
        calendar.set(Calendar.HOUR_OF_DAY, 9);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        
        // 如果当前已过今年的触发时间,自动设置为明年
        if (calendar.getTimeInMillis() < System.currentTimeMillis()) {
            calendar.add(Calendar.YEAR, 1);
        }
        
        // 针对不同Android版本选择可靠的闹钟触发方式
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            // Doze模式下也能精准触发
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        } else {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        }
    }
}

2. AlarmBroadcastReceiver 修正(添加通知渠道创建)

package fr.me.ephemeride;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;

import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

public class AlarmBroadcastReceiver extends BroadcastReceiver {

    private static final String CHANNEL_ID = "My notification";

    @Override
    public void onReceive(Context context, Intent intent) {
        // Android 8.0+必须先创建通知渠道
        createNotificationChannel(context);
        showNotification(context);
    }

    private void createNotificationChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence channelName = "纪念日通知";
            String channelDesc = "发送纪念日、节日相关提醒";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, channelName, importance);
            channel.setDescription(channelDesc);
            
            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }

    void showNotification(Context context) {
        Intent intent = new Intent(context, calendrier_japonais.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
        builder.setContentTitle("圣诞节提醒");
        builder.setContentText("今天是圣诞节,别忘了相关的纪念日哦!");
        builder.setSmallIcon(R.drawable.icon_nebra_foreground);
        builder.setAutoCancel(true);
        builder.setContentIntent(pendingIntent);
        builder.setOnlyAlertOnce(true);

        NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
        // 使用唯一通知ID,避免覆盖其他通知
        managerCompat.notify(101, builder.build());
    }
}

3. AndroidManifest.xml 修正(添加权限与开机广播)

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="fr.me.ephemeride">

    <!-- 开机重启权限:用于重启后恢复闹钟 -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <!-- Android 13+ 通知权限:必须动态申请 -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Ephemeride">
        
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <activity android:name=".calendrier_japonais" />

        <!-- 闹钟广播接收器 -->
        <receiver android:name=".AlarmBroadcastReceiver" />
        
        <!-- 开机重启广播接收器:恢复闹钟设置 -->
        <receiver
            android:name=".BootCompletedReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

4. 新增开机重启接收器 BootCompletedReceiver

package fr.me.ephemeride;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BootCompletedReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 设备重启后重新设置闹钟
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) || 
            Intent.ACTION_QUICKBOOT_POWERON.equals(intent.getAction())) {
            MainActivity.startAlarmBroadcastReceiver(context);
        }
    }
}

额外注意事项

  • Android 13+ 通知权限:需要在MainActivity中动态申请POST_NOTIFICATIONS权限,否则通知无法显示。
  • 测试技巧:可以临时将触发时间设置为当前时间的几分钟后,快速验证闹钟和通知是否生效。
  • 每日名言通知:如果需要每日触发,可调整闹钟逻辑为每次触发后设置下一天的时间(使用setExactAndAllowWhileIdle保证可靠性)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 19:38:10