XXXXX
C/C++
XXXXX
C#/.net
XXXXX
js
java
java
开发导航 开发导航 www.endv.cn
天云

Android定时器AlarmManager

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。所以精确是相对的。


 
posted @ 2020-07-29 02:05  Endv  阅读(152)  评论(0编辑  收藏