前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android开发笔记(五十)定时器AlarmManager

Android开发笔记(五十)定时器AlarmManager

作者头像
aqi00
发布2019-01-18 11:12:16
2.8K0
发布2019-01-18 11:12:16
举报
文章被收录于专栏:老欧说安卓老欧说安卓

Timer和TimerTask

Java中的定时器机制有现成的方案,就是Timer+TimerTask。其中TimerTask用来描述时刻到达后的事务处理,而Timer用来调度定时任务,如何时启动、间隔多久再次运行等等。 Timer的调度方法是schedule,主要有三个参数。第一个参数表示用来调度的定时任务,第二个参数表示延迟多久首次启动任务,第三个参数表示间隔多久再次启动任务。 public void schedule(TimerTask task, long delay, long period) 定时任务得自己写个继承自TimerTask的新类,并重写run方法填入具体的事务处理代码。调用Timer的schedule方法,定时任务便会按照调度设置按时启动;TimerTask不能直接设置运行的次数上限,一旦启动就会持续定时运行,除非对象销毁或者调用了TimerTask的cancel方法。调用cancel方法停止定时任务后,若想重启该定时任务,只能重新声明TimerTask对象,并且重新调用schedule方法。 Timer+TimerTask的实质是利用开启Thread来触发定时任务,所以TimerTask实际上运行于非UI线程,也就无法直接操作UI。若想在TimerTask中修改UI控件,得通过Handler发送消息来间接实现。

CountDownTimer

CountDownTimer是Android提供的倒计时器,日常生活中时有见到倒计时的场景,比如说火箭发射倒计时。 通常我们要自定义一个CountDownTimer的派生类,并重写如下的三个方法: 构造函数 : 第一个参数是总的计时长度,第二个参数是每次的计时间隔(好像时钟的滴答)。 onTick : 每次计时触发的事件。 onFinish : 计时结束事件。 要想启动CountDownTimer计时,调用它的start方法即可,停止计时则调用cancel方法。另外倒计时器触发的onTick和onFinish都运行于非UI线程,所以与Timer一样,也得借助于Handler机制才能操作UI元素。

AlarmManager

AlarmManager是Android提供的一个全局定时器,其使用范围要大于Timer方式。因为Timer方式采用Thread通信,所以只适用于线程间通信,并且生命周期也有限。如果在Activity中定义Timer,那么Activity页面销毁后,定时器也失效了;如果在Application中定义Timer,那么APP退出后,定时器也要失效。相比之下,AlarmManager利用系统的提醒服务定时发送广播,所以不但适用于线程间通信,而且也适用于进程间通信。另外,由于是系统服务发送广播,因此只要再次打开APP,就会自动收到广播发来的定时任务。 AlarmManager常用的启动方法有两个: set : 该方法用于设置一次性定时器。第一个参数表示定时器类型,第二个参数表示任务执行时间,第三个参数表示定时任务。 setRepeating : 该方法用于设置重复定时器。第一个参数表示定时器类型,第二个参数表示任务首次执行时间,第三个参数表示再次执行的间隔时间,第四个参数表示定时任务。 其中定时器类型主要取值有: RTC_WAKEUP : 表示定时器即使在睡眠状态下也会启用,此时定时器使用系统时间 RTC : 表示定时器在睡眠状态下不可用,此时定时器使用系统时间 ELAPSED_REALTIME_WAKEUP : 表示定时器即使在睡眠状态下也会启用,此时定时器使用相对时间(相对于系统启动开始) ELAPSED_REALTIME : 表示定时器在睡眠状态下不可用,此时定时器使用相对时间 因为AlarmManager使用的是系统服务来发送广播,所以在注册广播接收器时需要注意以下几点: 1、要在AndroidManifest.xml中定义receiver; 2、代码中注册接收器必须使用Context.registerReceiver,不能使用LocalBroadcastManager来注册;

PendingIntent

AlarmManager启动方法中的定时任务使用了PendingIntent类,PendingIntent顾名思义就是一个延迟处理的通信工具。PendingIntent的实例可通过下列三种方法得到: getActivity : 获取用于启动页面的实例 getService : 获取用于启动服务的实例 getBroadcast : 获取用于发送广播的实例 三个方法的参数是一样的,第一个参数表示Context,第二个参数表示请求代码用于标识本次请求的唯一性,第三个参数表示Intent实例(可捆绑具体参数信息Bundle),第四个参数表示PendingIntent的启动标志,具体取值说明如下: FLAG_ONE_SHOT : 此时启动的PendingIntent只能使用一次。 FLAG_NO_CREATE : 如果不存在描述的PendingIntent,则不会创建新任务。 FLAG_CANCEL_CURRENT : 如果已存在描述的PendingIntent,则先取消该任务再创建新任务。 FLAG_UPDATE_CURRENT : 一般用这个标志。如果已存在描述的PendingIntent,则更新而不是取消该任务。

使用示例

下面是两种定时方式的效果图:

下面是Timer、CountDownTimer和AlarmManager三种定时器的示例代码:

import java.util.Timer;
import java.util.TimerTask;

import com.example.exmthread.R;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class AlarmActivity extends Activity implements OnClickListener {

	private TextView tv_alarm;
	private Button btn_timer;
	private Button btn_counter;
	private Button btn_alarm;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_alarm);

		btn_timer = (Button) findViewById(R.id.btn_timer);
		btn_counter = (Button) findViewById(R.id.btn_counter);
		btn_alarm = (Button) findViewById(R.id.btn_alarm);
		btn_timer.setOnClickListener(this);
		btn_counter.setOnClickListener(this);
		btn_alarm.setOnClickListener(this);

		tv_alarm = (TextView) findViewById(R.id.tv_alarm);
		ALARM_EVENT = getResources().getString(R.string.alarm_event);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_timer) {
			if (mTimerTask == null) {
				mTimerTask = new MyTimerTask();
				Timer timer = new Timer();
				timer.schedule(mTimerTask, 50, 200);
				btn_timer.setText("停止Timer定时计数");
			} else {
				mTimerTask.cancel();
				mTimerTask = null;
				btn_timer.setText("开始Timer定时计数");
			}
		} else if (v.getId() == R.id.btn_counter) {
			if (mCounterTask == null) {
				mCounterTask = new MyCounter(8000, 1000);
				mCounterTask.start();
				btn_counter.setText("停止CountDownTimer定时计数");
			} else {
				mCounterTask.cancel();
				mCounterTask = null;
				btn_counter.setText("开始CountDownTimer定时计数");
			}
		} else if (v.getId() == R.id.btn_alarm) {
			if (alarmReceiver == null) {
				alarmReceiver = new AlarmReceiver();
				IntentFilter filter = new IntentFilter(ALARM_EVENT);
		        registerReceiver(alarmReceiver, filter);

				Intent intent = new Intent(ALARM_EVENT);
				PendingIntent pIntent = PendingIntent.getBroadcast(
						this, R.string.app_name, intent, PendingIntent.FLAG_UPDATE_CURRENT);
				AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
				alarmMgr.setRepeating(
						AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 200, pIntent);
				btn_alarm.setText("停止AlarmManager计数");
			} else {
		        unregisterReceiver(alarmReceiver);
		        alarmReceiver = null;
				btn_alarm.setText("开始AlarmManager计数");
			}
		}
	}

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			if (msg.what == 0) {
				tv_alarm.setText("当前计数值为"+msg.arg1);
			} else if (msg.what == 1) {
				tv_alarm.setText("当前计数值为"+msg.arg1);
				btn_counter.setText("CountDownTimer计时结束,重新计时");
			}
		}
	};

	private MyCounter mCounterTask = null;
	private class MyCounter extends CountDownTimer {

		private int count;
		public MyCounter(long millisInFuture, long countDownInterval) {
			super(millisInFuture, countDownInterval);
			count = 0;
		}

		@Override
		public void onTick(long millisUntilFinished) {
			Message msg = mHandler.obtainMessage();
			msg.what = 0;
			msg.arg1 = count++;
			mHandler.sendMessage(msg);
		}

		@Override
		public void onFinish() {
			Message msg = mHandler.obtainMessage();
			msg.what = 1;
			msg.arg1 = count;
			mHandler.sendMessage(msg);
		}
		
	}

	private MyTimerTask mTimerTask = null;
	private class MyTimerTask extends TimerTask {
		private int count = 0;

		@Override
		public void run() {
			Message msg = mHandler.obtainMessage();
			msg.what = 0;
			msg.arg1 = count++;
			mHandler.sendMessage(msg);
		}
	}
	
	private String ALARM_EVENT = "";
	private int mCount = 0;
    private AlarmReceiver alarmReceiver = null;
    
    public class AlarmReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
    			tv_alarm.setText("当前计数值为"+mCount++);
            }
        }
    }

}

点此查看Android开发笔记的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年01月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Timer和TimerTask
  • CountDownTimer
  • AlarmManager
  • PendingIntent
  • 使用示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档