8.4 AlarmManager实现精准定时任务

原创 2015年11月18日 09:07:06
需求分析:  在项目中,有这么一个功能点,app进程中,需要实现一个定时任务,只要设备处于开机状态,每隔半个小时,就需要定时向服务器上传一次位置信息,并且只要是有网络和获取到GPS信号,进程不能死,如果进程死掉了,需要自动重启。对该点进行细分梳理,包含如下几个小功能点:
     1.进程能够实现开机启动。
     2.进程需要一直存活,并且能够自动重启。
     3.需要定时(30分钟)一次,向server端上报信息。


      针对以上三个功能点,第1和2点,实现起来,都不难,唯独第三点:我这里提供如下解决方案:
方案一. 死循环中,使用sleep方法: for(;;)    Tread.sleep 30分钟
方案二. timer机制  timerTask 30分钟一次
最终方案三.AlarmManager进行精准定时

 方案一和方案二的定时方案不准,主要原因是sleep和timerTask的内部线程运行的时间。在thread运行时,CPU才开始计算时间,当线程挂起,CPU没有将时间片交给该线程,就没有计算时间。实际使用中,app在后台运行越长,误差就越大。


AlarmManager需要处理的问题:

Q1:进程死掉后,AlarmManager是否还有效果?是否需要使用自动重启的service来重启进程?
Q2:设备reboot(重启)后,设置的AlarmManager是否还有效?
Q3:重复set相同的alarm,是否会影响AlarmManager的定时机制?
阅读关于Alarm机制源码(参考: Android 4.0 Alarm机制浅析)后发现,在设备reboot后,为了确保AlarmManager的setInexactRepeating还有效,必须在设备接收到ACTION_BOOT_COMPLETED事件时,重新进行set alarm。精准的定时方案大致如下:
1)注册广播,接收系统ACTION_BOOT_COMPLETED事件时,进行set alarm,进行精准定时任务
 2)在alarm中启动service,service中实现网络HTTP请求。
 3)首次启动后,要set alarm。

编程实例:

1)新建类MainActivity.java

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		int id = v.getId();
		switch(id){
		case R.id.button1:
			ServiceUtil.invokeTimerPOIService(mContext);
			break;
		case R.id.button2:
			ServiceUtil.cancleAlarmManager(mContext);
			break;
		}
2) 类ServiceUtil.java

    public static void invokeTimerPOIService(Context context){
        Log.i("ServiceUtil-AlarmManager", "invokeTimerPOIService wac called.." );
        PendingIntent alarmSender = null;
        Intent startIntent = new Intent(context, UploadPOIService.class);
        startIntent.setAction(Constants.POI_SERVICE_ACTION);
        try {
            alarmSender = PendingIntent.getService(context, 0, startIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        } catch (Exception e) {
            Log.i("ServiceUtil-AlarmManager", "failed to start " + e.toString());
        }
        AlarmManager am = (AlarmManager) context.getSystemService(Activity.ALARM_SERVICE);
        am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), Constants.ELAPSED_TIME, alarmSender);
    }

    public static void cancleAlarmManager(Context context){
        Log.i("ServiceUtil-AlarmManager", "cancleAlarmManager to start ");
        Intent intent = new Intent(context,UploadPOIService.class);
    	intent.setAction(Constants.POI_SERVICE_ACTION);
        PendingIntent pendingIntent=PendingIntent.getService(context, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarm=(AlarmManager)context.getSystemService(Activity.ALARM_SERVICE);
        alarm.cancel(pendingIntent);
    }

3) 在类UploadPOIService,是一个service,使用Thread.sleep模拟网络HTTP请求。  
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			Log.i(TAG, "UploadPOIService beign to upload POI to server ");
			Thread.sleep(5*1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		stopSelf();
	}

4)类BootBroadcastReceiver,注册一个静态Broadcast,接收系统级的ACTION_BOOT_COMPLETED事件,用于开机set alarm。

    public void onReceive(Context context, Intent intent) {
        mContext = context;
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            LogUtil.i("BootBroadcastReceiver", "BroadcastReceiver onReceive here,action = " + intent.getAction());
            Handler handler = new Handler(Looper.getMainLooper());
            //after reboot the device,about 2 minutes later,upload the POI info to server
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if(!ServiceUtil.isServiceRunning(mContext,Constants.POI_SERVICE)){
                        ServiceUtil.invokeTimerPOIService(mContext);
                    }
                }
            }, Constants.BROADCAST_ELAPSED_TIME_DELAY);
        }
    }
5)运行后,针对question 1question 3进行测试。从打印的log分析问题。执行步奏:在控制台,使用adb kill命令杀死进程,观察先前设置的AlarmManager是否还有效果?log如下:


进程PID“32267”和“1190”属于同一应用,从log发现,进程被kill后,自动重启进程,并且先前设置的alarm同样有效。此log信息,说明系统级的alarm,在进程kill后,会自动重启,并且重启后的定时任务,依旧有效。
   在设备reboot后,重新set alarm,alarm会执行。

 在测试代码时,发现某些设备上,AlarmManager执行效果没有达到预期效果,10秒一次的定时任务,被搞成了5min+一次。例如雷布斯的小米3设备,源码设置的10秒一次,米3上,却是5分钟一次定时任务。后来查询资料,发现时由于Android碎片化的原因,各个厂家进行随意定制,考虑节能省电,一旦系统休眠,不会频繁唤醒系统造成的原因。相关链接如下:
   点击打开链接  

相关文章推荐

AlarmManager实现精准定时任务

  • 2014年11月03日 17:11
  • 2.12MB
  • 下载

AlarmManager实现精准定时任务

在项目中,有这么一个功能点,app进程中,需要实现一个定时任务,只要设备处于开机状态,每隔半个小时,就需要定时向服务器上传一次位置信息,并且只要是有网络和获取到GPS信号,进程不能死,如果进程死掉了,...
  • Coder80
  • Coder80
  • 2014年11月03日 22:01
  • 23541

使用AlarmManager实现Android应用每天定时执行任务

介绍android官方文档:AlarmManager 在Android平台,除了使用AlarmManger外,还可以使用Timer或者Handler来实现定时任务,但这两种方式定时并不会太准确;因此...

利用pendingintent 和AlarmManager实现定时任务的一些分析

PendingIntent 获取 PendingIntent对象的方法: 可以通过getActivity(Context context, int requestCode, Intent inte...

android Service重启问题,结合AlarmManager实现定时任务

当启动service进行后台任务的时候,我们一般的 做法是启动一个线程,然后通过sleep方法来控制进行定时的任务,如轮询操作,消息推送。这种service的资源是很容易被回收的,虽然service的...

用AlarmManager和Service实现定时任务

在开发过程中,我们可能要每隔一段时间,去执行一次任务,我们就可以用AlarmManager和Service实现定时任务,比如说,每隔5秒钟,请求一次网络数据MainActivity.javapacka...

运用AlarmManager实现的定时项目

  • 2016年09月08日 17:43
  • 32.87MB
  • 下载

定时任务,AlarmManager使用

项目需要:实现一个定时提醒的功能 查阅资料知道,需要使用AlarmManager AlarmManager介绍:  AlarmManager是Android的一个系统服务,通过Context.get...

Android利用AlarmManager执行定时任务

Android中的AlarmManager是一个全局定时器

AlarmManager定时重复任务,发送心跳

package com.example.alarm_1; import android.app.Activity; import android.app.AlarmManager; import a...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:8.4 AlarmManager实现精准定时任务
举报原因:
原因补充:

(最多只允许输入30个字)