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

Stella981
• 阅读 548

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

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

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

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

首先是MainActivity:

[java] view plain copy

  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. }

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

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

[java] view plain copy

  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. }

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

最后再来看一下FileMgrActivity:

[java] view plain copy

  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. }

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

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

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

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
unity将 -u4E00 这种 编码 转汉字 方法
 unity中直接使用 JsonMapper.ToJson(对象),取到的字符串,里面汉字可能是\\u4E00类似这种其实也不用转,服务器会通过类似fastjson发序列化的方式,将json转对象,获取对象的值就是中文但是有时服务器要求将传参中字符串中类似\\u4E00这种转汉字,就需要下面 publ
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Stella981 Stella981
2年前
Notification使用详解之三:通过服务更新进度通知&在Activity中监听服务进度
上次我们讲到如何实现一个可更新的进度通知,实现的方式是启动一个线程模拟一个下载任务,然后根据任务进度向UI线程消息队列发送进度消息,UI线程根据进度消息更新通知的UI界面。可是在实际应用中,我们一般会将上传、下载等比较耗时的后台任务以服务的形式运行,更新进度通知也是交由后台服务来完成的。不过有的时候,除了在通知里面显示进度信息,我们也要在Activit
京东云开发者 京东云开发者
5个月前
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这