• 使用AlarmManager定期执行工作


    新建一个Service来模拟后台执行的程序,PollingService.java:

    package com.ryantang.rtpollingdemo;
    
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    /**
     * Polling service
     * @Author Ryan
     * @Create 2013-7-13 涓婂崍10:18:44
     */
    public class PollingService extends Service {
    
        public static final String ACTION = "com.ryantang.service.PollingService";
        
        private Notification mNotification;
        private NotificationManager mManager;
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            initNotifiManager();
        }
        
        @Override
        public void onStart(Intent intent, int startId) {
            new PollingThread().start();
        }
        //初始化通知栏配置
        private void initNotifiManager() {
            mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            int icon = R.drawable.ic_launcher;
            mNotification = new Notification();
            mNotification.icon = icon;
            mNotification.tickerText = "New Message";
            mNotification.defaults |= Notification.DEFAULT_SOUND;
            mNotification.flags = Notification.FLAG_AUTO_CANCEL;
        }
        //弹出Notification
        private void showNotification() {
            mNotification.when = System.currentTimeMillis();
            //Navigator to the new activity when click the notification title
            Intent i = new Intent(this, MessageActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i,
                    Intent.FLAG_ACTIVITY_NEW_TASK);
            mNotification.setLatestEventInfo(this,
                    getResources().getString(R.string.app_name), "You have new message!", pendingIntent);
            mManager.notify(0, mNotification);
        }
    
        /**
         * Polling thread
         * 模拟向Server轮询的异步线程
         * @Author Ryan
         * @Create 2013-7-13 涓婂崍10:18:34
         */
        int count = 0;
        class PollingThread extends Thread {
            @Override
            public void run() {
                System.out.println("Polling...");
                count ++;
                //当计数能被5整除时弹出通知
                if (count % 5 == 0) {
                    showNotification();
                    System.out.println("New message!");
                }
            }
        }
        
        @Override
        public void onDestroy() {
            super.onDestroy();
            System.out.println("Service:onDestroy");
        }
    
    }

    别望了在AndroidManifest.xml中注册Service:

    <service android:name="com.ryantang.rtpollingdemo.PollingService">
                <intent-filter>
                    <action android:name="com.ryantang.service.PollingService"/>
                </intent-filter>
            </service>

    当计数能被5整除时弹出通知,点击通知后进入MessageActivity.java:

    package com.ryantang.rtpollingdemo;
    
    import android.app.Activity;
    import android.app.NotificationManager;
    import android.content.Context;
    import android.os.Bundle;
    
    public class MessageActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_message);
            System.out.println("新的activity");
            NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
            
            manager.cancelAll();
        }
    }
    View Code

    使用AlarmManager封装已给PollingUtils.java来执行Service的启动和停止,PollingUtils.java:

    package com.ryantang.rtpollingdemo;
    
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.os.SystemClock;
    /**
     * Polling Tools
     * @Author Ryan
     * @Create 2013-7-13 涓婂崍10:14:43
     */
    public class PollingUtils {
    
        /**开启轮询服务
         * @param context
         * @param seconds  定期执行的时间间隔
         * @param cls
         * @param action
         */ 
        public static void startPollingService(Context context, int seconds, Class<?> cls,String action) {
            //获取AlarmManager系统服务
            AlarmManager manager = (AlarmManager) context
                    .getSystemService(Context.ALARM_SERVICE);
            //包装需要执行Service的Intent
            Intent intent = new Intent(context, cls);
            intent.setAction(action);
            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                    intent, PendingIntent.FLAG_UPDATE_CURRENT);
            //触发服务的起始时间
            long triggerAtTime = SystemClock.elapsedRealtime();
            //使用AlarmManager的setRepeating方法设置定期执行时间间隔(seconds秒)和需要执行的Service
            manager.setRepeating(AlarmManager.ELAPSED_REALTIME, triggerAtTime,
                    seconds * 1000, pendingIntent);//第二个参数与第一个参数有对应的关系,ELAPSED_REALTIME对应的为SystemClock.elapsedRealTime,RTC对应的为System.currentTimeMills()
        }
    
        /**
         * 停止轮询服务
         * @param context
         * @param cls
         * @param action
         */
        public static void stopPollingService(Context context, Class<?> cls,String action) {
            //获取AlarmManager系统服务
            AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            Intent intent = new Intent(context, cls);
            intent.setAction(action);//需要与启动的action一致,负责无法取消定时任务
            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                    intent, PendingIntent.FLAG_UPDATE_CURRENT);
            //取消正在执行的服务
            manager.cancel(pendingIntent);
        }
    }

    最后在主程序中执行,MainActivity.java:

    package com.ryantang.rtpollingdemo;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // Start polling service
            System.out.println("Start polling service...");
            PollingUtils.startPollingService(this, 30, PollingService.class,PollingService.ACTION);// PollingService.ACTION与AndroidManifest.xml一一对应
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // Stop polling service
            System.out.println("Stop polling service...");
            PollingUtils.stopPollingService(this, PollingService.class,PollingService.ACTION);
        }
    
    }

    Android之AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

    (1)在指定时长后执行某项操作

    //操作:发送一个广播,广播接收后Toast提示定时操作完成
    Intent intent =new Intent(Main.this, alarmreceiver.class);
    intent.setAction("short");
    PendingIntent sender=
    PendingIntent.getBroadcast(Main.this, 0, intent, 0);
    
    //设定一个五秒后的时间
    Calendar calendar=Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.add(Calendar.SECOND, 5);
    
    AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE);
    alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
    //或者以下面方式简化
    //alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5*1000, sender);
    //注意:receiver记得在manifest.xml注册,使用的是静态的广播消息机制
    public static class alarmreceiver extends BroadcastReceiver{
    
    @Override
    public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    if(intent.getAction().equals("short")){
          Toast.makeText(context, "short alarm", Toast.LENGTH_LONG).show();
    }else{
           Toast.makeText(context, "repeating alarm",Toast.LENGTH_LONG).show();
        }
      }
    }
    //AndroidManifest.xml中需要注册广播接收器
    <receiver android:name="" > <intent-filter > <action android:name="short"><action /> </intent-filter> </receiver>

    AlarmManager类型如下:

    AlarmManager.RTC,硬件闹钟,不唤醒手机(也可能是其它设备)休眠;当手机休眠时不发射闹钟。

    AlarmManager.RTC_WAKEUP,硬件闹钟,当闹钟发射时唤醒手机休眠;

    AlarmManager.ELAPSED_REALTIME,真实时间流逝闹钟,不唤醒手机休眠;在指定的延时过后,发送广播,但不唤醒设备。

    AlarmManager.ELAPSED_REALTIME_WAKEUP,真实时间流逝闹钟,当闹钟发射时唤醒手机休眠; 

    RTC闹钟和ELAPSED_REALTIME最大的差别就是前者可以通过修改手机时间触发闹钟事件,后者要通过真实时间的流逝,即使在休眠状态,时间也会被计算。

    (2)周期性的执行某项操作

    Intent intent =new Intent(Main.this, alarmreceiver.class);
    intent.setAction("repeating");
    PendingIntent sender=PendingIntent
    .getBroadcast(Main.this, 0, intent, 0);
    //开始时间
    long firstime=SystemClock.elapsedRealtime();
    AlarmManager am=(AlarmManager)getSystemService(ALARM_SERVICE);
     //5秒一个周期,不停的发送广播
    am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstime, 5*1000, sender);

    AlarmManager的setRepeating()相当于Timer的Schedule(task,delay,peroid);有点差异的地方时Timer这个方法是指定延迟多长时间以后开始周期性的执行task;

    AlarmManager的取消:(其中需要注意的是取消的Intent必须与启动Intent保持绝对一致才能支持取消

    Intent intent =new Intent(Main.this, alarmreceiver.class);
    intent.setAction("repeating");
    PendingIntent sender=PendingIntent
    .getBroadcast(Main.this, 0, intent, 0);
    AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE);
    alarm.cancel(sender);

    当然还需要写一个静态的广播接收器。

    *****************************************2015-09-07 08:21:18***************************************************

    周期性执行选用的闹钟类型推荐AlarmManager.RTC_WAKEUP,经测试还是定时时间还是比较准确的,SystemClock.elapsedRealTime()指的的从计算机起始时间1970-1-1算1起,而System.currentTimeMills()指的是系统开机时间算起。

    ***********************************更新:2015-09-06 08:53:15*******************************************

    Android的碎片化严重,定制的ROM被国内厂商修改了很多,对于定时任务MIUI作为代表,开发者遇到到很多这样的情况,定时任务偏离,多半的原因是考虑到了系统休眠、降低CUP运行效率等等以达到省电的效果,这里就介绍另一种方法解决:PowerManager.WakeLock来实现要求的功能。

    PowerManager:给予控制设备电量状态的权限

    PowerManager.WakeLock:让系统知道你需要设置在工作状态上

    Android中通过各种Lock锁对电源进行控制,需要注意的是加锁和解锁必须成对出现

    首先获取权限:

    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.DEVICE_POWER"/>

    有时候Eclipse会提示系统应用才能需要这个权限,解决的办法是将项目Clean下即可。WakeLock的设置是Activity级别的,不是针对整个Application应用的。

    package com.eyu.wake_lock;  
      
    import android.app.Activity;  
    import android.os.Bundle;  
    import android.os.PowerManager;  
    import android.os.PowerManager.WakeLock;  
      
    public class Wake_lockActivity extends Activity {  
      
        private boolean iswakeLock = true;// 是否常亮  
        private WakeLock wakeLock;  
      
        /** Called when the activity is first created. */  
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
      
        }  
      
        @Override  
        protected void onResume() {  
            // TODO Auto-generated method stub  
            PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);  
            wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK  
                    | PowerManager.ON_AFTER_RELEASE, "DPA");  
      
            if (iswakeLock) {  
                wakeLock.acquire();  
            }  
            super.onResume();  
      
        }  
      
        @Override  
        protected void onPause() {  
            // TODO Auto-generated method stub  
            super.onDestroy();  
            if (wakeLock != null) {  
                wakeLock.release();  
            }  
            android.os.Process.killProcess(android.os.Process.myPid());  
        }  
      
    }  

    通常在onRusume方法中将获得到的锁使用acquire()方法来保持唤醒,在onPause方法中使用release()方法来释放掉该锁,利用Activity的生命周期来巧妙的使这两种方法成对的出现。

    PowerManager和WakeLock的操作步骤
    1. PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);通过 Context.getSystemService().方法获取PowerManager实例。
    2. 然后通过PowerManager的newWakeLock((int flags, String tag)来生成WakeLock实例。int Flags指示要获取哪种WakeLock,不同的Lock对cpu 、屏幕、键盘灯有不同影响。
    3. 获取WakeLock实例后通过acquire()获取相应的锁,然后进行其他业务逻辑的操作,最后使用release()释放(释放是必须的)。

    关于int flags

      各种锁的类型对CPU 、屏幕、键盘的影响:

      PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。

      SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯

      SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯

      FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度

      ACQUIRE_CAUSES_WAKEUP:正常唤醒锁实际上并不打开屏幕,但是,一旦打开就会一直保持。当获得wakelock,这个标志会使屏幕或/和键盘立即打开。一个典型的使用就是可以立即看到那些对用户重要的通知。

      ON_AFTER_RELEASE:设置了这个标志,当wakelock释放时用户activity计时器会被重置,导致照明持续一段时间。

     ***********************************更新:2015-09-15 20:24:29*******************************************

    使用AlarmManager就不需要设备锁了,测试过有时候还会导致程序报错,测试手机小米2S,先后试过MIUI、Lewa等第三方Rom,后来刷入Android4.0.3启动定时任务,毫秒不差 。

                                         

  • 相关阅读:
    悼念丹尼斯·里奇,那个给乔布斯提供肩膀的巨人(转载)
    c# 做成Windows服务
    Visual Studio 2010 新建完项目编译就出错
    C#调用Win32 的API函数User32.dll
    c# Remoting小例子
    backgroundworker使用 实现进度条ProgressBar
    winform最小化后隐藏到右下角,单击或双击后恢复
    关于Thread的实例
    c# 捕获的异常写到日志里
    C# delegate and event 规范写法
  • 原文地址:https://www.cnblogs.com/sowhat4999/p/4690850.html
Copyright © 2020-2023  润新知