您的位置:首页 > 移动开发 > Android开发

Android 定时操作方法AlarmManager,Timer,Handler

2015-10-27 17:33 501 查看

AlarmManager

Timer有一个明显的短板,它并不太适用于那些需要长期在后台运行的定时任务。我们都知道,为了能让电池更加耐用,每种手机都会有自己的休眠策略,Android 手机就会在长时间不操作的情况下自动让 CPU 进入到睡眠状态,这就有可能导致 Timer 中的定时任务无法正常运行。另一方面,其实也可以通过handler的poseDelay方法来实现定时操作,也是不靠谱的,因为默认handler依赖于线程(main线程或者子线程),所以只要进程被杀死,所有相关的线程都被杀死,所以handler中的定时操作就无效了。timer也一样,因为timer实际上是另启一个子线程,进程被杀了,子线程当然也被杀了,所以time失效。。。。而
Alarm 机制则不存在这种情况,它通过pendingintent具有唤醒 未启动的进程 的功能,即可以保证每次需要执行定时任务的时候 CPU 都能正常工作。但是闹钟当设备关机和重启后,闹钟将会被清除。一张图总结一下区别



ELAPSED_REALTIME 表示让定时任务的触发时间从系统开机开始算起,但不会唤醒 CPU

AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 1000;

//10s执行一次pendingIntent

manager.set(AlarmManager.ELAPSED_REALTIME, triggerAtTime, pendingIntent);

RTC 表示让定时任务的触发时间从 1970 年 1月 1 日 0 点开始算起,但不会唤醒 CPU

long triggerAtTime = System.currentTimeMillis() + 10 * 1000;

//10s执行一次pendingIntent

manager.set(AlarmManager.RTC, triggerAtTime, pendingIntent);

SystemClock.elapsedRealtime()方法可以获取到系统开机至今所经历时间的毫秒数

System.currentTimeMillis()方法可以获取到1970年1月1日0点至今所经历时间的毫秒数

long repeat = 10000;

//从当前时间开始,10s中执行一次PendingIntent

mAlarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), repeat, pendingIntent);

PendingIntent

Intent 更加倾向于去立即执行某个动作,而 PendingIntent 更加倾向于在某个合适的时机去执行某个动作。所以,也可以把 PendingIntent 简单地理解为延迟执行的 Intent。

getActivity()方法、getBroadcast()方法、getService()方法

Notification

sdk16以后可以这样使用,点击该通知后启动NextActivity

 
Intent acIntent = new Intent(this, NextActivity.class);
NotificationManager nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent pi = PendingIntent.getActivity(this, 0, acIntent, 0);
Notification notify = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker("TickerText:" + "您有新短消息,请注意查收!")
.setContentTitle("Notification Title")
.setContentText("This is the notification message")
.setContentIntent(pi).build();
notify.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明当通知被用户点击时,通知将被清除。
nm.notify(NotiID, notify);


 如果要支持老的sdk,点击该通知后启动HtmlNavActivity

 
Intent intent = new Intent();
intent.setClass(mContext, HtmlNavActivity.class);
final PendingIntent pi = PendingIntent.getActivity(mContext, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//创建一个通知
Notification n = new Notification(R.drawable.icon, obj.optString("LocalNotifyTitle"), System.currentTimeMillis());
// 为通知添加数据
n.flags |= Notification.FLAG_AUTO_CANCEL;
n.setLatestEventInfo(mContext, "LocalNotifyTitle", "LocalNotifyContent", pi);
// 发送通知
NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NotiID, n);


notify.flags |= Notification.FLAG_AUTO_CANCEL; //表明点击后,通知自动消失

也可以通过NotificationManager.cancel(NofiID); 手动取消通知

以下为通知设置震动,响铃,还有其它用法就不举例

long[] vibrates = {0, 1000, 1000, 1000};

notification.vibrate = vibrates;

Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/

Basic_tone.ogg"));

notification.sound = soundUri;

注意:
通知一到,如果该应用已经启动了进程,那么使用当前进程。如果没有启动进程,那么就会启动进程,可以看到会调用application的oncreate方法。从ddms也可以看出,通知一到,如果没有进程就启动该应用的进程

Date

Date date = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
Log.d("LiaBin", "current: " + dateFormat.format(date));
    2. yyyy:年  

    3. MM:月  

    4. dd:日   

    5. hh:1~12小时制(1-12)  

    6. HH:24小时制(0-23)  

    7. mm:分  

    8. ss:秒   

Calendar

推荐使用Calendar类进行时间和日期处理
Calendar checkInCal = Calendar.getInstance();
checkInCal.setTimeInMillis(System.currentTimeMillis());
checkInCal.add(Calendar.DATE, 2);
checkInCal.set(Calendar.HOUR_OF_DAY, 8);
if (checkInCal.getTimeInMillis() > System.currentTimeMillis()) {

}
        getTime方法 该方法的作用是将Calendar类型的对象转换为对应的Date类对象

        getTimeInMillis 转换为相对于1970.1.1时间
        after方法 该方法的作用是判断当前日期对象是否在when对象的后面,如果在when对象的后面则返回true,否则返回false

         Calendar.YEAR——年份

         Calendar.MONTH——月份

         Calendar.DATE——日期

         Calendar.DAY_OF_MONTH——日期,和上面的字段完全相同

         Calendar.HOUR——12小时制的小时数

         Calendar.HOUR_OF_DAY——24小时制的小时数

         Calendar.MINUTE——分钟

         Calendar.SECOND——秒

         Calendar.DAY_OF_WEEK——星期几

        

案例

实际项目中经常会需要在某个时间点弹出通知,或者重复在某个时间点弹出通知,下面是代码实现。
由于手机关机或者重启,闹钟就失效,所以在application中开启服务,service的oncreate方法中开启闹钟,所以每次启动进程,都会重新设定闹钟。

public class BaseApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
startService(new Intent(this, MyService.class));
Log.d("LiaBin","application oncreate");
}
}

public class MyService extends Service {
private final static String ACTION_NOTIFICATION = "ACTION_NOTIFICATION";

@Override
public void onCreate() {
super.onCreate();
initAlarm(ACTION_NOTIFICATION);
}

@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (intent != null) {
String action = intent.getAction();
if (ACTION_NOTIFICATION.equals(action)) {
Intent acIntent = new Intent(this, NextActivity.class);
NotificationManager nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent pi = PendingIntent.getActivity(this, 0, acIntent, 0);
Notification notify = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker("TickerText:" + "您有新短消息,请注意查收!")
.setContentTitle("Notification Title")
.setContentText("This is the notification message")
.setContentIntent(pi).build();
notify.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明当通知被用户点击时,通知将被清除。
nm.notify(1000, notify);
}
}
}

@Override
public IBinder onBind(Intent intent) {
return null;
}

private void initAlarm(String action) {
AlarmManager mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.setAction(action);
PendingIntent pi = PendingIntent.getService(this, 0, serviceIntent, 0);
mAlarmManager.cancel(pi);

Calendar checkInCal = Calendar.getInstance();
checkInCal.setTimeInMillis(System.currentTimeMillis());
checkInCal.add(Calendar.SECOND, 5);
long repeat = 10000;
mAlarmManager.setRepeating(AlarmManager.RTC, checkInCal.getTimeInMillis(), repeat, pi);
}
}

开启进程就启动service,oncreate方法中开启闹钟,注意设置闹钟前必须把以前设置的闹钟取消,mAlarmManager.cancel(pi);很关键。

此时设置一个重复性闹钟,5秒后开始执行,之后10s重复一次。然后pendingintent还是该service,这样就不必额外写一个broadcast了,如果该service

内存中已经存在一个实例,那么只会调用onstart方法,然后判断action,显示notification通知即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android