Notification 通知栏
知识点
-
Notification
-
设置特殊 Activity PendingIntent
-
浮动通知
-
锁定屏幕通知
-
在锁定屏幕上控制媒体播放
-
PendingIntent
-
TaskStackBuilder
-
RemoteViews
下面的都是废话 不必看了 官网有中文文档 说的很清楚
直接贴代码
版本25 这个版本不需要兼容8.0
默认通知
/**
* 默认样式的通知栏
*
* @param context
* @param builder
* @return
*/
public NotificationCompat.Builder defaultNotify(Context context, NotificationCompat.Builder builder) {
builder.setContentTitle("梦里挑灯看剑")
.setContentText("江山如此多娇,引无数英雄竞折腰")
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))// 右侧显示大图标
.setSmallIcon(R.drawable.test_baseline_school_black_24)
.setWhen(System.currentTimeMillis())
.setShowWhen(true)//显示时间 默认true
.setDefaults(NotificationCompat.DEFAULT_ALL)//默认提示 铃声 震动
.setPriority(NotificationCompat.PRIORITY_MAX)//设置优先级 和默认提示 搭配使用 可实现 悬浮提示效果
.setContentIntent(getTaskStackPending())
//.setContentInfo("ContentInfo")
//.setNumber(5)
.setOngoing(true)//true不可以滑动删除 false 可以滑动删除
.setAutoCancel(true)
;
return builder;
}
进度条通知
/**
* 进度条通知栏
*
* @param builder
* @return
*/
public NotificationCompat.Builder progressNotify(final NotificationCompat.Builder builder) {
builder.setContentTitle("正在下载:")
.setAutoCancel(false)
.setOngoing(true)
.setShowWhen(false)//显示时间 默认true
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
.setOnlyAlertOnce(true)
.setSmallIcon(R.drawable.test_baseline_school_black_24);
new Thread() {
@Override
public void run() {
int progress = 0;
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
progress += 10;
builder.setProgress(100, progress, false);
builder.setContentTitle("正在下载:" + progress + "%");
builder.setContentInfo(progress + "%");
mNotifyManager.notify(500, builder.build());
}
builder.setContentTitle("下载完成:");
mNotifyManager.notify(500, builder.build());
//mNotifyManager.cancel(500);
}
}.start();
return builder;
}
bigTextStyle
public NotificationCompat.Builder bigTextStyleNotify(NotificationCompat.Builder builder) {
NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle();
bigTextStyle.bigText("Android4.1+之后出现几种折叠样式,均需要使用setStyle()方法设定 setStyle()传递一个NotificationCompat.Style对象,它是一个抽象类,Android为我们提供了三个实现类,用于显示不同的场景。Android4.1+之后出现几种折叠样式,均需要使用setStyle()方法设定 setStyle()传递一个NotificationCompat.Style对象,它是一个抽象类,Android为我们提供了三个实现类,用于显示不同的场景。Android4.1+之后出现几种折叠样式,均需要使用setStyle()方法设定 setStyle()传递一个NotificationCompat.Style对象,它是一个抽象类,Android为我们提供了三个实现类,用于显示不同的场景。");
bigTextStyle.setBigContentTitle("折叠式:BigText"); //替换掉了 setContentTitle
bigTextStyle.setSummaryText("摘要");
return builder
.setSmallIcon(R.drawable.test_baseline_school_black_24)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
.setContentTitle("折叠式:BigText")
.setContentText("对折叠样式的说明")
.setStyle(bigTextStyle)
.setWhen(System.currentTimeMillis())
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(getTaskStackPending())
// .setOngoing(true)//true不可以滑动删除 false 可以滑动删除 使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
.setAutoCancel(true);
}
inboxStyle
public NotificationCompat.Builder inboxStyleNotify(NotificationCompat.Builder builder) {
return builder
.setSmallIcon(R.drawable.test_baseline_school_black_24)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
.setContentTitle("折叠式:Inbox")
.setContentText("对折叠样式的说明")
.setStyle(new NotificationCompat.InboxStyle()
.addLine("第一行数据")
.addLine("第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据第二行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
.addLine("第一行数据")
)
.setWhen(System.currentTimeMillis())
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(getTaskStackPending())
//.setOngoing(true)//true不可以滑动删除 false 可以滑动删除 使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
.setAutoCancel(true);
}
bigPictureStyle
public NotificationCompat.Builder bigPictureStyleNotify(NotificationCompat.Builder builder) {
return builder
.setSmallIcon(R.drawable.test_baseline_school_black_24)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
.setContentTitle("折叠式:BigPicture")
.setContentText("对折叠样式的说明")
.setStyle(new NotificationCompat.BigPictureStyle()
.bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
)
.setWhen(System.currentTimeMillis())
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(getTaskStackPending())
// .setOngoing(true)//true不可以滑动删除 false 可以滑动删除 使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
.setAutoCancel(true);
}
自定义大图 setCustomBigContentView 可理解为可折叠
public NotificationCompat.Builder customBigNotify(NotificationCompat.Builder builder) {
RemoteViews views = new RemoteViews(getPackageName(), R.layout.test_custom_remote_view_dj);
views.setOnClickPendingIntent(R.id.test_iv_large_img, getPendingIntent("onClickLargeImage"));
views.setOnClickPendingIntent(R.id.test_iv_src_right, getPendingIntent("onClickRightImage"));
views.setOnClickPendingIntent(R.id.test_iv_src, getPendingIntent("onClickLeftImage"));
views.setOnClickPendingIntent(R.id.test_tv_title, getPendingIntent("onClickTextTitle"));
return builder
.setSmallIcon(R.drawable.test_baseline_school_black_24)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
.setContentTitle("自定义")
.setContentText("RemoteViews")
.setWhen(System.currentTimeMillis())
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(getTaskStackPending())
.setCustomBigContentView(views)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setOngoing(true)//true不可以滑动删除 false 可以滑动删除 使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
.setAutoCancel(true);
}
setCustomContentView 不可折叠
public NotificationCompat.Builder customNotify(NotificationCompat.Builder builder) {
RemoteViews views = new RemoteViews(getPackageName(), R.layout.test_custom_remote_view_dj);
/**
* 加入点击事件 setAutoCancel 无效
*/
// views.setOnClickPendingIntent(R.id.test_iv_large_img,getPendingIntent("onClickLargeImage"));
// views.setOnClickPendingIntent(R.id.test_iv_src_right,getPendingIntent("onClickRightImage"));
//
// views.setOnClickPendingIntent(R.id.test_iv_src,getPendingIntent("onClickLeftImage"));
// views.setOnClickPendingIntent(R.id.test_tv_title,getPendingIntent("onClickTextTitle"));
return builder
.setSmallIcon(R.drawable.test_baseline_school_black_24)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.test_baseline_school_black_24))
.setContentTitle("自定义")
.setContentText("RemoteViews")
.setWhen(System.currentTimeMillis())
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(getTaskStackPending())
.setCustomContentView(views)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)//锁屏通知
.setOngoing(true)//true不可以滑动删除 false 可以滑动删除 使用这个属性 通知栏默认展开状态 说的不是很明白 可以自己试一下
.setAutoCancel(true);
}
调用方式
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(context);
findViewById(R.id.app_test_btn_send_notify).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//showProgressNotify();
showNotify();
mNotifyManager.notify(id++, defaultNotify(context, mBuilder).build());
progressNotify(mBuilder);
mNotifyManager.notify(id++, bigTextStyleNotify(mBuilder).build());
mNotifyManager.notify(id++, inboxStyleNotify(mBuilder).build());
//mNotifyManager.notify(id++, bigPictureStyleNotify(mBuilder).build());
//mNotifyManager.notify(id++, customBigNotify(mBuilder).build());
mNotifyManager.notify(id++, customNotify(mBuilder).build());
}
}.start();
}
});
public PendingIntent getTaskStackPending() {
//创建 Intent 以启动 Activity。
Intent resultIntent = new Intent(this, TestReceiveActivity.class);
//创建堆栈生成器
TaskStackBuilder builder = TaskStackBuilder.create(this);
//将返回栈添加到堆栈生成器。 对于在清单文件中所定义层次结构内的每个 Activity,返回栈均包含可启动 Activity 的 Intent 对象。此方法还会添加一些可在全新任务中启动堆栈的标志。
builder.addParentStack(TestReceiveActivity.class);
builder.addNextIntent(resultIntent);//添加可从通知中启动 Activity 的 Intent。 将在第一步中创建的 Intent 作为 addNextIntent() 的参数传递
/**
* 如需,请通过调用 TaskStackBuilder.editIntentAt() 向堆栈中的 Intent 对象添加参数。有时,需要确保目标 Activity 在用户使用“返回”导航回它时会显示有意义的数据。
*/
//通过调用 getPendingIntent() 获得此返回栈的 PendingIntent。 然后,您可以使用此 PendingIntent 作为 setContentIntent() 的参数。
return builder.getPendingIntent(200, PendingIntent.FLAG_UPDATE_CURRENT);
}
public PendingIntent getPendingIntent(Context context, int requestCode, Intent intent) {
return PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent getPendingIntent(String action) {
Intent intent = new Intent(this, TestReceiveActivity.class);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, PendingIntent.FLAG_UPDATE_CURRENT);
/**
FLAG_ONE_SHOT 表示返回的PendingIntent仅能执行一次,执行完后自动取消
FLAG_NO_CREATE 表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULL
FLAG_CANCEL_CURRENT 表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntent, 这个有利于数据保持为最新的,可以用于即时通信的通信场景
FLAG_UPDATE_CURRENT 表示更新的PendingIntent
*/
return pendingIntent;
}
配置TaskStackBuilder
<application
android:allowBackup="true"
android:icon="@mipmap/test_ic_launcher"
android:label="@string/test_app_name"
android:roundIcon="@mipmap/test_ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/test_AppTheme">
<activity android:name=".TestPluginMainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".TestNotificationActivity" />
<activity
android:name=".TestReceiveActivity"
android:parentActivityName=".TestPluginMainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".TestPluginMainActivity" />
</activity>
</application>
WindowManager
简单实现
public class TestWindowService extends Service {
private static final String TAG = "TestWindowService";
private WindowManager.LayoutParams params;
private WindowManager windowManager;
private View view;
private int startX;
private int startY;
private int endX;
private int endY;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
createFloatView();
initWindow();
addWindowView2Window();
initClick();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
private void initWindow() {
windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams();
// 更多type:https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#TYPE_PHONE
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
params.format = PixelFormat.TRANSPARENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
// |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
// |WindowManager.LayoutParams.FLAG_FULLSCREEN
;
// 设置通知栏的长和宽
// params.width = windowManager.getDefaultDisplay().getWidth();
// params.height = 200;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = (int) (200 * getResources().getDisplayMetrics().density + 0.5);
params.gravity = Gravity.LEFT | Gravity.TOP;
}
private void createFloatView() {
view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.test_custom_remote_view_dj, null);
int height = view.getHeight();
}
private void addWindowView2Window() {
windowManager.addView(view, params);
}
private void initClick() {
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getRawX();
startY = (int) event.getRawY();
Log.d(TAG, "getRawX: " + startX + " getX() = " + event.getX());
Log.d(TAG, "getRawY: " + startY + " getY() = " + event.getY());
//getRawX是触摸位置相对于屏幕的坐标,getX是相对于父控件的坐标
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "onTouch: move");
endX = (int) event.getRawX();
endY = (int) event.getRawY();
params.x = (int) (event.getRawX() - view.getMeasuredWidth() / 2);
params.y = (int) (event.getRawY() - view.getMeasuredHeight() / 2);
windowManager.updateViewLayout(view, params);
return true;
case MotionEvent.ACTION_UP:
if (needIntercept()) {
return true;
}
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return false;
}
});
}
private boolean needIntercept() {
if (Math.abs(startX - endX) > 30 || Math.abs(startY - endY) > 30) {
return true;
}
return false;
}
@Override
public void onDestroy() {
super.onDestroy();
if (windowManager != null) {
windowManager.removeView(view);
}
view = null;
}
现在我们把版本改成8.0以上
//统一编译版本
ext {
buildToolsVersion = '28.0.3'
compileSdkVersion = 28
minSdkVersion = 16
targetSdkVersion = 28
versionCode = 1
versionName = "1.0"
//javaVersion = JavaVersion.VERSION_1_8
supportLibraryVersion = '28.0.0'
}
windowmManager 问题
Unable to create service com.component.fx.plugin_test.TestWindowService: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@7a19d70 -- permission denied for window type 2010
Unable to add window android.view.ViewRootImpl$W@7a19d70 -- permission denied for window type 2010
原因
使用SYSTEM_ALERT_WINDOW权限的应用程序无法再使用以下窗口类型在其他应用程序和系统窗口上方显示警报窗口:
TYPE_PHONE
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR
相反,应用必须使用名为TYPE_APPLICATION_OVERLAY的新窗口类型。
修改的代码
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
}
/**
* 创建一个Channel类型
*/
@TargetApi(Build.VERSION_CODES.O)
public static void createChannel() {
String channelName = "聊天消息";
int importance = NotificationManager.IMPORTANCE_MAX;
setChannel(CHAT_ChANNEL_ID, channelName, importance);
channelName = "新闻";
importance = NotificationManager.IMPORTANCE_DEFAULT;
setChannel(NEWS_ChANNEL_ID, channelName, importance);
}
/**
* 创建Channel类型
*
* @param id
* @param name
* @param importance
*/
@TargetApi(Build.VERSION_CODES.O)
private static void setChannel(String id, String name, int importance) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager nm = (NotificationManager) BaseApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (nm == null) {
return;
}
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setShowBadge(true);
nm.createNotificationChannel(channel);
}
}
/**
* 判断 是否关闭了通知
* <p>
* 是否允许通知
*
* @param context
* @return true 可用 false 不可用
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static boolean isNotifyEnable(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
///< 8.0手机以上
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Log.d("feng", "mNm: "+notificationManager);
if (notificationManager.getImportance() == NotificationManager.IMPORTANCE_NONE) {
return false;
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
AppOpsManager opsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo info = context.getApplicationInfo();
String packageName = context.getPackageName();
int uid = info.uid;
try {
Class<?> appOpsClass = Class.forName(AppOpsManager.class.getName());
Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);
Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
int value = (Integer) opPostNotificationValue.get(Integer.class);
return ((Integer) checkOpNoThrowMethod.invoke(opsManager, value, uid, packageName) == AppOpsManager.MODE_ALLOWED);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return true;
}
/**
* 判断channel是否可用
*
* @param channelId
* @return true 可用 false 不可用
*/
public static boolean isChannelEnable(String channelId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager nm = (NotificationManager) BaseApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = nm.getNotificationChannel(channelId);
return !(channel.getImportance() == NotificationManager.IMPORTANCE_NONE);
}
return true;
}
/**
* 如果用户关闭了Channel通道可以根据这个方法跳转到设置页面
*
* @param channelId
*/
@TargetApi(Build.VERSION_CODES.O)
public static void openNotifyChannel(String channelId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager nm = (NotificationManager) BaseApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
Log.d("feng", "mNm: openNotifyChannel "+nm);
NotificationChannel channel = nm.getNotificationChannel(channelId);
if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BaseApplication.getAppContext().getPackageName());
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.getId());
BaseApplication.getAppContext().startActivity(intent);
}
}
}
defaultNotify8.0适配
image.png元素:
-
标题 Title/Name
-
大图标 Icon/Photo
-
内容文字
-
内容信息 MESSAGE
-
小图标 Secondary Icon
-
通知的时间 Timestamp,默认为系统发出通知的时间,也可通过setWhen()来设置
自定义通知布局的可用高度取决于通知视图。普通视图布局限制为 64 dp,扩展视图布局限制为 256 dp。
Notification
通知是您可以在应用的常规 UI 外部向用户显示的消息。当您告知系统发出通知时,它将先以图标的形式显示在通知区域中。用户可以打开抽屉式通知栏查看通知的详细信息。 通知区域和抽屉式通知栏均是由系统控制的区域,用户可以随时查看。
一个最简单的通知栏。
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentText("今天中午吃什么?")
.setSmallIcon(R.drawable.test_ic_launcher_background)
.setContentTitle("我是标题");
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(100, builder.build());
这几行代码就可以显示出一个通知栏。
必需设置的通知内容
- setContentText 内容
- setSmallIcon 图标
- setContentTitle 标题
少一个都报错。
setContentIntent
现在我们加入意图:
.setContentIntent(getPendingIntent())//设置意图
获取一个PendiingIntent
包含着点击之后的行为
private PendingIntent getPendingIntent() {
Intent intent = new Intent(this, TestPluginMainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, 0);
return pendingIntent;
}
其实Pendding就是Intent的包装,下面会说,我们的行为定义了打开一个Activity。
现在点击发送按钮,会发送一条通知,通知栏显示出我们发送的通知
findViewById(R.id.app_test_btn_send_notify).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showNotify();
}
});
点击通知,触发定义的行为,跳转到TestPluginMainActivity类中。
请注意,现在没有对通知的消失做任何处理,所点点击通知,通知栏不会消失。
官方网站是这样获取pendingIntent
的
public PendingIntent getTaskStackPending(String action) {
Intent resultIntent = new Intent(this, TestPluginMainActivity.class);
TaskStackBuilder builder = TaskStackBuilder.create(this);
builder.addParentStack(TestPluginMainActivity.class);
builder.addNextIntent(resultIntent);
return builder.getPendingIntent(200, PendingIntent.FLAG_UPDATE_CURRENT);
}
行为是一样的,有个知识点TaskStackBuilder
一会在说,先留意下。
只有一条通知?
在内容上在加入时间,点击发送 在发送一条, 会发现只是内容做了替换,但是还是只有一条消息。
这样可不行,做成这样,需求会打死我的。
其实很好解决,在发送通知的时候有个参数id
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(100, builder.build());
我这里写死了 是100,所以才会只有一条消息。
修改之后
notificationManager.notify(id++, builder.build());
效果
image.png image.png发送的内容过多时,会自动折叠,展开后,显示每条数据。
setDeleteIntent
当通知被删除时触发。
.setDeleteIntent(getPendingIntent("onDelete"))//设置删除意图
可以在通知被删除时做一些行为。
稍微修改下getPendingIntent()
.setContentIntent(getPendingIntent("onClick"))//设置意图
.setDeleteIntent(getPendingIntent("onDelete"))//设置删除意图
发送时加入一个action,在接受端 打印这个action。
private PendingIntent getPendingIntent(String action) {
Intent intent = new Intent(this, TestPluginMainActivity.class);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, 0);
return pendingIntent;
}
可以发现 点击通知栏时,在TestPluginMainActivity类,toast弹出onClick ,删除通知时,弹出onDelete。
.setPriority() //设置优先级
- Notification.PRIORITY_MAX
重要而紧急的通知,通知用户这个事件是时间上紧迫的或者需要立即处理的。
-
Notification.PRIORITY_HIGH
高优先级用于重要的通信内容,例如短消息或者聊天,这些都是对用户来说比较有兴趣的
-
Notification.PRIORITY_DEFAULT
默认优先级用于没有特殊优先级分类的通知
-
Notification.PRIORITY_LOW
低优先级可以通知用户但又不是很紧急的事件。只显示状态栏图标
-
Notification.PRIORITY_MIN
用于后台消息 (例如天气或者位置信息)。只有用户下拉通知抽屉才能看到内容
其它flag
提醒标志符成员:
Notification.FLAG_SHOW_LIGHTS
//三色灯提醒,在使用三色灯提醒时候必须加该标志符
-
Notification.FLAG_ONGOING_EVENT
//发起正在运行事件(活动中) -
Notification.FLAG_INSISTENT
//让声音、振动无限循环,直到用户响应 (取消或者打开) -
Notification.FLAG_ONLY_ALERT_ONCE
//发起Notification后,铃声和震动均只执行一次 -
Notification.FLAG_AUTO_CANCEL
//用户单击通知后自动消失 -
Notification.FLAG_NO_CLEAR
//只有全部清除时,Notification才会清除 ,不清楚该通知(QQ的通知无法清除,就是用的这个) -
Notification.FLAG_FOREGROUND_SERVICE
//表示正在运行的服务
setDefaults 需要的flags
-
Notification.DEFAULT_VIBRATE
//添加默认震动提醒 需要 VIBRATE permission -
Notification.DEFAULT_SOUND
// 添加默认声音提醒 -
Notification.DEFAULT_LIGHTS
// 添加默认三色灯提醒 -
Notification.DEFAULT_ALL
// 添加默认以上3种全部提醒
震动
-
setDefaults(Notification.DEFAULT_ALL)
//向通知添加声音、闪灯和振动效果的最简单、 使用默认(defaults)属性,可以组合多个属性,Notification.DEFAULT_VIBRATE(添加默认震动提醒); Notification.DEFAULT_SOUND(添加默认声音提醒); Notification.DEFAULT_LIGHTS(添加默认三色灯提醒) Notification.DEFAULT_ALL(添加默认以上3种全部提醒)
-
setVibrate(new long[]{0, 300, 500, 700,500,1000,500,1000})
设置自定义震动 延迟0ms,然后振动300ms,在延迟500ms, 接着再振动700ms,
setDefaults 和 setVibrate 如果都设置 setDefaults生效,setVibrate不生效。
铃声
-
setSound(Uri.parse("file:///sdcard/a.mp3"))
加载本地音乐 -
setSound((Uri.withAppendedPath(internalContentUri, "5")))
//设置接收到通知时的铃声,可以用系统的,也可以自己设置 获取Android多媒体库内的铃声
三色灯
- setLights(0xffff0000,1000,0)
//设置三色灯,参数依次是:灯光颜色, 亮持续时间,暗的时间,不是所有颜色都可以,这跟设备有关,有些手机还不带三色灯; 另外,还需要为Notification设置flags为Notification.FLAG_SHOW_LIGHTS才支持三色灯提醒!
setOngoing(boolean ongoing)
设置为ture,表示它为一个正在进行的通知。他们通常是用来表示 一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载, 同步操作,主动网络连接)
setProgress()
max:进度条最大数值 、progress:当前进度、indeterminate:表示进度是否不确定,true为不确定,如下所示 ,false为确定 如下所示
image.png image.png功能:设置带进度条的通知,可以在下载中使用
public void showProgressNotify() {
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.test_ic_launcher_background);
// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
@SuppressLint("LongLogTag")
@Override
public void run() {
int incr;
// Do the "lengthy" operation 20 times
for (incr = 0; incr <= 100; incr += 5) {
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder.setProgress(100, incr, true);
// Displays the progress bar for the first time.
mNotifyManager.notify(0, mBuilder.build());
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
Log.d(TAG, "sleep failure");
}
}
// When the loop is finished, updates the notification
mBuilder.setContentText("Download complete")
// Removes the progress bar
.setProgress(0, 0, false);
mNotifyManager.notify(id++, mBuilder.build());
}
}
// Starts the thread by calling the run() method in its Runnable
).start();
}
setTicker
在 api 21 后不再显示,仅用于辅助服务。
builder.setTicker("this is ticker");
PendingIntent
PendingIntent 是一种特殊的 Intent ,字面意思可以解释为延迟的 Intent ,用于在某个事件结束后执行特定的 Action
PendingIntent 是 Android 系统管理并持有的用于描述和获取原始数据的对象的标志(引用)。也就是说,即便创建该PendingIntent对象的进程被杀死了,这个PendingItent对象在其他进程中还是可用的。 日常使用中的短信、闹钟等都用到了 PendingIntent。
//获取一个用于启动 Activity 的 PendingIntent 对象
public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags);
//获取一个用于启动 Service 的 PendingIntent 对象
public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags);
//获取一个用于向 BroadcastReceiver 广播的 PendingIntent 对象
public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags)
Intent intent = new Intent(this, TestReceiveActivity.class);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 200, intent, FLAG_CANCEL_CURRENT);
-
FLAG_ONE_SHOT
表示返回的PendingIntent仅能执行一次,执行完后自动取消 -
FLAG_NO_CREATE
表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULL -
FLAG_CANCEL_CURRENT
表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntent, 这个有利于数据保持为最新的,可以用于即时通信的通信场景 -
FLAG_UPDATE_CURRENT
表示更新的PendingIntent
Intent和PendingIntent的区别
-
Intent是立即使用的,而PendingIntent可以等到事件发生后触发,PendingIntent可以cancel
-
Intent在程序结束后即终止,而PendingIntent在程序结束后依然有效
-
PendingIntent自带Context,而Intent需要在某个Context内运行
-
Intent在原task中运行,PendingIntent在新的task中运行
TaskStackBuilder
有三个界面 A主界面,B发送通知栏界面,C 通知栏跳转界面。
现在 我需要 进入A界面,在跳转B界面,发送一个通知栏,点击通知栏进入C界面,注意 现在我们在C界面,如果点击返回按钮,如何返回到A界面?
设置特殊 Activity PendingIntent
浮动通知
实现的方法有两种:
- 通知拥有高优先级而且使用了铃声和震动。
- setFullScreenIntent(),如以下例子:
锁定屏幕通知
RemoteViews
image.png image.pngNotification的自定义布局是RemoteViews,和其他RemoteViews一样,在自定义视图布局文件中,仅支持FrameLayout、LinearLayout、RelativeLayout三种布局控件和AnalogClock、Chronometer、Button、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView和AdapterViewFlipper这些显示控件,不支持这些类的子类或Android提供的其他控件。否则会引起ClassNotFoundException异常