Notification
概述
字面意思为通知,实际上也是。通知平时在大家手机接触的比较多了,这里指的通知一般是手机下拉菜单里的那个通知。
说的规范一点,就是在应用常规界面之外展示的消息。
通知抽屉(notificationdrawer)中的notification有两种显示方式
- 普通视图
notification drawer的标准显示方式 -
宽视图
当app让系统发送一个消息的时候,消息首先以图表的形式显示在通知栏。要查看消息的详情需要进入通知抽屉(notificationdrawer)中查看。(notificationdrawer)都是系统层面控制的,你可以随时查看,不限制于app。
?来自Android API文档
必需的通知内容
Notification 对象必须包含以下内容:
- 小图标,由 setSmallIcon() 设置
- 标题,由 setContentTitle() 设置
- 详细文本,由 setContentText()设置
布局
为了方便测试,设置几个按钮。
并事先设置好对应的点击事件,即接下来要进行测试的几个通知类型。
然后为了稍微整齐点用LinearLayout,代码很简单,就直接放出了。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/normal_view"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:onClick="sendNotification1"
android:text="普通的通知" />
<Button
android:id="@+id/big_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="sendNotification2"
android:text="大视图通知" />
<Button
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="sendNotification3"
android:text="进度条通知" />
<Button
android:id="@+id/button4_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="sendNotification4"
android:text="自定义视图通知" />
</LinearLayout>
实现
普通通知
- 先实例化对象,new一个notification,这里需要注意的是,可能不能直接new(如果你的API低于11)
Notification n=new Notification()
而需要使用下面的语句来进行(最下面那个是v4支持包,如果你想在低版本的的API也使用Builder)
Notification.Builder builder=new Notification.Builder(this)
NotificationCompat.Builder builder=new NotificationCompat.Builder(this)
代码如下:
- 然后是设置相关属性
- 接着创建一个通知对象,注意API版本需要大于16,低于16可以试试实例化的时候使用上面的v4支持包。
- 最后是推送通知 (先取得服务的实例,然后notify)
package com.example.a3_22notification;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
//id
private static final int NID_1=0x1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//普通的通知
public void sendNotification1(View view){
Notification.Builder builder=new Notification.Builder(this);
//设置相关的属性
//设置图标
builder.setSmallIcon(R.mipmap.ic_launcher);
//设置通知标题
builder.setContentTitle("这是标题");
//设置通知内容
builder.setContentText("这是通知正文!");
//创建一个通知对象
Notification n =builder.build();
//推送通知
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_1,n);
}
}
效果图:
普通通知的补充
上面的案例只提供了三个基本属性,但是这三个基本属性也是必须要有的!下面给出一些更丰富属性
考虑到某些属性对版本和测试环境有一定的限制,就不进一一行测试了。
//设置常驻通知(一般不能被清除,除非退出)
//builder.setOngoing(true);
//设置自动清除,当你点击完通知后,它会自动被清除
builder.setAutoCancel(true);
//设置通知铃声 提供几个参数
/*
Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。
Notification.DEFAULT_SOUND:系统默认铃声。
Notification.DEFAULT_VIBRATE:系统默认震动。
Notification.DEFAULT_LIGHTS:系统默认闪光。
*/
builder.setDefaults(上面列出的参数);
//设置通知栏字体内容,安卓5.0以下有效,5.0以上需要再设置内开启辅助功能
builder.setTicker("自定义内容");
//通知集合数量,显示在右下角,高版本也已经看不到了
builder.setNumber(int类型);
下面基于setContentInten——通知事件,来进行一段测试
它具有一个参数PendingIntent——待确定的意图
待确定的意图具有getActivity的能力,从而达成了点击事件可以跳转到另一个Activity的效果
为此我们需要创建一个新的Activity,内容任意即可,就不给出了。
下面提供修改后的代码:
package com.example.a3_22notification;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
//id
private static final int NID_1 = 0x1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//普通的通知
public void sendNotification1(View view) {
Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
//设置图标
builder.setSmallIcon(R.mipmap.ic_launcher);
//设置通知标题
builder.setContentTitle("这是标题");
//设置通知内容
builder.setContentText("这是通知正文!");
Intent intent = new Intent(this, Test.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//参数:上下文,请求编码,意图,创建PendingIntet的方式
/*
PendingIntent.FLAG_CANCEL_CURRENT:取消当前的PI,创建新的
PendingIntent.FLAG_NO_CREATE:如果有就用,没有不创建
PendingIntent.FLAG_ONE_SHOT:只使用一次
PendingIntent.FLAG_UPDATE_CURRENT:如果有,更新Intent,没有就创建
*/
builder.setContentIntent(pi);
//通知的事件
//创建一个通知对象
Notification n = builder.build();
//推送通知
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_1, n);
}
}
点击后成功跳转...
另外,还有几个小Tips
关闭通知
当然之前提到的为它设置点击后直接关闭的属性也完全可以达到同样的效果,可以通过在新建的Activity中加入
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(MainActivity.NID_1);
来实现,打开点击通知进入新界面后通知关闭的效果。NID_1为你为通知定义的ID。
传递信息
在通知的Activity中加上Intent.putExtra("xxx","消息文本");
在弹出的Activity中用getIntent.getStringExtra("xxx");将可以接受这段内容。
效果如下,可以看到,虽然Textview文本原来是“这是一段测试内容...”
但是已经变成了通知所在Activity传来的消息文本了。
更新通知
修改通知并不困难,再创建一个NotifactionCompat.Builder对象,同时在NotifactionManager.notify调用时候,使用老的通知的ID即可。
宽视图通知
其实和普通通知没有本质差别,主要在于多了一个InboxStyle的使用,下面直接上代码
了解宽视图style的一些基本设置。
package com.example.a3_22notification;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
//id
private static final int NID_1 = 0x1;
private static final int NID_2 = 0x2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//普通的通知
public void sendNotification1(View view) {
Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
//设置图标
builder.setSmallIcon(R.mipmap.ic_launcher);
//设置通知标题
builder.setContentTitle("这是标题");
//设置通知内容
builder.setContentText("这是通知正文!");
Intent intent = new Intent(this, Test.class);
intent.putExtra("msg","这是由首页发送来的通知");
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//参数:上下文,请求编码,意图,创建PendingIntet的方式
/*
PendingIntent.FLAG_CANCEL_CURRENT:取消当前的PI,创建新的
PendingIntent.FLAG_NO_CREATE:如果有就用,没有不创建
PendingIntent.FLAG_ONE_SHOT:只使用一次
PendingIntent.FLAG_UPDATE_CURRENT:如果有,更新Intent,没有就创建
*/
builder.setContentIntent(pi);
//通知的事件
//创建一个通知对象
Notification n = builder.build();
//推送通知
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_1, n);
}
//宽视图
public void sendNotification2(View v){
Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("这是标题");
builder.setContentText("这是通知内容");
//宽视图样式设置
Notification.InboxStyle style=new Notification.InboxStyle();
style.setBigContentTitle("大视图标题");
style.addLine("第一行");
style.addLine("第二行");
style.addLine("第三行");
style.addLine("第四行");
builder.setStyle(style);
style.setSummaryText("设置概要文本");
//宽视图样式结束
Notification n=builder.build();
NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_2,n);
}
}
效果一览(不同版本可能显示的位置如概要文本有一定差异)
进度条通知
通知是可以包含一个动态的进度条的,之前学习了ProgressBar是静态的和动态的设置方法。
在这里就可以进行运用了。
ProgressBar相关可以参考我之前的文章
在Android4.0版本之前需要单独创建布局来包含ProgressBar视图,
不过现在已经可以通过setProgress()方法来简化流程了,所以接下来使用的是后者。
下面提供一个简单的初步案例...
public void sendNotification3(View v){
Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("进度条通知");
builder.setContentText("进度条Loading");
//三个参数 进度条最大值,进度条当前值,是否是不确定的
builder.setProgress(100,5,false);
NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_3,builder.build());
}
效果如下,一个最简单的带进度条的通知就完成了
下面我们进一步完善它
之前的Listview学习中,传送门:
用到了“线程”的概念,这次也要使用它,由于都是已经学习过的内容,所以下面直接放代码,已经添加必要的注释
包含了前面部分的代码,关于这部分 直接看
public void sendNotification3(View v)部分即可
package com.example.a3_22notification;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
//id
private static final int NID_1 = 0x1;
private static final int NID_2 = 0x2;
private static final int NID_3 = 0x3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//普通的通知
public void sendNotification1(View view) {
Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
//设置图标
builder.setSmallIcon(R.mipmap.ic_launcher);
//设置通知标题
builder.setContentTitle("这是标题");
//设置通知内容
builder.setContentText("这是通知正文!");
Intent intent = new Intent(this, Test.class);
intent.putExtra("msg","这是由首页发送来的通知");
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//参数:上下文,请求编码,意图,创建PendingIntet的方式
/*
PendingIntent.FLAG_CANCEL_CURRENT:取消当前的PI,创建新的
PendingIntent.FLAG_NO_CREATE:如果有就用,没有不创建
PendingIntent.FLAG_ONE_SHOT:只使用一次
PendingIntent.FLAG_UPDATE_CURRENT:如果有,更新Intent,没有就创建
*/
builder.setContentIntent(pi);
//通知的事件
//创建一个通知对象
Notification n = builder.build();
//推送通知
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_1, n);
}
//宽视图
public void sendNotification2(View v){
Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("这是标题");
builder.setContentText("这是通知内容");
//宽视图样式设置
Notification.InboxStyle style=new Notification.InboxStyle();
style.setBigContentTitle("大视图标题");
style.addLine("第一行");
style.addLine("第二行");
style.addLine("第三行");
style.addLine("第四行");
builder.setStyle(style);
style.setSummaryText("设置概要文本");
//宽视图样式结束
Notification n=builder.build();
NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_2,n);
}
//进度条通知
public void sendNotification3(View v){
//被方法内部类访问的局部变量必须被final修饰
final Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("进度条通知");
builder.setContentText("进度条Loading");
//三个参数 进度条最大值,进度条当前值,是否是不确定的
builder.setProgress(100,5,false);
//被方法内部类访问的局部变量必须被final修饰
final NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_3,builder.build());
//模拟动态更新的线程
new Thread(new Runnable() {
@Override
public void run() {
//进度条每次增加5
for(int progress=0;progress<=100;progress+=5){
builder.setProgress(100,progress,false);
//重新推送,更新进度条
nm.notify(NID_3,builder.build());
try {
//延迟...
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//进度条满,重置
builder.setProgress(0,0,false);
builder.setContentText("进度已完成!!");
nm.notify(NID_3,builder.build());
}
}).start();
}
}
emm效果如上,应该放动图比较好,反正就是它是能每秒走百分之10的(每0.5秒走百分之5)
自定义视图通知
经常可以看到很多APP的通知“花里胡哨”的,每个APP都有自己特殊的进度条,这是通知提供的RemoteViews,翻译过来是远程的视图,可能不太好理解,实际上它表示
可以在其他进程中显示的视图。这个“其他进程”,在这里就指代系统进程,所以它可以实现自定义通知栏视图的
- 既然要自定义,所以我们首先创建一个单独的布局文件(XML)参考代码如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<ImageView
android:id="@+id/imageView"
android:layout_width="22dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@android:drawable/picture_frame" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center"
android:text="我的通知" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="按钮1" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="按钮2" />
</LinearLayout>
- 下面开始编写sendNotification4,直接放代码
public void sendNotification4(View v){
//被方法内部类访问的局部变量必须被final修饰
final Notification.Builder builder = new Notification.Builder(this);
//设置相关的属性
builder.setSmallIcon(R.mipmap.ic_launcher);
//常驻通知...
builder.setOngoing(true);
//创建一个远程的视图 my_notififation为你的自定义通知栏视图布局
RemoteViews views=new RemoteViews(getPackageName(),R.layout.my_notififation);
views.setTextViewText(R.id.textView,"被修改的文本");
//views.setImageViewResource();设置图片
//按钮的文字也是通过setTextView
views.setTextViewText(R.id.button,"修改按钮");
//views.setOnClickPendingIntent();设置单击按钮进度条事件
//views.setOnClickFillInIntent();设置单击进度条事件
builder.setContent(views);
NotificationManager nm= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_4,builder.build());
}
效果如下,可以看到虽然,布局中的button文本为按钮2,布局中的Textview文本为我的通知,但是通过setTextViewText确实将通知文本内容进行了修改,所以我们可以搭配被注释掉的点击事件,来实现诸多丰富有趣的效果,抛砖引玉,就不一一测试了。