【问题标题】:How To give notifications on android on specific time?如何在特定时间在android上发出通知?
【发布时间】:2015-12-29 19:13:17
【问题描述】:

我想在特定时间向我的应用发出通知。说每天早上 7 点我必须通知,即使应用程序已关闭。

我该怎么做?有教程吗? 请注明链接。

【问题讨论】:

    标签: android android-notifications


    【解决方案1】:

    首先您需要使用广播接收器。并且因为广播接收器只启动了很短的时间

    来自 android 开发者博客。处理广播时,应用程序有固定的时间(当前为 10 秒)来完成其工作。如果在这段时间内没有完成,则认为应用程序行为不端,它的进程会立即进入后台状态,以便在需要时将其杀死以获取内存。

    在此处使用意图服务是一种更好的做法,您有一个示例。

    这是广播接收器类。

    public class MyReceiver extends BroadcastReceiver {
        public MyReceiver() {
        }
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
            Intent intent1 = new Intent(context, MyNewIntentService.class);
            context.startService(intent1);
        }
    }
    

    并在清单中注册。

    <receiver
        android:name=".MyReceiver"
        android:enabled="true"
        android:exported="false" >
    </receiver>
    

    这是意图服务类。

    public class MyNewIntentService extends IntentService {
        private static final int NOTIFICATION_ID = 3;
    
        public MyNewIntentService() {
            super("MyNewIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            Notification.Builder builder = new Notification.Builder(this);
                builder.setContentTitle("My Title");
                builder.setContentText("This is the Body");
                builder.setSmallIcon(R.drawable.whatever);
            Intent notifyIntent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 2, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            //to be able to launch your activity from the notification 
            builder.setContentIntent(pendingIntent);
            Notification notificationCompat = builder.build();
            NotificationManagerCompat managerCompat = NotificationManagerCompat.from(this);
            managerCompat.notify(NOTIFICATION_ID, notificationCompat);
        }
    }
    

    并在清单中注册。

    <service
        android:name=".MyNewIntentService"
        android:exported="false" >
    </service>
    

    然后在您的活动中设置警报管理器以在特定时间启动广播接收器并使用 AlarmManager setRepeating 方法重复它下面的示例将每天重复它。

     Intent notifyIntent = new Intent(this,MyReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast
                (context, NOTIFICATION_REMINDER_NIGHT, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,  System.currentTimeMillis(),
                1000 * 60 * 60 * 24, pendingIntent);
    

    希望对你有帮助。

    【讨论】:

    • 不适合我,尝试手动设置时间但仍然无法正常工作。
    • 使用广播有什么理由吗?不要认为这是必要/有用的。您可以使用 PendingIntent 直接与您的 IntentService 对话。
    • 在 Pie 版本中可以使用吗?似乎没有这样做:(
    • @NarendraSingh 那是因为您需要 android O 及更高版本的通知通道。见developer.android.com/training/notify-user/…
    【解决方案2】:

    您可以使用AlarmManager在指定时间设置闹钟

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    if (!prefs.getBoolean("firstTime", false)) {
    
        Intent alarmIntent = new Intent(this, AlarmReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
    
        AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(Calendar.HOUR_OF_DAY, 7);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 1);
    
        manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                AlarmManager.INTERVAL_DAY, pendingIntent);
    
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean("firstTime", true);
        editor.apply();
    }
    

    我使用SharedPreferences 来检查这不是第一次运行应用程序,如果是,则设置警报,否则什么都不做,而不是在每次启动应用程序时重置警报。
    警报发生时使用BroadcastReceiver 进行监听

    public class AlarmReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // show toast
            Toast.makeText(context, "Alarm running", Toast.LENGTH_SHORT).show();
        }
    }
    

    使用另一个接收器来收听设备启动,以便您可以重置警报

    public class DeviceBootReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
                // on device boot compelete, reset the alarm
                Intent alarmIntent = new Intent(context, AlarmReceiver.class);
                PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
    
                AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(System.currentTimeMillis());
                calendar.set(Calendar.HOUR_OF_DAY, 7);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 1);
    
                manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
                        AlarmManager.INTERVAL_DAY, pendingIntent);
            }
        }
    }
    

    将权限添加到清单

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    

    然后注册你的接收器

    <receiver android:name=".DeviceBootReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <receiver android:name=".AlarmReceiver" />
    

    【讨论】:

    • 如果打开应用也要发送通知呢?
    • 您可以在您的启动器活动的onCreate()方法中添加通知代码。
    • 感谢您的回复。 SharedPReference 第二天将如何工作?因为布尔值会是假的
    • 不客气。 SharedPreferences 应该只在应用程序第一次启动设置警报的情况下工作一次,然后它将布尔值设置为 true,即应用程序之前启动,以避免一遍又一遍地重置警报。
    • 如果您的意图神奇地消失了,您可能需要设置一个标志:see this answer。此外,如果您的 Serializable 对象未包装在 Bundle: see this answer 中,它们可能会为 null。
    【解决方案3】:

    由于后台服务限制 (https://developer.android.com/about/versions/oreo/background.html#services),来自已接受答案的解决方案将无法在 Android 8 Oreo(api 级别 26)及更高版本上正常运行,并且当应用在后台:

    java.lang.IllegalStateException: Not allowed to start service Intent xxx: app is in background
    

    一种可能的解决方法是使用JobIntentService

    1. JobIntentService 扩展您的Service 而不是IntentService 并使用onHandleWork 方法而不是onHandleIntent

    2. AndroidManifest.xml 中将android:permission="android.permission.BIND_JOB_SERVICE" 添加到您的Service

    【讨论】:

    • 此方法在使用已接受答案中给出的代码时不起作用,并根据您的说明进行修改。它没有打电话给BroadCastReceiver。我该如何解决?
    • 不看你的代码很难说。如果您的接收器有问题,它发生在开始服务之前,我的意思是无论您使用我的建议还是接受器的回答。您是否在清单中注册了您的接收器?
    • 为什么不把服务全部去掉呢?设置通知应该足够快,以便在 BroadcastReceiver 中完成。
    【解决方案4】:

    这是我的解决方案,在 android 10 上进行了测试。还兼容所有以前版本的android。

    MainActivity.class

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        ....
        reminderNotification();
    
    }
    
    public void reminderNotification()
    {
        NotificationUtils _notificationUtils = new NotificationUtils(this);
        long _currentTime = System.currentTimeMillis();
        long tenSeconds = 1000 * 10;
        long _triggerReminder = _currentTime + tenSeconds; //triggers a reminder after 10 seconds.
        _notificationUtils.setReminder(_triggerReminder);
    }
    

    NotificationUtils.class

    public class NotificationUtils extends ContextWrapper
    {
    
        private NotificationManager _notificationManager;
        private Context _context;
    
        public NotificationUtils(Context base)
        {
            super(base);
            _context = base;
            createChannel();
        }
    
        public NotificationCompat.Builder setNotification(String title, String body)
        {
            return new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.noti_icon)
                    .setContentTitle(title)
                    .setContentText(body)
                    .setAutoCancel(true)
                    .setPriority(NotificationCompat.PRIORITY_DEFAULT);
        }
    
        private void createChannel()
        {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            {
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID, TIMELINE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
                channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
                getManager().createNotificationChannel(channel);
            }
        }
    
        public NotificationManager getManager()
        {
            if(_notificationManager == null)
            {
                _notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            }
    
            return _notificationManager;
        }
    
        public void setReminder(long timeInMillis)
        {
            Intent _intent = new Intent(_context, ReminderBroadcast.class);
            PendingIntent _pendingIntent = PendingIntent.getBroadcast(_context, 0, _intent, 0);
    
            AlarmManager _alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    
            _alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, _pendingIntent);
        }
    
    }
    

    ReminderBroadcast.class

    public class ReminderBroadcast extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            NotificationUtils _notificationUtils = new NotificationUtils(context);
            NotificationCompat.Builder _builder = _notificationUtils.setNotification("Testing", "Testing notification system");
            _notificationUtils.getManager().notify(101, _builder.build());
        }
    }
    

    AndroidManifest.xml

    <application>
        ...
        <receiver android:name=".custom.ReminderBroadcast"/>
    </application>
    

    注意:CHANNEL_IDTIMELINE_CHANNEL_NAME,已在另一个类上创建。

    例如,

    CHANNEL_ID = "notification channel";

    TIMELINE_CHANNEL_NAME = "Timeline notification";

    对我的代码和错误有任何误解,请随时发表评论。我会尽快回复。

    【讨论】:

      【解决方案5】:
      • 从系统中获取报警服务。
      • 制作一个挂起的意图,传入广播接收器类的名称。
      • 制作一个日历对象并将其时间设置为上午 8 点。
      • 检查当前时间是否超过 8 点。如果是,则再增加一天。
      • 调用AlarmManager类的设置重复方法。

      相同的示例代码:

      alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);   
      alarmIntent = new Intent(context of current file, AlarmReceiver1.class); 
      AlarmReceiver1 = broadcast receiver
      
          pendingIntent = PendingIntent.getBroadcast(  Menu.this, 0, alarmIntent, 
      PendingIntent.FLAG_UPDATE_CURRENT);
          alarmIntent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
          alarmManager.cancel(pendingIntent);
      
          Calendar alarmStartTime = Calendar.getInstance();
          Calendar now = Calendar.getInstance();
          alarmStartTime.set(Calendar.HOUR_OF_DAY, 8);
          alarmStartTime.set(Calendar.MINUTE, 00);
          alarmStartTime.set(Calendar.SECOND, 0);
          if (now.after(alarmStartTime)) {
              Log.d("Hey","Added a day");
              alarmStartTime.add(Calendar.DATE, 1);
          }
      
           alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 
      alarmStartTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
           Log.d("Alarm","Alarms set for everyday 8 am.");
      

      来到广播接收器类。您需要在清单中注册广播接收器。这将导致您接收时钟事件。 覆盖此广播接收器的 onReceive 方法并在那里自己发出通知或制作单独的通知构建服务并在那里构建和显示您的通知。

      清单代码sn-p:

      广播接收代码sn-p:

      public class AlarmReceiver1 extends BroadcastReceiver {
      
      @Override
      public void onReceive(Context context, Intent intent) {
        Intent service1 = new Intent(context, NotificationService1.class);
      service1.setData((Uri.parse("custom://"+System.currentTimeMillis())));
                context.startService(service1);
      }
      

      通知构建服务代码sn-p:

      public class NotificationService1 extends IntentService{
      
      private NotificationManager notificationManager;
      private PendingIntent pendingIntent;
      private static int NOTIFICATION_ID = 1;
      Notification notification;
      @Override
      protected void onHandleIntent(Intent intent) {
      Context context = this.getApplicationContext();
             notificationManager = 
      (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
      Intent mIntent = new Intent(this, Activity to be opened after clicking on the 
      notif);
              Bundle bundle = new Bundle(); 
              bundle.putString("test", "test");
              mIntent.putExtras(bundle);
              pendingIntent = PendingIntent.getActivity(context, 0, mIntent, 
      PendingIntent.FLAG_UPDATE_CURRENT);     
      
              Resources res = this.getResources();
              NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
              Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
              notification = new NotificationCompat.Builder(this)
                          .setContentIntent(pendingIntent)
                          .setSmallIcon(R.drawable.ic_launcher)
                          .setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
                          .setTicker("ticker value")
                          .setAutoCancel(true)
                          .setPriority(8)
                          .setSound(soundUri)
                          .setContentTitle("Notif title")
                          .setContentText("Text").build();
              notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
              notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
              notification.ledARGB = 0xFFFFA500;
              notification.ledOnMS = 800;
              notification.ledOffMS = 1000;
              notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
              notificationManager.notify(NOTIFICATION_ID, notification);
              Log.i("notif","Notifications sent.");
      
      }
      
      }
      

      【讨论】:

        【解决方案6】:

        使用 NotifyMe Android 库进行简单通知。当您希望弹出通知时,非常容易设置延迟或时间。系统重启后会弹出通知。

        使用 Jitpack.io 下载库 将此添加到您的应用的 build.gradle 文件中。

        allprojects {
            repositories {
                ...
                maven { url 'https://jitpack.io' }
            }
        }
        

        将此添加到项目的 build.gradle 中的依赖项中。

        dependencies {
                implementation 'com.github.jakebonk:NotifyMe:1.0.1'
        }
        

        示例 创建一个 NotifyMe 构建器对象

        NotifyMe.Builder notifyMe = new NotifyMe.Builder(getApplicationContext());
        

        然后设置你想要的字段。

        notifyMe.title(String title);
        notifyMe.content(String content);
        notifyMe.color(Int red,Int green,Int blue,Int alpha);//Color of notification header
        notifyMe.led_color(Int red,Int green,Int blue,Int alpha);//Color of LED when 
        notification pops up
        notifyMe.time(Calendar time);//The time to popup notification
        notifyMe.delay(Int delay);//Delay in ms
        notifyMe.large_icon(Int resource);//Icon resource by ID
        notifyMe.rrule("FREQ=MINUTELY;INTERVAL=5;COUNT=2")//RRULE for frequency of 
        //notification
        notifyMe.addAction(Intent intent,String text); //The action will call the intent when 
        //pressed
        

        在你想要的所有字段都设置好之后,只需调用 build()!

        notifyMe.build();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-09-15
          • 1970-01-01
          • 1970-01-01
          • 2012-12-23
          • 1970-01-01
          • 2018-07-19
          • 1970-01-01
          相关资源
          最近更新 更多