上次讲到了如何在Activity中监听后台服务的进度信息,实现的方式是让Activity与后台服务绑定,通过中间对象Binder的实例操作后台服务。从效果上来讲,这种方式是可行的,不过这种实现有个缺点,那就是Activity的任务太重了,为了监听服务的状态,我们不得不绑定服务,然后还需不断地定时的获取最新的进度,我们为何不换一下形式呢,让Service主动将进度发送给Activity,我们在Activity中只需拿到进度数据,然后更新UI界面。这种新形式就像上次结尾提到的,就像两个男人同时喜欢一个女人,都通过自己的手段试图从那个女人那里获取爱情,现在我们要让那个女人变为主动方,将爱情同时传递给那两个男人。

要实现以上方式,我们需要用到BroadcastReceiver,如果不太了解的朋友们,可以查阅相关资料补充一下。

关于整个流程的的截图,我在这里就不在贴出了,大家可以参看Notification详解之三的流程截图。布局文件也没有变化,所以这里也不在贴出。

我们主要看一下MainActivity、DownloadService、FileMgrActivity这几个组件的实现形式。

首先是MainActivity:

[java] view plaincopyprint?
  1. package com.scott.notification;
  2. import android.app.Activity;
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.IntentFilter;
  7. import android.os.Bundle;
  8. import android.view.View;
  9. import android.widget.TextView;
  10. public class MainActivity extends Activity {
  11. private MyReceiver receiver;
  12. private TextView text;
  13. @Override
  14. public void onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.main);
  17. text = (TextView) findViewById(R.id.text);
  18. receiver = new MyReceiver();
  19. IntentFilter filter = new IntentFilter();
  20. filter.addAction("android.intent.action.MY_RECEIVER");
  21. //注册
  22. registerReceiver(receiver, filter);
  23. }
  24. @Override
  25. protected void onDestroy() {
  26. super.onDestroy();
  27. //不要忘了这一步
  28. unregisterReceiver(receiver);
  29. }
  30. public void start(View view) {
  31. Intent intent = new Intent(this, DownloadService.class);
  32. //这里不再使用bindService,而使用startService
  33. startService(intent);
  34. }
  35. /**
  36. * 广播接收器
  37. * @author user
  38. *
  39. */
  40. private class MyReceiver extends BroadcastReceiver {
  41. @Override
  42. public void onReceive(Context context, Intent intent) {
  43. Bundle bundle = intent.getExtras();
  44. int progress = bundle.getInt("progress");
  45. text.setText("downloading..." + progress + "%");
  46. }
  47. }
  48. }
package com.scott.notification;import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;public class MainActivity extends Activity {private MyReceiver receiver;private TextView text;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);text = (TextView) findViewById(R.id.text);receiver = new MyReceiver();IntentFilter filter = new IntentFilter();filter.addAction("android.intent.action.MY_RECEIVER");//注册registerReceiver(receiver, filter);}@Overrideprotected void onDestroy() {super.onDestroy();//不要忘了这一步unregisterReceiver(receiver);}public void start(View view) {Intent intent = new Intent(this, DownloadService.class);//这里不再使用bindService,而使用startServicestartService(intent);}/*** 广播接收器* @author user**/private class MyReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Bundle bundle = intent.getExtras();int progress = bundle.getInt("progress");text.setText("downloading..." + progress + "%");}}
}

上面的代码中,我们的MyReceiver类是继承了BroadcastReceiver,在onReceive方法中,定义了收到进度信息并更新UI的逻辑,在onCreate中,我们注册了这个接受者,并指定action为android.intent.action.MY_RECEIVER,如此一来,如果其他组件向这个指定的action发送消息,我们就能够接收到;另外要注意的是,不要忘了在Activity被摧毁的时候调用unregisterReceiver取消注册。

然后再来看一下DownloadService有什么变化:

[java] view plaincopyprint?
  1. package com.scott.notification;
  2. import android.app.Notification;
  3. import android.app.NotificationManager;
  4. import android.app.PendingIntent;
  5. import android.app.Service;
  6. import android.content.Context;
  7. import android.content.Intent;
  8. import android.os.Handler;
  9. import android.os.IBinder;
  10. import android.os.Message;
  11. import android.widget.RemoteViews;
  12. public class DownloadService extends Service {
  13. private static final int NOTIFY_ID = 0;
  14. private boolean cancelled;
  15. private Context mContext = this;
  16. private NotificationManager mNotificationManager;
  17. private Notification mNotification;
  18. private Handler handler = new Handler() {
  19. public void handleMessage(android.os.Message msg) {
  20. switch (msg.what) {
  21. case 1:
  22. int rate = msg.arg1;
  23. if (rate < 100) {
  24. //更新进度
  25. RemoteViews contentView = mNotification.contentView;
  26. contentView.setTextViewText(R.id.rate, rate + "%");
  27. contentView.setProgressBar(R.id.progress, 100, rate, false);
  28. } else {
  29. //下载完毕后变换通知形式
  30. mNotification.flags = Notification.FLAG_AUTO_CANCEL;
  31. mNotification.contentView = null;
  32. Intent intent = new Intent(mContext, FileMgrActivity.class);
  33. // 告知已完成
  34. intent.putExtra("completed", "yes");
  35. //更新参数,注意flags要使用FLAG_UPDATE_CURRENT
  36. PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
  37. mNotification.setLatestEventInfo(mContext, "下载完成", "文件已下载完毕", contentIntent);
  38. }
  39. // 最后别忘了通知一下,否则不会更新
  40. mNotificationManager.notify(NOTIFY_ID, mNotification);
  41. if (rate >= 100) {
  42. stopSelf(); //停止服务
  43. }
  44. break;
  45. case 0:
  46. // 取消通知
  47. mNotificationManager.cancel(NOTIFY_ID);
  48. break;
  49. }
  50. };
  51. };
  52. @Override
  53. public void onCreate() {
  54. super.onCreate();
  55. mNotificationManager = (NotificationManager) getSystemService(android.content.Context.NOTIFICATION_SERVICE);
  56. }
  57. @Override
  58. public void onStart(Intent intent, int startId) {
  59. super.onStart(intent, startId);
  60. int icon = R.drawable.down;
  61. CharSequence tickerText = "开始下载";
  62. long when = System.currentTimeMillis();
  63. mNotification = new Notification(icon, tickerText, when);
  64. // 放置在"正在运行"栏目中
  65. mNotification.flags = Notification.FLAG_ONGOING_EVENT;
  66. RemoteViews contentView = new RemoteViews(mContext.getPackageName(), R.layout.download_notification_layout);
  67. contentView.setTextViewText(R.id.fileName, "AngryBird.apk");
  68. // 指定个性化视图
  69. mNotification.contentView = contentView;
  70. Intent intnt = new Intent(this, FileMgrActivity.class);
  71. PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intnt, PendingIntent.FLAG_UPDATE_CURRENT);
  72. // 指定内容意图
  73. mNotification.contentIntent = contentIntent;
  74. mNotificationManager.notify(NOTIFY_ID, mNotification);
  75. new Thread() {
  76. public void run() {
  77. startDownload();
  78. };
  79. }.start();
  80. }
  81. @Override
  82. public void onDestroy() {
  83. super.onDestroy();
  84. cancelled = true;   //停止下载线程
  85. }
  86. private void startDownload() {
  87. cancelled = false;
  88. int rate = 0;
  89. while (!cancelled && rate < 100) {
  90. try {
  91. //模拟下载进度
  92. Thread.sleep(500);
  93. rate = rate + 5;
  94. } catch (InterruptedException e) {
  95. e.printStackTrace();
  96. }
  97. Message msg = handler.obtainMessage();
  98. msg.what = 1;
  99. msg.arg1 = rate;
  100. handler.sendMessage(msg);
  101. //发送特定action的广播
  102. Intent intent = new Intent();
  103. intent.setAction("android.intent.action.MY_RECEIVER");
  104. intent.putExtra("progress", rate);
  105. sendBroadcast(intent);
  106. }
  107. if (cancelled) {
  108. Message msg = handler.obtainMessage();
  109. msg.what = 0;
  110. handler.sendMessage(msg);
  111. }
  112. }
  113. @Override
  114. public IBinder onBind(Intent intent) {
  115. return null;
  116. }
  117. }
package com.scott.notification;import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.widget.RemoteViews;public class DownloadService extends Service {private static final int NOTIFY_ID = 0;private boolean cancelled;private Context mContext = this;private NotificationManager mNotificationManager;private Notification mNotification;private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case 1:int rate = msg.arg1;if (rate < 100) {//更新进度RemoteViews contentView = mNotification.contentView;contentView.setTextViewText(R.id.rate, rate + "%");contentView.setProgressBar(R.id.progress, 100, rate, false);} else {//下载完毕后变换通知形式mNotification.flags = Notification.FLAG_AUTO_CANCEL;mNotification.contentView = null;Intent intent = new Intent(mContext, FileMgrActivity.class);// 告知已完成intent.putExtra("completed", "yes");//更新参数,注意flags要使用FLAG_UPDATE_CURRENTPendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);mNotification.setLatestEventInfo(mContext, "下载完成", "文件已下载完毕", contentIntent);}// 最后别忘了通知一下,否则不会更新mNotificationManager.notify(NOTIFY_ID, mNotification);if (rate >= 100) {stopSelf();  //停止服务}break;case 0:// 取消通知mNotificationManager.cancel(NOTIFY_ID);break;}};};@Overridepublic void onCreate() {super.onCreate();mNotificationManager = (NotificationManager) getSystemService(android.content.Context.NOTIFICATION_SERVICE);}@Overridepublic void onStart(Intent intent, int startId) {super.onStart(intent, startId);int icon = R.drawable.down;CharSequence tickerText = "开始下载";long when = System.currentTimeMillis();mNotification = new Notification(icon, tickerText, when);// 放置在"正在运行"栏目中mNotification.flags = Notification.FLAG_ONGOING_EVENT;RemoteViews contentView = new RemoteViews(mContext.getPackageName(), R.layout.download_notification_layout);contentView.setTextViewText(R.id.fileName, "AngryBird.apk");// 指定个性化视图mNotification.contentView = contentView;Intent intnt = new Intent(this, FileMgrActivity.class);PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intnt, PendingIntent.FLAG_UPDATE_CURRENT);// 指定内容意图mNotification.contentIntent = contentIntent;mNotificationManager.notify(NOTIFY_ID, mNotification);new Thread() {public void run() {startDownload();};}.start();}@Overridepublic void onDestroy() {super.onDestroy();cancelled = true;   //停止下载线程}private void startDownload() {cancelled = false;int rate = 0;while (!cancelled && rate < 100) {try {//模拟下载进度Thread.sleep(500);rate = rate + 5;} catch (InterruptedException e) {e.printStackTrace();}Message msg = handler.obtainMessage();msg.what = 1;msg.arg1 = rate;handler.sendMessage(msg);//发送特定action的广播Intent intent = new Intent();intent.setAction("android.intent.action.MY_RECEIVER");intent.putExtra("progress", rate);sendBroadcast(intent);}if (cancelled) {Message msg = handler.obtainMessage();msg.what = 0;handler.sendMessage(msg);}}@Overridepublic IBinder onBind(Intent intent) {return null;}
}

可以看到,我们在onBind方法里不在返回自定义的Binder实例了,因为现在的Service和Activitys之间并没有绑定关系了,他们是独立的;在下载过程中,我们会调用sendBroadcast方法,向指定的action发送一个附带有进度信息的intent,这样的话,所有注册过action为android.intent.action.MY_RECEIVER的Activity都能收到这条进度消息了。

最后再来看一下FileMgrActivity:

[java] view plaincopyprint?
  1. package com.scott.notification;
  2. import android.app.Activity;
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.IntentFilter;
  7. import android.os.Bundle;
  8. import android.view.View;
  9. import android.widget.ProgressBar;
  10. public class FileMgrActivity extends Activity {
  11. private MyReceiver receiver;
  12. private ProgressBar progressBar;
  13. @Override
  14. public void onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.filemgr);
  17. progressBar = (ProgressBar) findViewById(R.id.progress);
  18. if ("yes".equals(getIntent().getStringExtra("completed"))) {
  19. progressBar.setProgress(100);
  20. }
  21. receiver = new MyReceiver();
  22. IntentFilter filter = new IntentFilter();
  23. filter.addAction("android.intent.action.MY_RECEIVER");
  24. //注册
  25. registerReceiver(receiver, filter);
  26. }
  27. public void cancel(View view) {
  28. Intent intent = new Intent(this, DownloadService.class);
  29. stopService(intent);
  30. }
  31. @Override
  32. protected void onDestroy() {
  33. super.onDestroy();
  34. //不要忘了这一步
  35. unregisterReceiver(receiver);
  36. }
  37. /**
  38. * 广播接收器
  39. * @author user
  40. *
  41. */
  42. private class MyReceiver extends BroadcastReceiver {
  43. @Override
  44. public void onReceive(Context context, Intent intent) {
  45. Bundle bundle = intent.getExtras();
  46. int progress = bundle.getInt("progress");
  47. progressBar.setProgress(progress);
  48. }
  49. }
  50. }
package com.scott.notification;import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;public class FileMgrActivity extends Activity {private MyReceiver receiver;private ProgressBar progressBar;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.filemgr);progressBar = (ProgressBar) findViewById(R.id.progress);if ("yes".equals(getIntent().getStringExtra("completed"))) {progressBar.setProgress(100);}receiver = new MyReceiver();IntentFilter filter = new IntentFilter();filter.addAction("android.intent.action.MY_RECEIVER");//注册registerReceiver(receiver, filter);}public void cancel(View view) {Intent intent = new Intent(this, DownloadService.class);stopService(intent);}@Overrideprotected void onDestroy() {super.onDestroy();//不要忘了这一步unregisterReceiver(receiver);}/*** 广播接收器* @author user**/private class MyReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Bundle bundle = intent.getExtras();int progress = bundle.getInt("progress");progressBar.setProgress(progress);}}}

我们发现,FileMgrActivity的模式和MainActivity差不多,也是注册了相同的广播接收者,对于DownloadService来说自己是广播基站,MainActivity和FileMgrActivity就是听众,信号能够同时到达多个听众,对于代码而言,与之前的代码比较一下,发现简洁了许多,显然这种方式更好一些。

对于我们上面提到的男女关系,DownloadService就是那个女人,然后两个男人将自己的手机号告知了女人,等于注册了接收器,然后女人将短信群发给两个男人。不过在这种情况下,两个男人互相都不知道对方的存在,以为女人深深的爱着自己,等到发现一切的时候,就是痛苦的时候。相信大家如果遇到这种情况都会很痛苦吧,至于你们信不信,我反正是信的。哈哈。

其实关于Notification的讲解最后两篇涉及到Notification的不多,主要是围绕Notification做一些实际的应用示例,希望对于朋友们平时遇到的问题会有所帮助,如果这方面有了新的研究总结,我会再及时更新的,谢谢大家。

Notification使用详解之四:由后台服务向Activity发送进度信息相关推荐

  1. Notification使用详解之三:通过服务更新进度通知在Activity中监听服务进度

    为什么80%的码农都做不了架构师?>>>    上次我们讲到如何实现一个可更新的进度通知,实现的方式是启动一个线程模拟一个下载任务,然后根据任务进度向UI线程消息队列发送进度消息,U ...

  2. ios 后台唤醒应用_IOS开发之----详解在IOS后台执行

    文一 我从苹果文档中得知,一般的应用在进入后台的时候可以获取一定时间来运行相关任务,也就是说可以在后台运行一小段时间. 还有三种类型的可以运行在后以, 1.音乐 2.location 3.voip 文 ...

  3. Android Notification通知详解

    Android Notification通知详解 Notification: (一).简介: 显示在手机状态栏的通知.Notification所代表的是一种具有全局效果的通知,程序一般通过Notifi ...

  4. Git详解之四 服务器上的Git

    Git详解之四 服务器上的Git 服务器上的 Git 到目前为止,你应该已经学会了使用 Git来完成日常工作.然而,如果想与他人合作,还需要一个远程的 Git仓库.尽管技术上可以从个人的仓库里推送和拉 ...

  5. vue连接后端本地接口_详解vue配置后台接口方式

    详解vue配置后台接口方式 在vueAdmin项目中有两种方式配置后端接口的方式,在此做下记录 第一种(代理方式) 在工程目录下 > config > index.js - 修改为如下配置 ...

  6. Fragment详解之四——管理Fragment(2)

    相关文章: 1.<Fragment详解之一--概述> 2.<Fragment详解之二--基本使用方法> 3.<Fragment详解之三--管理Fragment(1)> ...

  7. java 重定向 redirect_详解Java从后台重定向(redirect)到另一个项目的方法

    (1)通过ModelAndView跳转 @RequestMapping("alipayforward") public ModelAndView alipayforward(Htt ...

  8. PM配置详解之四:维护和服务处理

    31. 维护数值种类 功能说明 配置路径 IMG->工厂维护和客户服务->维护和服务处理->基本设置->成本显示设置->维护数值种类 业务示例 配置步骤 31. 将成本元 ...

  9. 史上最强Dubbo面试28题答案详解:核心功能+服务治理+架构设计等

    1.Dubbo是什么? Dubbo 是一个分布式.高性能.透明化的 RPC 服务框架,提供服务自动注册.自动发现等高效服务治理方案, 可以和 Spring 框架无缝集成. RPC 指的是远程调用协议, ...

最新文章

  1. B/S软件超越C/S软件的优势在哪里?
  2. 兴趣部落的 Git 迁移实践
  3. Nosql数据一致性技术概要
  4. python2 转 python3 代码
  5. phpcmsV9推荐位posid文章,图片不显示问题 - 思路篇
  6. 计算机大学英语值最高的3项,计算机等级考试一级B上机试题:Windows字处理
  7. 程序相关概念及OS Linux发行版
  8. 六石管理学:做产品,要确定自己是太子还是陪太子
  9. (一)员工信息管理系统(超级详细代码)
  10. 面了6家大厂,我把问烂了的Redis常见面试题总结了一下(带答案)
  11. 11月4日绿健简报,星期五,农历十月十一
  12. 培训班出身的程序员为什么遭人嫌弃
  13. “春节游”还准备去海外猎食新鲜?麻烦!家门口明明啥都有!
  14. it系统应急响应流程图_[应急处理程序] 应急响应程序6个过程
  15. 使用中文维基百科语料库训练一个word2vec模型 12.1
  16. 5G网络的关键技术及特点,面临的挑战!
  17. 一个比较全的C++农历算法
  18. 【逗老师带你考IE】如何快速通过HCIE考试
  19. 中电信CDMA战略 CDMA+WiFi成杀手锏
  20. Python|让python帮忙做鸡兔同笼

热门文章

  1. mysql 定期删除表中无用数据
  2. 【比赛】百度之星2017 复赛
  3. Java程序员的日常 —— 响应式导航Demo
  4. python打开一个本地目录文件路径
  5. SOA相关资料整理分享
  6. 企业邮件系统搭建-关于不能往yahoo,sina,hotmail地址发邮件的问题一
  7. Educational Codeforces Round 65 (Rated for Div. 2) C. News Distribution
  8. 因讨要介绍费引发纠纷 浙江龙湾一男子砍死房产中介
  9. vue-cli的项目文件说明
  10. 第二次冲刺-个人工作总结08