Alarm

原创 2015年11月18日 16:58:20

1:需求

  常常有这样的需求,在某个时候手机自动执行某一动作,或者周期性的做一些事情。

在程序的声明周期中,我们可以使用Schedule+Timer+TimerTask运行在service中,也可以使用handler的延时post进行处理。都比较方便,尤其是采用handler方式。但是当不在程序的生命周期的时候,上述两种方式就显得力不从心了。

这个时候就到了Alarm大显身手了。当然Alarm也是可以在程序的生命周期内使用。

注意一下:handler在程序切到后后台的时候会出现计时延缓,我发现这个问题是在程序发短信倒计时的时候。

2:什么是Alarm

  Alarm是在预定的时间触发Intent的,独立于应用程序的提醒用户的方式。当这个Alarm触发后,就会广播这个Intent,如果应用程序没有起启,就会启动这个应用程序,而不需要就用程序被打开或者处于活动状态(这里说的只是其中一种较为特殊的情况,具体的启动方式可以根据参数的不同而配置)

  在android中通过AlarmManager来管理所有的Alarm。

  AlarmManage有一个AlarmManagerServie服务程序,该服务程序才是正真提供闹铃服务的,它主要维护应用程序注册下来的各类闹铃并适时的设置即将触发的闹铃给闹铃设备(在系统中,linux实现的设备名为”/dev/alarm”),并且一直监听闹铃设备,一旦有闹铃触发或者是闹铃事件发生,AlarmManagerServie服务程序就会遍历闹铃列表找到相应的注册闹铃并发出广播。该服务程序在系统启动时被系统服务程序system_service启动并初始化闹铃设备(/dev/alarm)。当然,在JAVA层的AlarmManagerService与Linux Alarm驱动程序接口之间还有一层封装,那就是JNI。

  AlarmManager将应用与服务分割开来后,使得应用程序开发者不用关心具体的服务,而是直接通过AlarmManager来使用这种服务。这也许就是客户/服务模式的好处吧。AlarmManager与 AlarmManagerServie之间是通过Binder来通信的,他们之间是多对一的关系。

3:Alarm如何使用

这里只介绍BroadcastReceiver中的使用,因为核心代码类似顾不在详解。

在应用中进行Alarm的注册(这种方式更令我认同)

布局的code

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <Button 
        android:id="@+id/cancle"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="cancle"
        />
    <Button 
        android:id="@+id/restart"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="restart"
        android:layout_marginTop="20dp"
        />
</LinearLayout>

activity中的code

public class MainActivity extends Activity implements OnClickListener{

    private AlarmManager alarmManager;  
    private PendingIntent pendingIntent;  
    private Button cancle,restart;
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        
        cancle = (Button) findViewById(R.id.cancle);
        restart = (Button) findViewById(R.id.restart);
        cancle.setOnClickListener(this);
        restart.setOnClickListener(this);
        
        Intent intent;
        intent = new Intent(this, AlarmBroadcastReceiver.class);  
        intent.setAction("Action.Alarm");  
        pendingIntent = PendingIntent.getBroadcast(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);  
        
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        //alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5000, pendingIntent)
        alarmManager.setRepeating(AlarmManager.RTC,System.currentTimeMillis(), 1000, pendingIntent);
        
        //api19以后使用
        //alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5000, pendingIntent);
        //alarmManager.setWindow(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 15*1000, pendingIntent);
    }

	@Override
	public void onClick(View v) {
		int id = v.getId();
		switch (id) {
		case R.id.cancle:
			alarmManager.cancel(pendingIntent);
			break;
        case R.id.restart:
        	alarmManager.setRepeating(AlarmManager.RTC,System.currentTimeMillis(), 1000, pendingIntent);
        	break;
		default:
			break;
		}
	}  
}

广播接收的code,在这里可以进行一些启动服务或者activity的操作。(这里不能进行耗时操作)

public class AlarmBroadcastReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		if ("Action.Alarm".equals(intent.getAction())) {  
            System.out.println("闹钟事件发生了!");  
            Toast.makeText(context, "闹钟事件发生了!", Toast.LENGTH_SHORT).show();  
        }  
	}
}

4:Alarm知识点

alarm 需要使用pendingIntent进行注册。pendingIntent对Intent进行了包装,可以根据需求的不同得到不同的pendingIntent。

   PendingIntent.getBroadcast

   PendingIntent.getActivity

   PendingIntent.getService

就3中的PendingIntent.getBroadcast(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);进行参数的讲解

参数1:上下文

参数2:int requestCode 类似于startActivityForResult中的requestCode(这个到底有什么作用呢

参数3:intent可以携带数据

参数4:

FLAG_CANCEL_CURRENT:如果描述的PendingIntent对象已经存在时,会先取消当前的PendingIntent对象再生成新的。

FLAG_NO_CREATE:如果描述的PendingIntent对象不存在,它会返回null而不是去创建它。

FLAG_ONE_SHOT:创建的PendingIntent对象只使用一次。

FLAG_UPDATE_CURRENT:如果描述的PendingIntent对象存在,则保留它,并将新的PendingIntent对象的数据替换进去。

在从提取PendingIntent时,通过FLAG_CANCEL_CURRENT参数,让这个老PendingIntent的先cancel()掉,这样得到的pendingInten和其token的就是新的了。可以让新的Intent会更新之前PendingIntent中的Intent对象数据


拿到alarmManager,就可以对alarm进行注册了。

注册的方式有下面几种

//一次

set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5000, pendingIntent)

参数1:后面讲解

参数2:alarm触发的的时间

参数3:上文已经讲解


//多次

alarmManager.setRepeating(AlarmManager.RTC,System.currentTimeMillis(), 1000, pendingIntent)

setInexactRepeating(AlarmManager.RTC,System.currentTimeMillis(), 1000, pendingIntent)

参数1:后面讲解

参数2:alarm触发的的时间

参数3:两次触发之间的时间间隔

参数4:上文已经讲解

二者都是周期性的触发,区别在于setRepeating将安排第一个报警准确的触发,而setInexactRepeating将会偏离你所设定的具体值

setInexactRepeating中第三个参数可做选择

AlarmManager.INTERVAL_DAY

AlarmManager.INTERVAL_FIFTEEN_MINUTES

AlarmManager.INTERVAL_HALF_DAY

AlarmManager.INTERVAL_HALF_HOUR

AlarmManager.INTERVAL_HOUR


//Api19之后可以使用
//alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5000, pendingIntent);
//alarmManager.setWindow(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 15*1000, pendingIntent);

 

第一个参数

FLAG_CANCEL_CURRENT:如果描述的PendingIntent对象已经存在时,会先取消当前的PendingIntent对象再生成新的。

FLAG_NO_CREATE:如果描述的PendingIntent对象不存在,它会返回null而不是去创建它。

FLAG_ONE_SHOT:创建的PendingIntent对象只使用一次。

FLAG_UPDATE_CURRENT:如果描述的PendingIntent对象存在,则保留它,并将新的PendingIntent对象的数据替换进去。



5:Alarm出现的问题

1:Alarm不能滥用,否则会使得程序成为待机电量杀手。

2:小米手机

定时器,15秒发一个广播,HTC测试都是立马就发出第一个广播,
就MI2测试时,第一个等了好5分钟才发出来

原因:这是由于MIUI的对齐唤醒机制导致的,这个用什么都不太好使,小米上如果要使用AlarmManager 智能使用RTC 模式 其他的都有限制。

3:另当定时不准确的时候,看看是不是因为没有使用最新的API19以后推荐使用的接口。


参考:

http://www.cnblogs.com/jk1001/archive/2010/08/02/1790167.html

http://www.cnblogs.com/linzheng/archive/2011/01/22/1942059.html

http://blog.csdn.net/hudashi/article/details/7060837

http://blog.csdn.net/dianyueneo/article/details/19157289

http://blog.csdn.net/maosidiaoxian/article/details/21776697


版权声明:本文为博主原创文章,未经博主允许不得转载。

本地通知使用总结

一.关于通知注册: ios8之前:registerForRemoteNotificationTypes: ios8之后:registerUserNotificationSettings   二...

Android AlarmManager实现不间断轮询服务(定时提醒功能)

在消息的获取上是选择轮询还是推送得根据实际的业务需要来技术选型,例如对消息实时性比较高的需求,比如微博新通知或新闻等那就最好是用推送了。但如果只是一般的消息检测比如更新检查,可能是半个小时或一个小时一...

VB Kanban (Display Alarm)

  • 2013年06月26日 18:50
  • 1.87MB
  • 下载

linux c之alarm函数的使用,定时器的实现

#include #include #include int main(int argc, char *argv[]) { unsigned int timeleft; print...
  • earbao
  • earbao
  • 2016年05月30日 11:24
  • 2710

Alarm.java

  • 2013年08月01日 14:28
  • 8KB
  • 下载

实用定时器Alarm机制

  • 2015年08月01日 16:36
  • 1.38MB
  • 下载

linux C由signal和alarm实现的键盘监控和程序计时

1.alarm() 函数原型:unsigned int alarm(unsigned int seconds); 头文件:#include 函数说明: alarm()用来设置信号SIGALRM在...

Alarm Clock

  • 2014年05月17日 15:36
  • 2.41MB
  • 下载

Zone Alarm防火墙

  • 2007年09月04日 18:27
  • 8.97MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Alarm
举报原因:
原因补充:

(最多只允许输入30个字)