上次和大家分享了关于Notification的基础应用,包括简单的通知和自定义视图的通知。今天和大家分享一下如何实现一个可更新进度的通知。

我们将会模拟一个下载任务,先启动一个线程负责模拟下载工作,在这个过程中更新进度信息,然后下载线程把最新的进度信息以消息的形式,发送到UI线程的消息队列中,最后UI线程负责根据最新的进度信息来更新进度通知的UI界面。

好,大概就是这个步骤。接下来我们根据具体的实例来演示一下这个过程。

我们新建一个notification项目,然后修改/res/layout/main.xml布局文件,代码如下:

[html] view plaincopyprint?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent">
  6. <Button
  7. android:id="@+id/download"
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:text="download"
  11. android:onClick="download"/>
  12. <Button
  13. android:id="@+id/cancel"
  14. android:layout_width="fill_parent"
  15. android:layout_height="wrap_content"
  16. android:text="cancel"
  17. android:onClick="cancel"/>
  18. </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:id="@+id/download"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="download"android:onClick="download"/><Buttonandroid:id="@+id/cancel"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="cancel"android:onClick="cancel"/>
</LinearLayout>

注意,为了使示例中的Java代码看起来结构更加清晰,我们将按钮的点击事件都定义在布局文件中。

然后再来看一下MainActivity.java的代码:

[java] view plaincopyprint?
  1. package com.scott.notification;
  2. import android.app.Activity;
  3. import android.app.Notification;
  4. import android.app.NotificationManager;
  5. import android.app.PendingIntent;
  6. import android.content.Context;
  7. import android.content.Intent;
  8. import android.os.Bundle;
  9. import android.os.Handler;
  10. import android.os.Message;
  11. import android.view.View;
  12. import android.widget.RemoteViews;
  13. public class MainActivity extends Activity {
  14. private static final int NOTIFY_ID = 0;
  15. private boolean cancelled;
  16. private NotificationManager mNotificationManager;
  17. private Notification mNotification;
  18. private Context mContext = this;
  19. private Handler handler = new Handler() {
  20. public void handleMessage(android.os.Message msg) {
  21. switch (msg.what) {
  22. case 1:
  23. int rate = msg.arg1;
  24. if (rate < 100) {
  25. // 更新进度
  26. RemoteViews contentView = mNotification.contentView;
  27. contentView.setTextViewText(R.id.rate, rate + "%");
  28. contentView.setProgressBar(R.id.progress, 100, rate, false);
  29. } else {
  30. // 下载完毕后变换通知形式
  31. mNotification.flags = Notification.FLAG_AUTO_CANCEL;
  32. mNotification.contentView = null;
  33. Intent intent = new Intent(mContext, FileMgrActivity.class);
  34. PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
  35. mNotification.setLatestEventInfo(mContext, "下载完成", "文件已下载完毕", contentIntent);
  36. }
  37. // 最后别忘了通知一下,否则不会更新
  38. mNotificationManager.notify(NOTIFY_ID, mNotification);
  39. break;
  40. case 0:
  41. // 取消通知
  42. mNotificationManager.cancel(NOTIFY_ID);
  43. break;
  44. }
  45. };
  46. };
  47. @Override
  48. public void onCreate(Bundle savedInstanceState) {
  49. super.onCreate(savedInstanceState);
  50. setContentView(R.layout.main);
  51. }
  52. public void download(View view) {
  53. mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  54. int icon = R.drawable.down;
  55. CharSequence tickerText = "开始下载";
  56. long when = System.currentTimeMillis();
  57. mNotification = new Notification(icon, tickerText, when);
  58. // 放置在"正在运行"栏目中
  59. mNotification.flags = Notification.FLAG_ONGOING_EVENT;
  60. RemoteViews contentView = new RemoteViews(mContext.getPackageName(), R.layout.download_notification_layout);
  61. contentView.setTextViewText(R.id.fileName, "AngryBird.apk");
  62. // 指定个性化视图
  63. mNotification.contentView = contentView;
  64. // intent为null,表示点击通知时不跳转
  65. PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, null, 0);
  66. // 指定内容意图
  67. mNotification.contentIntent = contentIntent;
  68. mNotificationManager.notify(NOTIFY_ID, mNotification);
  69. new Thread() {
  70. public void run() {
  71. startDownload();
  72. };
  73. }.start();
  74. }
  75. public void cancel(View view) {
  76. cancelled = true;
  77. }
  78. private void startDownload() {
  79. cancelled = false;
  80. int rate = 0;
  81. while (!cancelled && rate < 100) {
  82. try {
  83. // 模拟下载进度
  84. Thread.sleep(500);
  85. rate = rate + 5;
  86. } catch (InterruptedException e) {
  87. e.printStackTrace();
  88. }
  89. Message msg = handler.obtainMessage();
  90. msg.what = 1;
  91. msg.arg1 = rate;
  92. handler.sendMessage(msg);
  93. }
  94. if (cancelled) {
  95. Message msg = handler.obtainMessage();
  96. msg.what = 0;
  97. handler.sendMessage(msg);
  98. }
  99. }
  100. }
package com.scott.notification;import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.RemoteViews;public class MainActivity extends Activity {private static final int NOTIFY_ID = 0;private boolean cancelled;private NotificationManager mNotificationManager;private Notification mNotification;private Context mContext = this;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);PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);mNotification.setLatestEventInfo(mContext, "下载完成", "文件已下载完毕", contentIntent);}// 最后别忘了通知一下,否则不会更新mNotificationManager.notify(NOTIFY_ID, mNotification);break;case 0:// 取消通知mNotificationManager.cancel(NOTIFY_ID);break;}};};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);}public void download(View view) {mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);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为null,表示点击通知时不跳转PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, null, 0);// 指定内容意图mNotification.contentIntent = contentIntent;mNotificationManager.notify(NOTIFY_ID, mNotification);new Thread() {public void run() {startDownload();};}.start();}public void cancel(View view) {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);}if (cancelled) {Message msg = handler.obtainMessage();msg.what = 0;handler.sendMessage(msg);}}
}

值得注意的是,在控制下载线程时使用了cancelled这个boolean值标志变量,对于线程的控制更好一些,不建议使用Thread.interrupt()去中断一个线程。另外,对于更新通知的UI界面时,要记住调用NotificationManager.notify(int id, Notification notification)方法通知一下,否则即使设置了新值,也不会起作用的。

程序中用到的带进度的通知布局/res/layout/download_notification_layout.xml布局文件代码如下:

[html] view plaincopyprint?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:padding="3dp">
  6. <ImageView
  7. android:id="@+id/imageView"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_margin="3dp"
  11. android:src="@drawable/down"/>
  12. <TextView
  13. android:id="@+id/fileName"
  14. android:layout_width="fill_parent"
  15. android:layout_height="fill_parent"
  16. android:layout_toRightOf="@id/imageView"
  17. android:layout_alignBottom="@id/imageView"
  18. android:gravity="center_vertical"
  19. android:textColor="#000"/>
  20. <TextView
  21. android:id="@+id/rate"
  22. android:layout_width="fill_parent"
  23. android:layout_height="wrap_content"
  24. android:layout_below="@id/imageView"
  25. android:layout_alignRight="@id/imageView"
  26. android:gravity="center"
  27. android:text="0%"
  28. android:textColor="#000"/>
  29. <ProgressBar
  30. android:id="@+id/progress"
  31. style="?android:attr/progressBarStyleHorizontal"
  32. android:layout_width="fill_parent"
  33. android:layout_height="wrap_content"
  34. android:layout_below="@id/fileName"
  35. android:layout_alignLeft="@id/fileName"
  36. android:max="100"
  37. android:progress="0"/>
  38. </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:padding="3dp"><ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="3dp"android:src="@drawable/down"/><TextViewandroid:id="@+id/fileName"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_toRightOf="@id/imageView"android:layout_alignBottom="@id/imageView"android:gravity="center_vertical"android:textColor="#000"/><TextViewandroid:id="@+id/rate"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@id/imageView"android:layout_alignRight="@id/imageView"android:gravity="center"android:text="0%"android:textColor="#000"/><ProgressBar android:id="@+id/progress"style="?android:attr/progressBarStyleHorizontal"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_below="@id/fileName"android:layout_alignLeft="@id/fileName"android:max="100"android:progress="0"/>
</RelativeLayout>

该通知的布局使用了相对布局,更加灵活易用,所以推荐大家多使用相对布局。

对于MainActivity.java中涉及到的FileMgrActivity,它是一个简单的界面,这里就不在介绍了,that's not the point。

最后我们跑一下程序,看看效果如何:

貌似还不错,好了,今天先到这里,下次再找机会分享。

<!-- Baidu Button BEGIN -->

Notification使用详解之二:可更新进度的通知相关推荐

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

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

  2. 【Google Play】App Bundle 使用详解 ( 简介 | 应用内更新 | 即时更新 | 灵活更新 )

    Google Play 上架完整流程 系列文章目录 [Google Play]创建 Google 开发者账号 ( 注册邮箱账号 | 创建开发者账号 ) [Google Play]创建并设置应用 ( 访 ...

  3. MySQL之SQL优化详解(二)

    目录 MySQL之SQL优化详解(二) 1. SQL的执行顺序 1.1 手写顺序 1.2 机读顺序 2. 七种join 3. 索引 3.1 索引初探 3.2 索引分类 3.3 建与不建 4. 性能分析 ...

  4. 一致性协议raft详解(二):安全性

    一致性协议raft详解(二):安全性 前言 安全性 log recovery 为什么no-op能解决不一致的问题? 成员变更 Single mempership change raft用到的随机时间 ...

  5. [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)...

    [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) 原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之 ...

  6. ViewPager 详解(二)---详解四大函数

    前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合Android的API说明 ...

  7. BIND配置文件详解(二)

    本文档摘录自<BIND9管理员手册>,如果有不对或者不清楚的地方,请大家告诉我,谢谢!   BIND配置文件详解(二)   6.options语句 options语句的定义和使用: opt ...

  8. Linux常用基本命令详解(二)-------磁盘分区和磁盘管理类命令

    Linux常用基本命令详解(一) Linux常用基本命令详解(二)-------磁盘分区和磁盘管理类命令 Linux常用基本命令详解(三) 1.磁盘分区 磁盘分区(系统分区)是使用分区编辑器(part ...

  9. CI流水线配置文件参数详解(二)

    文章目录 4. 参数详解(二) 4.9 git tag打标签的使用 4.10 ``allow_failure`` 4.11 ``when`` 关键字用于实现在作业失败时或发生故障时运行的作业 (whe ...

最新文章

  1. Radboud科学家探索材料「量子大脑」——没有软件,硬件也可以实现机器学习 | AI日报...
  2. Javascript与正则表达式
  3. 递归和迭代_迭代与递归
  4. 空类-自动生成的函数
  5. redis 哨兵_Redis的哨兵模式
  6. 【Java】ArrayList 为啥要实现 RandomAccess 接口
  7. java asm源码分析_探究CAS原理(基于JAVA8源码分析)
  8. windows temp用户问题
  9. Java并发AtomicIntegerArray类
  10. 前端测试框架Jest系列教程 -- Matchers(匹配器)
  11. MATLAB平台学习(9)信道模型
  12. Codevs1074:食物链——题解
  13. ELK日志平台---老男孩教育笔记
  14. android 首字母 验证码,Android 验证码功能实现代码
  15. matlab 为双y轴加标签,[转载]matlab双y轴添加误差棒(转载)
  16. 计算机组成原理实验三思考题,计算机组成原理实验三:存储器部件教学实验
  17. 依托抖音、快手直播的上架工具开发
  18. shell 函数详解
  19. 阿里云人工智能课程(一)机器学习介绍
  20. 北京Uber优步司机奖励政策(12月31日)

热门文章

  1. oralce 存储过程、函数和触发器
  2. Android studio ,Gradle 添加so库
  3. set 和 vector的简单比较
  4. linux内核驱动中对字符串的操作【转】
  5. chrome插件-显示在地址栏的二维码
  6. 数据库:mongodb与关系型数据库相比的优缺点zz (转)
  7. 生成网上下载的EF项目对应的数据库
  8. 为什么优秀的程序员也是优秀的设计师
  9. 《深入解析Android 虚拟机》——导读
  10. 【LeetCode题解】二叉树的遍历