美文网首页Binder机制
Android定时器AlarmManager

Android定时器AlarmManager

作者: 许宏川 | 来源:发表于2016-08-07 17:00 被阅读7263次

    AlarmManager是Android的全局定时器。就是在指定时间做一个事情(封装在PendingIntent)。通过PendingIntent的getActivity()、getService()或getBroadcast()来执行。
    听起来AlarmManager和Timer很类似,但是Timer有可能因为手机休眠而被杀掉服务,但是AlarmManager可以做到唤醒手机。

    创建方式

    AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
    

    注:ALARM_SERVIC是context的一个常量。

    闹钟类型

    • RTC_WAKEUP
      表示闹钟在睡眠状态下唤醒系统并执行提示功能,绝对时间。
    • RTC
      睡眠状态下不可用,绝对时间。
    • ELAPSED_REALTIME_WAKEUP
      睡眠状态下可用,相对时间。
    • ELAPSED_REALTIME
      睡眠状态下不可用,相对时间。

    以上绝对时间就是手机的时间,相对时间是相对于当前开机时间来说。例如如果是绝对时间,那么你测试可以通过修改系统时间来提前触发。而相对时间的使用场景是强调多久之后触发,例如2小时后,这个时候把时间修改到2小时后也是没用的。
    注:以前还有一个POWER_OFF_WAKEUP,即使在关机后还能提醒,但是Android4.0以后就没有了。

    常用方法

    set(int type, long triggerAtMillis, PendingIntent operation)
    

    该方法用于设置一次性闹钟。第一个参数是闹钟类型,第二个参数是触发时间,第三个参数是动作。

    setExact(int type, long triggerAtMillis, PendingIntent operation)
    

    和set一样,但是时间更精准。

    setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
    

    重复闹钟,第1、2、4个参数同上,第3个参数是两次闹钟的时间间隔。

    setRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)
    

    和setInexactRepeating一样,但是时间更精准。

    以上四个方法时间精不精准的原因还没有深入研究,大概是是否允许系统同时发出多个提醒,意义在于系统唤醒cpu后会把时间接近的alarm同时发出,避免重复唤醒cpu,减少电量。

    cancel(PendingIntent operation)
    

    取消闹钟。

    写个小程序实验一下

    目的:在指定时间从一个发送个广播,收到广播后打印log。界面如下面这样。


    布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.xuhongchuan.alarmclocktest.MainActivity">
    
        <LinearLayout
            android:id="@+id/view_group1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <TimePicker
                android:id="@+id/time_picker"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            </TimePicker>
    
        </LinearLayout>
    
        <LinearLayout
            android:id="@+id/view_group2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal"
            android:layout_below="@id/view_group1">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="是否重复"/>
    
            <CheckBox
                android:id="@+id/checkbox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
    
        </LinearLayout>
    
        <Button
            android:id="@+id/confirm"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/view_group2"
            android:text="确定" />
    </RelativeLayout>
    
    

    广播接收器:

    public class AlarmReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == MainActivity.INTENT_ALARM_LOG) {
                Log.d("AlarmReceiver", "log log log");
            }
    
        }
    }
    

    MainActivity

    public class MainActivity extends AppCompatActivity {
    
        public static final String INTENT_ALARM_LOG = "intent_alarm_log";
    
        private TimePicker timePicker;
        private CheckBox checkBox;
        private Button btnConfirm;
    
        private int hour;
        private int minute;
    
        AlarmManager am;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            init();
        }
    
        private void init() {
            timePicker = (TimePicker) findViewById(R.id.time_picker);
            timePicker.setIs24HourView(true);
            checkBox = (CheckBox) findViewById(R.id.checkbox);
            btnConfirm = (Button) findViewById(R.id.confirm);
    
            am = (AlarmManager) getSystemService(ALARM_SERVICE);
    
            btnConfirm.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (Build.VERSION.SDK_INT >= 23) {
                        hour = timePicker.getHour();
                        minute = timePicker.getMinute();
                    } else {
                        hour = timePicker.getCurrentHour();
                        minute = timePicker.getCurrentMinute();
                    }
                    Calendar calendar = Calendar.getInstance();
                    calendar.set(Calendar.HOUR_OF_DAY, hour);
                    calendar.set(Calendar.MINUTE, minute);
                    calendar.set(Calendar.SECOND, 0);
    
                    Intent intent = new Intent(INTENT_ALARM_LOG);
                    PendingIntent pi = PendingIntent.getBroadcast(MainActivity.this, 0, intent, 0);
    
                    if (!checkBox.isChecked()) {
                        am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pi);
                    } else {
                        long intervalMillis  = 60 * 1000; // 60秒
                        am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), intervalMillis, pi);
                    }
                }
            });
        }
    }
    

    AndroidManifest要注册一下receiver

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

    经过测试,以上的时间间隔intervalMillis即使设置5秒也是没用的,因为误差(几十秒呢)无法避免,即使是setRepeating。所以精确是相对的。

    相关文章

      网友评论

        本文标题:Android定时器AlarmManager

        本文链接:https://www.haomeiwen.com/subject/eiicsttx.html