Android AlarmManager實現不間斷輪詢服務

yangxi_001發表於2016-05-23

      在訊息的獲取上是選擇輪詢還是推送得根據實際的業務需要來技術選型,例如對訊息實時性比較高的需求,比如微博新通知或新聞等那就最好是用推送了。但如果只是一般的訊息檢測比如更新檢查,可能是半個小時或一個小時一次,那用輪詢也是一個不錯的選擇,因為不需要額外搭建推送伺服器,不用額外配置推送服務。另外推送現在一般以維持長連線的方式實現,在手機客戶端也會耗費一定的電量。今天就介紹一個在Android上實現輪詢機制的方法——使用AlarmManager

AlarmManager在Android中主要用來定時處理一個事件或是定期處理一個事件,比如鬧鐘應用就是使用AlarmManager來實現的,我們今天要使用AlarmManager的定期執行功能來實現輪詢的功能。對於定期執行任務也可以用Timer和TimerTask來實現,也可以開一個Service在Thread裡面以while迴圈來實現。但最好的方案還是選用AlarmManager,這裡涉及一個Android系統鎖的機制,即系統在檢測到一段時間沒有活躍以後,會關閉一些不必要的服務來減少資源和電量消耗。使用Timer和Service來實現的話很可能出現的情況就是螢幕熄滅後一段時間,服務就被停止了,當然輪詢也就被停止了。這個大家可以實驗一下,之前我寫過一篇文章也介紹了一種保持後臺喚醒的機制《使用WakeLock使Android應用程式保持後臺喚醒》,感興趣的可以看看。那麼接下來就開始使用AlarmManager+Service+Thread來實現我們的輪詢服務吧!


一、新建輪詢工具類PollingUtils.java

[java] view plain copy
  1. public class PollingUtils {  
  2.   
  3.     //開啟輪詢服務  
  4.     public static void startPollingService(Context context, int seconds, Class<?> cls,String action) {  
  5.         //獲取AlarmManager系統服務  
  6.         AlarmManager manager = (AlarmManager) context  
  7.                 .getSystemService(Context.ALARM_SERVICE);  
  8.           
  9.         //包裝需要執行Service的Intent  
  10.         Intent intent = new Intent(context, cls);  
  11.         intent.setAction(action);  
  12.         PendingIntent pendingIntent = PendingIntent.getService(context, 0,  
  13.                 intent, PendingIntent.FLAG_UPDATE_CURRENT);  
  14.           
  15.         //觸發服務的起始時間  
  16.         long triggerAtTime = SystemClock.elapsedRealtime();  
  17.           
  18.         //使用AlarmManger的setRepeating方法設定定期執行的時間間隔(seconds秒)和需要執行的Service  
  19.         manager.setRepeating(AlarmManager.ELAPSED_REALTIME, triggerAtTime,  
  20.                 seconds * 1000, pendingIntent);  
  21.     }  
  22.   
  23.     //停止輪詢服務  
  24.     public static void stopPollingService(Context context, Class<?> cls,String action) {  
  25.         AlarmManager manager = (AlarmManager) context  
  26.                 .getSystemService(Context.ALARM_SERVICE);  
  27.         Intent intent = new Intent(context, cls);  
  28.         intent.setAction(action);  
  29.         PendingIntent pendingIntent = PendingIntent.getService(context, 0,  
  30.                 intent, PendingIntent.FLAG_UPDATE_CURRENT);  
  31.         //取消正在執行的服務  
  32.         manager.cancel(pendingIntent);  
  33.     }  
  34. }  


二、構建輪詢任務執行PollingService.java

[java] view plain copy
  1. public class PollingService extends Service {  
  2.   
  3.     public static final String ACTION = "com.ryantang.service.PollingService";  
  4.       
  5.     private Notification mNotification;  
  6.     private NotificationManager mManager;  
  7.   
  8.     @Override  
  9.     public IBinder onBind(Intent intent) {  
  10.         return null;  
  11.     }  
  12.   
  13.     @Override  
  14.     public void onCreate() {  
  15.         initNotifiManager();  
  16.     }  
  17.       
  18.     @Override  
  19.     public void onStart(Intent intent, int startId) {  
  20.         new PollingThread().start();  
  21.     }  
  22.   
  23.     //初始化通知欄配置  
  24.     private void initNotifiManager() {  
  25.         mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);  
  26.         int icon = R.drawable.ic_launcher;  
  27.         mNotification = new Notification();  
  28.         mNotification.icon = icon;  
  29.         mNotification.tickerText = "New Message";  
  30.         mNotification.defaults |= Notification.DEFAULT_SOUND;  
  31.         mNotification.flags = Notification.FLAG_AUTO_CANCEL;  
  32.     }  
  33.   
  34.     //彈出Notification  
  35.     private void showNotification() {  
  36.         mNotification.when = System.currentTimeMillis();  
  37.         //Navigator to the new activity when click the notification title  
  38.         Intent i = new Intent(this, MessageActivity.class);  
  39.         PendingIntent pendingIntent = PendingIntent.getActivity(this0, i,  
  40.                 Intent.FLAG_ACTIVITY_NEW_TASK);  
  41.         mNotification.setLatestEventInfo(this,  
  42.                 getResources().getString(R.string.app_name), "You have new message!", pendingIntent);  
  43.         mManager.notify(0, mNotification);  
  44.     }  
  45.   
  46.     /** 
  47.      * Polling thread 
  48.      * 模擬向Server輪詢的非同步執行緒 
  49.      * @Author Ryan 
  50.      * @Create 2013-7-13 上午10:18:34 
  51.      */  
  52.     int count = 0;  
  53.     class PollingThread extends Thread {  
  54.         @Override  
  55.         public void run() {  
  56.             System.out.println("Polling...");  
  57.             count ++;  
  58.             //當計數能被5整除時彈出通知  
  59.             if (count % 5 == 0) {  
  60.                 showNotification();  
  61.                 System.out.println("New message!");  
  62.             }  
  63.         }  
  64.     }  
  65.       
  66.     @Override  
  67.     public void onDestroy() {  
  68.         super.onDestroy();  
  69.         System.out.println("Service:onDestroy");  
  70.     }  
  71.   
  72. }  

三、在MainActivity.java中開啟和停止PollingService

[java] view plain copy
  1. public class MainActivity extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.activity_main);  
  7.         //Start polling service  
  8.         System.out.println("Start polling service...");  
  9.         PollingUtils.startPollingService(this5, PollingService.class, PollingService.ACTION);  
  10.     }  
  11.       
  12.     @Override  
  13.     protected void onDestroy() {  
  14.         super.onDestroy();  
  15.         //Stop polling service  
  16.         System.out.println("Stop polling service...");  
  17.         PollingUtils.stopPollingService(this, PollingService.class, PollingService.ACTION);  
  18.     }  
  19.   
  20. }  


四、執行效果

執行工程後可以在控制檯輸出看到,每隔5s就發出一個通知,退出Activity時,輪詢服務就停止了,達到了我們事先期望的效果,並且鎖屏後很長一段時間也不會停止服務,因為AlarmManager是系統及服務。Demo效果如下圖:



在手機上我們可以看到彈出的通知資訊,點選通知則進到訊息介面:

                            


當進入訊息詳情Activity時,頂部狀態列的訊息通知就會取消,使用如下方式也可以取消狀態列頂部的訊息通知顯示:

[java] view plain copy
  1. NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);  
  2.         manager.cancelAll();  

以上就實現了使用AlarmManger實現輪詢的一種方式,有不足或缺陷的地方歡迎大家留言補充,以上程式碼只是部分,需要工程原始碼的同學可以到Github上Clone:https://github.com/tangren03/RTPollingDemo


加入我們的QQ群或微信公眾賬號請檢視:Ryan's zone公眾賬號及QQ群

同時歡迎關注我的新浪微博和我交流:@唐韌_Ryan

轉自:http://blog.csdn.net/ryantang03/article/details/9317499

相關文章