android中定时任务可以使用Timer,Thread,handler来实现一个小定时器功能。其实在android中还提供了一种Alarm机制,
这种定时机制要比前面那些实现方式有更多的好处以及其无法实现复杂定时功能,如下:
1,Alarm定时不需要程序自身去维护,而又系统来维护,使得程序更好避免了容易出错问题,更是占用系统资源,cpu占有率。
2,即使程序退出后,程序自身不会有任何烦恼的问题,系统到时间自动调用对应组件执行定义好的逻辑
3,定时的多样性,包括一次定时,循环定时(在xx年x月x日执行,周一至周五执行,每天几点几分执行。。。)
最典型应用案例闹铃,事件提醒应用实现提醒机制。我们通过操作AlarmManager与PendingIntent即可设定定时功能。
首先说一下android中时间计时两种方式,一种是SystemClock.elapsedRealtime()方式计时,第二种是以System.currentTimeMillis()方法计时,
根据计时方式的不同,设置定时任务是也略有不同,如下:
SystemClock.elapsedRealtime()方式定时(以开机启动时间开始计时):
以30s为周期进行定时提醒功能
// We want the alarm to go off 30 seconds from now. long firstTime = SystemClock.elapsedRealtime(); firstTime += 15*1000; AlarmManager am = (AlarmManager)mcontext.getSystemService(Context.ALARM_SERVICE); // Schedule the alarm! am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, 30*1000, sender);
System.currentTimeMillis()方法定时:
30s后进行提醒功能
Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.add(Calendar.SECOND, 30); AlarmManager am = (AlarmManager)mcontext.getSystemService(Context.ALARM_SERVICE); // Schedule the alarm! am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
其中setRepeating()为循环计划任务任务,set()方法单次任务计划,sender 为PendingIntent,它与intent用法类似,专门用于定时功能
PendingIntent 可以启动service 通过getService,启动Activity 通过getActivity,启动Broadcast通过getBroadcast
这里以定时启动Broadcast为例用法如下:
PendingIntent sender = PendingIntent.getBroadcast(mcontext,requestCode, intent, PendingIntent.FLAG_NO_CREATE);
参数一:context
参数二:用来区分不同的定时编码(同一个intent可以被使用,根据code进行区分是一个定时,还是多个定时任务,code相同可以被覆盖)
参数三:intent包含启动broadcast实例
参数四:flag 同一个intent处理方式分别为FLAG_ONE_SHOT
, FLAG_NO_CREATE
,FLAG_CANCEL_CURRENT
,
FLAG_UPDATE_CURRENT
,也可以写成0
具体实现如下:
1,创建任务广播,计划任务开始时调用
任务广播:
public class SheduleReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent arg1) { Toast.makeText(context, "receive shedule!", Toast.LENGTH_SHORT).show(); } }
广播注册:
这里需要注意在独立进程中配置,这是android所定义的
<receiver android:name="com.pioneersoft.aoc.ui.SheduleReceiver" android:process=":remote" />
自己封装的计划任务管理类:
import java.util.Calendar; import java.util.HashMap; import java.util.Map; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.util.Log; public class SheduleTask { final String tag=getClass().getSimpleName(); private Context mcontext; // private Map<Integer,Integer> weekValues=new HashMap<Integer,Integer>(7); public SheduleTask(Context mcontext){ this.mcontext=mcontext; // initWeekDay(); } /*private void initWeekDay(){ weekValues.put(1, Calendar.MONDAY); weekValues.put(2, Calendar.TUESDAY); weekValues.put(3, Calendar.WEDNESDAY); weekValues.put(4, Calendar.THURSDAY); weekValues.put(5, Calendar.FRIDAY); weekValues.put(6, Calendar.SATURDAY); weekValues.put(7, Calendar.SUNDAY); }*/ /** * 格式化时间格式 * @param date */ private void formatSheduleTimer(String date){ int week=0,hour=0,minutes=0; String[] str=date.split(":"); if(str==null||str.length==0){ Log.e(tag, "time data error!"); return; }else{ try{ week=Integer.valueOf(str[0]); hour=Integer.valueOf(str[1]); minutes=Integer.valueOf(str[2]); }catch(NumberFormatException e){ Log.e(tag, "time formate erroe!"); } } Log.e(tag, "time= "+week+":"+hour+":"+minutes); } /** * 距离此时后多少秒开始计划任务 * @param intent * @param requestCode * @param delaySecond */ public void startSheduleDelayTime(Intent intent,int requestCode,int delaySecond){ // We want the alarm to go off some seconds from now. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.add(Calendar.SECOND, delaySecond); PendingIntent sender = PendingIntent.getBroadcast(mcontext,requestCode, intent, 0); // Schedule the alarm! AlarmManager am = (AlarmManager)mcontext.getSystemService(Context.ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender); } /** * 某月某日一次计划任务 * @param intent * @param requestCode * @param month * @param day * @param hour * @param minuts */ public void startSheduleSpecificData(Intent intent,int requestCode,int month,int day,int hour,int minuts){ Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.MONTH, month); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minuts); calendar.set(Calendar.SECOND, 0); PendingIntent sender = PendingIntent.getBroadcast(mcontext,requestCode, intent, 0); // Schedule the alarm! AlarmManager am = (AlarmManager)mcontext.getSystemService(Context.ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender); } /** * 以天为单位进行循环计划任务 * @param intent * @param requestCode * @param hour * @param minuts */ public void startSheduleEveryday(Intent intent,int requestCode,int hour,int minuts){ Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minuts); calendar.set(Calendar.SECOND, 0); PendingIntent sender = PendingIntent.getBroadcast(mcontext,requestCode, intent, 0); AlarmManager am = (AlarmManager)mcontext.getSystemService(Context.ALARM_SERVICE); am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY, sender); } /** * 以周为单位进行循环计划任务 * @param intent * @param requestCode * @param week * @param hour * @param minuts */ public void startSheduleWeekday(Intent intent,int requestCode,int week,int hour,int minuts){ Calendar calSet=Calendar.getInstance(); calSet.set(Calendar.DAY_OF_WEEK, week); calSet.set(Calendar.HOUR_OF_DAY, hour); calSet.set(Calendar.MINUTE, minuts); calSet.set(Calendar.SECOND, 0); //calSet.set(Calendar.MILLISECOND, 0); PendingIntent sender = PendingIntent.getBroadcast(mcontext,requestCode, intent, 0); AlarmManager am = (AlarmManager)mcontext.getSystemService(Context.ALARM_SERVICE); am.setRepeating(AlarmManager.RTC_WAKEUP, calSet.getTimeInMillis(), 1 * 60 * 60 * 1000, sender); } /** * 取消计划任务 * @param intent * @param requestCode */ public void cancelShedule(Intent intent,int requestCode){ PendingIntent sender = PendingIntent.getBroadcast(mcontext,requestCode, intent, 0); AlarmManager am = (AlarmManager)mcontext.getSystemService(Context.ALARM_SERVICE); am.cancel(sender); } /** * @return true if clock is set to 24-hour mode */ public boolean get24HourMode(final Context context) { return android.text.format.DateFormat.is24HourFormat(context); } }
2,设定计划任务,这里以每天为例:
Intent intent=new Intent(this,SheduleReceiver.class); sheduleCount++; shedule.startSheduleEveryday(intent,sheduleCount, hour, minutes,seconds);
其中sheduleCount 为计划任务编号,当有多个计划任务时需要改变编号。
如果想定时启动Activity,Service只需把broadcast替换对应组件即可