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

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通知即可



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值