Android的日常闹铃射击往往还是只有一次 [英] Android daily alarm firing too often or only once

查看:122
本文介绍了Android的日常闹铃射击往往还是只有一次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个每日提醒功能在我的Andr​​oid应用程序,这应该触发一次,每天在设定的时间。第一个实现我想工作对于大多数人来说,但用户的一些子集(其中至少有一人在三星运行在Android 4.3)的报告说,报警的射击方式更加往往比它应该,例如:每10分钟,每一个他们打开的应用程序,只是时间一般是很烦人的。

这里的报警器是如何启用:

 意图myIntent =新的意图(CTX,AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(CTX,0,myIntent,0);

AlarmManager alarmManager =(AlarmManager)ctx.getSystemService(Service.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,排程,
                AlarmManager.INTERVAL_DAY,
                pendingIntent);
 

再有就是这个AlarmReceiver类:

 公共类AlarmReceiver扩展的BroadcastReceiver {

    @覆盖
    公共无效的onReceive(上下文的背景下,意图意图){
        // TODO自动生成方法存根

           意图服务1 =新的意图(背景下,AlarmService.class);
           context.startService(服务1);
    }

}
 

这是注册为AndroidManifest接收器:<接收机器人:名称=。AlarmReceiver/>

最后,还有的AlarmService,曾经是这样的:

 公共类AlarmService延伸服务{

    @覆盖
    公众的IBinder onBind(意向为arg0){
        // TODO自动生成方法存根
        返回null;
    }


    @覆盖
    公共无效的onCreate()
    {
       // TODO自动生成方法存根
       super.onCreate();
    }

   @燮pressWarnings(静态访问)
   @覆盖
   公共无效ONSTART(意向意图,诠释startId)
   {
       super.onStart(意向,startId);

       Log.v(PM,关于通知);

       意图int​​ent1 =新的意图(this.getApplicationContext(),MainActivity.class);
       intent1.setAction(Intent.ACTION_MAIN);
       intent1.addCategory(Intent.CATEGORY_LAUNCHER);
       //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

       PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this.getApplicationContext(),0,intent1,PendingIntent.FLAG_UPDATE_CURRENT);

       通知通知=新Notification.Builder(this.getApplicationContext())
                                       .setContentTitle(我的应用)
                                       .setContentText(不要忘了那件事!)
                                       .setSmallIcon(R.drawable.ic_launcher)
                                       .setWhen(System.currentTimeMillis的())
                                       .setContentIntent(pendingNotificationIntent)
                                       。得到通知();

       notification.flags | = Notification.FLAG_AUTO_CANCEL;
       notification.defaults | = Notification.DEFAULT_SOUND;
       notification.defaults | = Notification.DEFAULT_VIBRATE;

       NotificationManager nManager =
                (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
       nManager.notify(0,通知);
    }

    @覆盖
    公共无效的onDestroy()
    {
        // TODO自动生成方法存根
        super.onDestroy();
    }
}
 

不过,正如我说的,人报告说,这种解雇每隔十分钟左右!所以,我试图改变AlarmService到少去precated实现,但在现在这个过程的人说,它仅触发一次,然后再也没有!

我换成 ONSTART 这一点:

  @覆盖
 公众诠释onStartCommand(意向意图,诠释标志,INT startId)
 {
       Log.v(PM,关于通知);

   如果(意向!= NULL){
       意图int​​ent1 =新的意图(this.getApplicationContext(),MainActivity.class);
       intent1.setAction(Intent.ACTION_MAIN);
       intent1.addCategory(Intent.CATEGORY_LAUNCHER);
       //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

       PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this.getApplicationContext(),0,intent1,PendingIntent.FLAG_UPDATE_CURRENT);

       通知通知=新Notification.Builder(this.getApplicationContext())
                                       .setContentTitle(我的应用)
                                       .setContentText(不要忘了那件事!)
                                       .setSmallIcon(R.drawable.ic_launcher)
                                       .setWhen(System.currentTimeMillis的())
                                       .setContentIntent(pendingNotificationIntent)
                                       。得到通知();

       notification.flags | = Notification.FLAG_AUTO_CANCEL;
       notification.defaults | = Notification.DEFAULT_SOUND;
       notification.defaults | = Notification.DEFAULT_VIBRATE;

       NotificationManager nManager =
                (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
       nManager.notify(0,通知);
   } 其他 {
       Log.v(下午,空意图);
   }

   返回START_STICKY;
}
 

因为我不能在我的设备重现原来的问题,这是一个有点难以测试!我的两个理论是:

  1. 问题在于AlarmReceiver,喜欢它应该不会首发了全新的服务,但做一些与现有服务
  2. 在我不该打扰排除空在我的 onStartCommand 函数的意图

我只是有点紧张,试图号2情况下,它引起了人们的设备再次惹恼了他们!

解决方案
  

这里的报警器是如何启用

请注意,这将是不准确的在Android 4.4+,即使您正在使用 setRepeating(),一旦你提高你的安卓targetSdkVersion 19或更高。

  

再有就是这个AlarmReceiver类

这不会是可靠与 _WAKEUP 式的报警。它绝对有可能的设备睡着了 startService()呼叫,当您的服务实际上得到机会做一些事情的。请<一href="http://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html"相对=nofollow>使用 WakefulBroadcastReceiver 或的我的 WakefulIntentService _WAKEUP 式的报警,如果你要使用的委托到一个 - 服务模式。

  

但在现在这个过程的人说,它每天只有一次火灾!

因为这是你想要什么,我会认为这是一件好事。

  

我取代ONSTART这一点:

我不知道为什么你使用的是服务,而不是 IntentService 。无论如何,请致电 stopSelf()在你的 onStartCommand()法的底部,因此该服务就会消失。没有理由为这个服务保持运行,一旦这项工作完成。此外,替换 START_STICKY START_NOT_STICKY

和,如果这是你想要做的服务工作,你可以完全转储服务和移动你的 onStartCommand()胆量到的onReceive()的BroadcastReceiver

委托工作,从接收服务的模式时使用的工作将需要很长时间去冒险占用主应用程序线程(如> 1毫秒)......但那么你的服务需要后台线程,这你所缺乏的。因为我希望你code小于在执行时间1ms,你可能只是做,在的onReceive()并简化您的应用程序,你将不再需要单独的服务,也没有任何的清醒* 的东西,我前面提到的。

  

问题在于AlarmReceiver,喜欢它应该不会首发了全新的服务,但做一些与现有服务

如果这只能运行一次,每天,有更好的不会是一个现有的服务。没有必要让你有一个正在运行的进程,占用系统内存,只是在等待时钟滴答。

  

我不应该打扰我的onStartCommand功能不包括空意图值

您将获得 意图,如果:

  • 您进程终止的服务完成了 onStartCommand() startService()呼叫之前,以及

  • 您的服务已成功运行 onStartCommand()之前,并返回 START_STICKY

  

我越来越想知道为什么我AlarmReceiver创建一个服务,而不仅仅是直接显示出该通知。

同意。如果您计划在其它更多的工作,涉及到磁盘或网络I / O,然后的使用 IntentService (后台线程,服务会自动停止本身)。否则,我只是把这个的onReceive()并调用它好。

I'm trying to implement a "daily reminder" function in my Android app, that should fire once per day at a set time. The first implementation I tried worked for most people, but some subset of users (including at least one person running on Android 4.3 on a Samsung) were reporting that the alarm was firing WAY more often than it should, e.g. every 10 minutes, and every time they opened the app, and just generally being very annoying.

Here's how the alarm is enabled:

Intent myIntent = new Intent(ctx, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, 0, myIntent,0);

AlarmManager alarmManager = (AlarmManager)ctx.getSystemService(Service.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, sched, 
                AlarmManager.INTERVAL_DAY, 
                pendingIntent);

Then there's this AlarmReceiver class:

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub

           Intent service1 = new Intent(context, AlarmService.class);
           context.startService(service1);
    }

}

This is registered as a receiver in the AndroidManifest: <receiver android:name=".AlarmReceiver"/>

Finally there's the AlarmService, which used to look like this:

public class AlarmService extends Service { 

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }


    @Override
    public void onCreate() 
    {
       // TODO Auto-generated method stub  
       super.onCreate();
    }

   @SuppressWarnings("static-access")
   @Override
   public void onStart(Intent intent, int startId)
   {
       super.onStart(intent, startId);

       Log.v("pm", "about to notify");

       Intent intent1 = new Intent(this.getApplicationContext(), MainActivity.class);
       intent1.setAction(Intent.ACTION_MAIN);
       intent1.addCategory(Intent.CATEGORY_LAUNCHER);
       //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);

       PendingIntent pendingNotificationIntent = PendingIntent.getActivity( this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT);

       Notification notification = new Notification.Builder(this.getApplicationContext())
                                       .setContentTitle("My App")
                                       .setContentText("Don't forget that thing!")
                                       .setSmallIcon(R.drawable.ic_launcher)
                                       .setWhen(System.currentTimeMillis())
                                       .setContentIntent(pendingNotificationIntent)
                                       .getNotification();                     

       notification.flags |= Notification.FLAG_AUTO_CANCEL;
       notification.defaults |= Notification.DEFAULT_SOUND;
       notification.defaults |= Notification.DEFAULT_VIBRATE;

       NotificationManager nManager = 
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
       nManager.notify(0, notification);
    }

    @Override
    public void onDestroy() 
    {
        // TODO Auto-generated method stub
        super.onDestroy();
    }
}

However, as I say, people were reporting that this fired every ten minutes or so! So I tried changing the AlarmService to a less deprecated implementation, but in the process now people are saying it only fires once, and then never again!

I replaced onStart with this:

 @Override
 public int onStartCommand(Intent intent, int flags, int startId)
 {
       Log.v("pm", "about to notify");

   if (intent != null) {
       Intent intent1 = new Intent(this.getApplicationContext(), MainActivity.class);
       intent1.setAction(Intent.ACTION_MAIN);
       intent1.addCategory(Intent.CATEGORY_LAUNCHER);
       //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);

       PendingIntent pendingNotificationIntent = PendingIntent.getActivity( this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT);

       Notification notification = new Notification.Builder(this.getApplicationContext())
                                       .setContentTitle("My App")
                                       .setContentText("Don't forget that thing!")
                                       .setSmallIcon(R.drawable.ic_launcher)
                                       .setWhen(System.currentTimeMillis())
                                       .setContentIntent(pendingNotificationIntent)
                                       .getNotification();                     

       notification.flags |= Notification.FLAG_AUTO_CANCEL;
       notification.defaults |= Notification.DEFAULT_SOUND;
       notification.defaults |= Notification.DEFAULT_VIBRATE;

       NotificationManager nManager = 
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
       nManager.notify(0, notification);
   } else {
       Log.v("pm", "Null Intent");
   }

   return START_STICKY;
}

Since I can't reproduce the original issue on my devices, it's a bit hard to test! My two theories are:

  1. The problem lies in AlarmReceiver, like it ought to not be starting up a brand new service but doing something with the existing service
  2. I shouldn't bother excluding null intent values in my onStartCommand function

I'm just a little nervous to try number 2 in case it causes people's devices to annoy them again!

解决方案

Here's how the alarm is enabled

Note that this will be inexact on Android 4.4+, even though you are using setRepeating(), once you raise your android:targetSdkVersion to 19 or higher.

Then there's this AlarmReceiver class

That will not be reliable with a _WAKEUP-style alarm. It is eminently possible for the device to fall asleep between the startService() call and when your service actually gets a chance to do something. Please use WakefulBroadcastReceiver or my WakefulIntentService for _WAKEUP-style alarms if you are going to use the delegate-to-a-service pattern.

but in the process now people are saying it only fires once per day!

Since that is what you want, I would think that this is a good thing.

I replaced onStart with this:

I do not know why you are using a Service instead IntentService. Regardless, please call stopSelf() at the bottom of your onStartCommand() method, so the service goes away. There is no reason for this service to stay running once this work is completed. Also, replace START_STICKY with START_NOT_STICKY.

And, if this is all the work you intend to do in the service, you could dump the service entirely and move your onStartCommand() guts into onReceive() of the BroadcastReceiver.

The pattern of delegating work to a service from a receiver is used when the work will take too long to risk tying up the main application thread (e.g., >1ms)... but then your service needs a background thread, which yours lacks. Since I would expect your code to be less than 1ms in execution time, you could just do that in onReceive() and simplify your app, you would no longer need the separate Service, nor any of the Wakeful* stuff I mentioned earlier.

The problem lies in AlarmReceiver, like it ought to not be starting up a brand new service but doing something with the existing service

If this only runs once per day, there better not be an "existing service". There is no need for you to have a running process, tying up system RAM, just waiting for the clock to tick.

I shouldn't bother excluding null intent values in my onStartCommand function

You will get a null Intent if:

  • Your process was terminated before the service completed onStartCommand() for a startService() call, and

  • Your service had successfully run onStartCommand() before and returned START_STICKY

I'm more and more wondering why my AlarmReceiver creates a service, rather than just showing the notification directly.

Agreed. If you plan on lots more work, involving disk or network I/O, then use an IntentService (background thread, service stops itself automatically). Otherwise, I'd just put this in onReceive() and call it good.

这篇关于Android的日常闹铃射击往往还是只有一次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆