在消息的获取上是选择 轮询还是推送得根据实际的业务需要来技术选型,例如对消息实时性比较高的需求,比如微博新通知或新闻等那就最好是用推送了。但如果只是一般的消息检测比如 更新检查,可能是半个小时或一个小时一次,那用轮询也是一个不错的选择,因为不需要额外搭建推送服务器,不用额外配置推送服务。另外推送现在一般以维持长 连接的方式实现,在手机客户端也会耗费一定的电量。今天就介绍一个在Android上实现轮询机制的方法——使用AlarmManager

AlarmManager 在Android中主要用来定时处理一个事件或是定期处理一个事件,比如闹钟应用就是使用AlarmManager来实现的,我们今天要使用 AlarmManager的定期执行功能来实现轮询的功能。对于定期执行任务也可以用Timer和TimerTask来实现,也可以开一个Service 在Thread里面以while循环来实现。但最好的方案还是选用AlarmManager,这里涉及一个Android系统锁的机制,即系统在检测到一 段时间没有活跃以后,会关闭一些不必要的服务来减少资源和电量消耗。使用Timer和Service来实现的话很可能出现的情况就是屏幕熄灭后一段时间, 服务就被停止了,当然轮询也就被停止了。这个大家可以实验一下,之前我写过一篇文章也介绍了一种保持后台唤醒的机制《使用WakeLock使Android应用程序保持后台唤醒》,感兴趣的可以看看。那么接下来就开始使用AlarmManager+Service+Thread来实现我们的轮询服务吧!

一、新建轮询工具类PollingUtils.java

  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, ,
  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 * , 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, ,
  30. intent, PendingIntent.FLAG_UPDATE_CURRENT);
  31. //取消正在执行的服务
  32. manager.cancel(pendingIntent);
  33. }
  34. }

二、构建轮询任务执行PollingService.java

  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(this, , 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(, mNotification);
  44. }
  45.  
  46. /**
  47. * Polling thread
  48. * 模拟向Server轮询的异步线程
  49. * @Author Ryan
  50. * @Create 2013-7-13 上午10:18:34
  51. */
  52. int count = ;
  53. class PollingThread extends Thread {
  54. @Override
  55. public void run() {
  56. System.out.println("Polling...");
  57. count ++;
  58. //当计数能被5整除时弹出通知
  59. if (count % == ) {
  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

  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(this, , 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时,顶部状态栏的消息通知就会取消,使用如下方式也可以取消状态栏顶部的消息通知显示:

  1. NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
  2. manager.cancelAll();

以上就实现了使用AlarmManger实现轮询的一种方式,有不足或缺陷的地方欢迎大家留言补充,以上代码只是部分,需要工程源码的同学可以到Github上Clone:https://github.com/tangren03/RTPollingDemo

Android AlarmManager实现不间断轮询服务的更多相关文章

  1. [置顶] Android AlarmManager实现不间断轮询服务

    在消息的获取上是选择轮询还是推送得根据实际的业务需要来技术选型,例如对消息实时性比较高的需求,比如微博新通知或新闻等那就最好是用推送了.但如果只是一般的消息检测比如更新检查,可能是半个小时或一个小时一 ...

  2. Android学习系列(7)--App轮询服务器消息

    这篇文章是android开发人员的必备知识. 1.轮询服务器     一般的应用,定时通知消息可以采用轮询的方法从服务器拿取消息,当然实时消息通知的话,建议采用推送服务.    其中需要注意轮询的频率 ...

  3. 背水一战 Windows 10 (112) - 通知(Badge): application 的 badge 通知, secondary 的 badge 通知, 轮询服务端以更新 badge 通知

    [源码下载] 背水一战 Windows 10 (112) - 通知(Badge): application 的 badge 通知, secondary 的 badge 通知, 轮询服务端以更新 bad ...

  4. 背水一战 Windows 10 (109) - 通知(Tile): 按计划显示 tile 通知, 轮询服务端以更新 tile 通知

    [源码下载] 背水一战 Windows 10 (109) - 通知(Tile): 按计划显示 tile 通知, 轮询服务端以更新 tile 通知 作者:webabcd 介绍背水一战 Windows 1 ...

  5. 日夕如是寒暑不间,基于Python3+Tornado6+APScheduler/Celery打造并发异步动态定时任务轮询服务

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_220 定时任务的典型落地场景在各行业中都很普遍,比如支付系统中,支付过程中因为网络或者其他因素导致出现掉单.卡单的情况,账单变成了 ...

  6. nginx 配置轮询服务

    通常我们应用nginx做代理时,用到它的轮训服务 #设置轮询名称 upstream zyy{ server 127.0.0.1:8080  #本机的apache服务 } server { listen ...

  7. Android 轮询之 Service + AlarmManager+Thread (转)

    android中涉及到将服务器中数据变化信息通知用户一般有两种办法,推送和轮询. 消息推送是服务端主动发消息给客户端,因为第一时间知道数据发生变化的是服务器自己,所以推送的优势是实时性高.但服务器主动 ...

  8. 三周,用长轮询实现Chat并迁移到Azure测试

    公司的OA从零开始进行开发,继简单的单点登陆.角色与权限.消息中间件之后,轮到在线即时通信的模块需要我独立去完成.这三周除了逛网店见爱*看动漫接兼职,基本上都花在这上面了.简单地说就是用MVC4基于长 ...

  9. polling轮询和comet

    comet:(原意:彗星) Comet is a web application model in which a long-held(held:保留) HTTP request allows a w ...

随机推荐

  1. 快速查询本机IP 分类: windows常用小技巧 2014-04-15 09:28 138人阅读 评论(0) 收藏

    第一步: 点击windows建(屏幕左下方),在搜索程序和文件文本框内输入:cmd 第二步:      点击Enter建进入. 第三步: 输入:ipconfig即可. 版权声明:本文为博主原创文章,未 ...

  2. Lucene为不同字段指定不同分词器(转)

    在lucene使用过程中,如果要对同一IndexWriter中不同 Document,不同Field中使用不同的analyzer,我们该如何实现呢? 通过对<lucene in action&g ...

  3. 概率dp-九度-1546-迷宫问题

    题目链接: http://ac.jobdu.com/problem.php?pid=1546 题目意思: 有一个起点S,多个出口E,#代表不能走,每次等概率的随机选择下一个可以行走的位置,求从S到出口 ...

  4. [PWA] 1. Intro to Service worker

    Service worker stays between our browser and noetwork requests. It can help to fetch data from cache ...

  5. java——递归调用

    递归函数调用调用本身,并通过自己的相应参数,这个计算过程中进行层,直到满足某些条件,只要停止呼叫. 递归函数的特点 1.函数要直接或间接调用自身. 2.要有递归终止条件检查.即递归终止的条件被满足后. ...

  6. VMware于CentOS网络设置

    VMware于CentOS网络设置 底: 笔记本电脑有两块网卡: 1. 网卡连接公司内网,仅仅配置了内网ip和子网掩码. 2. 无线网卡.连接4g无线路由器.dhcp自己主动配置. 问题: 在VMwa ...

  7. CF 19D Points 【线段树+平衡树】

    在平面上进行三种操作: 1.add x y:在平面上添加一个点(x,y) 2.remove x y:将平面上的点(x,y)删除 3.find x y:在平面上寻找一个点,使这个点的横坐标大于x,纵坐标 ...

  8. 码表 ASCII Unicode GBK UTF-8

    2017-1-3 [ASCII]一个字节(7位,128个字符,2个16进制) 不包含中文 ASCII(American Standard Code for Information Interchang ...

  9. 1247 排排站 USACO(查分+hash)

    /* 暴力查分 n*n */ #include<cstdio> #include<cstring> #include<iostream> #define maxn ...

  10. angular中ueditor插件的使用

    #在angularjs中使用ueditor编辑器需要注意事项: 在ui-view中使用放置ueditor的div,页面加载时编辑器在页面中是不显示的,需要通过指令手动replay 例: /** * u ...