android 特殊用户通知用法汇总

  一直用的android手机,用过这么多的app,平时也会遇到有趣的通知提醒,在这里先总结两种吧,notification和图标数字,有的以后看到再研究。还有,推广一下哈,刚刚建立一个Q群544645972,有兴趣的加一下,一起成长。

Notification

  Notification应该算是最常见的app通知方式了,网上资料也很多,各种使用方法官方文档也已经写的非常详细了:http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html。这里就介绍一下几种特殊的用法:

动态改变

  将一个notification的setOngoing属性设置为true之后,notification就能够一直停留在系统的通知栏直到cancel或者应用退出。所以有的时候需要实时去根据情景动态改变notification,这里以一个定时器的功能为例,需要每隔1s去更新一下notification,具体效果:

  

非常简单的功能,代码也很简单:

private Timer timer;
private TimerTask task;
...
if (timer != null)
    return;
timer = new Timer("time");
task = new TimerTask() {
    @Override
    public void run() {
        showDynamicNotification();
    }
};
timer.scheduleAtFixedRate(task, 0, 1000);

private void showDynamicNotification() {
    L.i("show dynamic notification");
    mBuilder = new NotificationCompat.Builder(NotificationActivity.this);
    RemoteViews view = new RemoteViews(getPackageName(), R.layout.layout_notification);
    view.setTextViewText(R.id.tv_number, parseDate());
    view.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher);

    Intent intent = new Intent(NOTIFY_ACTION);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(NotificationActivity.this,
            1000, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    mBuilder.setSmallIcon(R.mipmap.ic_launcher)
            .setContentIntent(pendingIntent)
            .setTicker("you got a new message")
            .setOngoing(true)
            .setContent(view);
    notification = mBuilder.build();
    notificationManager.notify(NOTIFY_ID2, notification);
}

private String parseDate() {
    SimpleDateFormat format = new SimpleDateFormat("yyyy hh:mm:ss", Locale.getDefault());
    return format.format(System.currentTimeMillis());
}

  需要注意的是Notification.Builder 是 Android 3.0 (API 11) 引入的,为了兼容低版本,我们一般使用 Support V4 包提供的 NotificationCompat.Builder 来构建 Notification。要想动态更新notification,需要利用 NotificationManager.notify() 的 id 参数,该 id 在应用内需要唯一(如果不唯一,在有些4.x的手机上会出现pendingIntent无法响应的问题,在红米手机上出现过类似情况),要想更新特定 id 的通知,只需要创建新的 notification,并触发与之前所用 id 相同的 notification,如果之前的通知仍然可见,则系统会根据新notification 对象的内容更新该通知,相反,如果之前的通知已被清除,系统则会创建一个新通知。

  在这个例子中使用的是完全自定义的remoteViews,remoteViews和普通view的更新机制不一样,网上资料很多,感兴趣的可以去仔细了解。还有一个就是PendingIntent,这就不详细介绍了,这里简单列一下PendingIntent的4个flag的作用

  • FLAG_CANCEL_CURRENT:如果构建的PendingIntent已经存在,则取消前一个,重新构建一个。
  • FLAG_NO_CREATE:如果前一个PendingIntent已经不存在了,将不再构建它。
  • FLAG_ONE_SHOT:表明这里构建的PendingIntent只能使用一次。
  • FLAG_UPDATE_CURRENT:如果构建的PendingIntent已经存在,则替换它,常用。

big view

  Notification有两种视觉风格,一种是标准视图(Normal view)、一种是大视图(Big view)。标准视图在Android中各版本是通用的,但是对于大视图而言,仅支持Android4.1+的版本,比如邮件,音乐等软件就会使用到这种大视图样式的扩展通知栏,系统提供了setStyle()函数用来设置大视图模式,一般情况下有三种模式提供选择:

  1. NotificationCompat.BigPictureStyle, 在细节部分显示一个256dp高度的位图
  2. NotificationCompat.BigTextStyle,在细节部分显示一个大的文本块。
  3. NotificationCompat.InboxStyle,在细节部分显示一段行文本。
  4.   

在21版本之后增加了一个Notification.MediaStyle,这个可以达到类似

  

的效果,基本和一些主流媒体播放器的界面类似了,在这就不具体介绍了,提供一篇资料:controllingMedia

  如果不使用上面的几种style,完全自定义布局也是可以的,例如实现:

  

相关源码:Android custom notification for music player Example

  在这我就以一个简单的实现为例,效果如下:

  

代码:

RemoteViews smallView = new RemoteViews(getPackageName(), R.layout.layout_notification);
smallView.setTextViewText(R.id.tv_number, parseDate());
smallView.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher);

mBuilder = new NotificationCompat.Builder(NotificationActivity.this);
mBuilder.setSmallIcon(R.mipmap.ic_launcher)
        .setNumber((int) (Math.random() * 1000))
        //No longer displayed in the status bar as of API 21.
        .setTicker("you got a new message")
        .setDefaults(Notification.DEFAULT_SOUND
                | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)
//        .setDeleteIntent()
        .setAutoCancel(true)
        .setWhen(0)
        .setPriority(NotificationCompat.PRIORITY_LOW);

intent = new Intent(NOTIFY_ACTION);
pendingIntent = PendingIntent.getBroadcast(NotificationActivity.this,
        1000, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);

//在5.0版本之后,可以支持在锁屏界面显示notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
    mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
}
notification = mBuilder.build();
notification.contentView = smallView;

//如果系统版本 >= Android 4.1,设置大视图 RemoteViews
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    RemoteViews view = new RemoteViews(getPackageName(), R.layout.layout_big_notification);
    view.setTextViewText(R.id.tv_name, "我是名字1我是名字2我是名字3我是名字4我是名字5我是名字6我是名字7我是名字");
    view.setOnClickPendingIntent(R.id.btn_click_close,
            PendingIntent.getBroadcast(NotificationActivity.this, 1001,
                    new Intent(CLICK_ACTION), PendingIntent.FLAG_UPDATE_CURRENT));
    //textview marquee property is useless for bigContentView
    notification.bigContentView = view;
}

notificationManager.notify(NOTIFY_ID3, notification);

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:background="#ef222222">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="150dp">

        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@mipmap/ic_launcher"
            android:layout_gravity="center_vertical"/>

        <LinearLayout
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView android:id="@+id/tv_name"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:ellipsize="marquee"
                android:fadingEdge="horizontal"
                android:layout_gravity="center"
                android:gravity="center_horizontal|center_vertical"
                android:marqueeRepeatLimit="marquee_forever"
                android:scrollHorizontally="false"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:singleLine="true"
                android:textSize="15sp"
                android:textStyle="bold"
                android:textColor="#fff">
            <requestFocus/>
            </TextView>

            <Button
                android:id="@+id/btn_click_close"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginTop="10dp"
                android:layout_gravity="center_horizontal"
                android:textSize="30sp"
                android:background="#ef222222"
                android:text="X"/>

        </LinearLayout>
    </FrameLayout>

</LinearLayout>

  这里有几点需要着重说明一下

  1. setTicker函数在21版本之后已经Deprecated了,没有效果。
  2. 监听notification删除函数setDeleteIntent是在11版本后新增的,而且setAutoCancel为true后,该函数会失效。
  3. setPriority函数用来给notification设置优先级,上面给的google文档中有很详细的介绍。
  4. 21版本之后,可以支持在锁屏界面显示notification,这个在google文档中也有介绍,这个体验对于我个人来说感触很深,对于短信等私密性通知可以隐藏,但是对于一般毫无隐私的应用通知,就可以设置其为public,省去用户解锁,下拉通知栏的操作。
  5. 自定义大图模式也是将自定义的RemoteViews赋值给notification.bigContentView变量,而且这个功能也只是在api16(4.1)之后生效。
  6. 大图模式高度的设置有些奇怪,在上面的xml文件中,LinearLayout设置高度是无效的,必须要套一层FrameLayout,设置FrameLayout的高度才行,貌似定义最外层的LinearLayout的layoutParams是无效的。
  7. 在bigContentView中是无法实现textview的marquee效果,而且事实也很奇怪,单独使用contentView,传入的remoteViews中的textview的marquee属性是好用的,但是一旦设置了bigContentView,contentView中的textview属性也失效了,这点使用的时候要注意。

浮动通知

  这种效果大家应该在微信中看的很多,其实实现也很简单:

  

代码:

RemoteViews headsUpView = new RemoteViews(getPackageName(), R.layout.layout_heads_up_notification);

intent = new Intent(NOTIFY_ACTION);
pendingIntent = PendingIntent.getBroadcast(NotificationActivity.this,
        1000, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder = new NotificationCompat.Builder(NotificationActivity.this);
mBuilder.setSmallIcon(R.mipmap.ic_launcher)
        .setContentTitle("this is notification title test")
        .setContentText("this is notification text test")
        .setNumber((int) (Math.random() * 1000))
        .setTicker("you got a new message")
        //must set pendingintent for this notification, or will be crash
        .setContentIntent(pendingIntent)
        .setDefaults(Notification.DEFAULT_SOUND
                | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)
        .setAutoCancel(true)
        .setWhen(0);
notification = mBuilder.build();
if (Build.VERSION.SDK_INT >= 21) {
    notification.priority = Notification.PRIORITY_MAX;
    notification.headsUpContentView = headsUpView;
}
notificationManager.notify(NOTIFY_ID1, notification);

  这个效果非常的方便,用户都不需要直接下拉出通知栏,直接就能够看见,省去了多余操作,google官方文档介绍:http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html#Heads-up。headsUpContentView属性也只是在21版本时出现,使用的时候需要注意。

notification常见问题总结

  1.通过notification打开activity的时候,就要涉及到保存用户导航的问题,这个时候就要使用到activity task的相关内容了,我以前写过一篇博客中有介绍到activity task的内容:android深入解析Activity的launchMode启动模式,Intent Flag,taskAffinity,感兴趣的可以去看看。那么要实现点击notification打开指定activity,就需要设置相关的pendingIntent,有两种特殊的情况需要说明一下:  

  • 第一种是需要打开该activity的整个task栈,也就是说父activity也需要同时全部打开,而且按照次序排列在task栈中。
  • 但是这里会有一个问题,它在打开整个activity栈之前会先清空原先的activity task栈,所以最后在task栈中只剩下相关的几个activity,举个例子我要打开A->B->C的activity栈,但是我原先的activity栈中有D和C这两个activity,系统会直接按顺序关闭D和C这两个activity,接着按顺序打开A->B->C,这种情况在使用的时候需要注意。

  • 第二种是直接打开一个activity在一个单独的task栈中
  • 这种情况会生成两个task栈,

这两种情况在google官方文档中已经详细介绍了:http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html#NotificationResponse

  2.我在以前的博客中曾经介绍过一个notification图标变成白块的问题:android5.0状态栏图标变成白色,这个问题在国产的很多rom中自己解决了,例如小米,锤子等,但是例如HTC和三星等rom仍然是有这样的问题,要重视起来啊 

  3.在2.3的时候直接使用

RemoteViews rvMain = new RemoteViews(context.getPackageName(), R.layout.notification_layout);
//TODO rvMain...
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                .setContent(rvMain);
// TOOD ...

是无效的,需要换一种方式:

RemoteViews rvMain = new RemoteViews(context.getPackageName(), R.layout.notification_layout);
//TODO rmMain...
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                .setContent(rvMain);
// TOOD ...
Notification notification = builder.build();
if(Build.VERSION.SDK_INT <= 10){
    notification.contentView = rvMain;
}

4.通知栏上的操作事件:

  • setContentIntent():用户点击通知时触发
  • setFullScreenIntent()://TODO 这个在通知显示的时候会被调用
  • setDeleteIntent():用户清除通知时触发,可以是点击清除按钮,也可以是左右滑动删除(当然了,前提是高版本)

2.3及以下是无法处理自定义布局中的操作事件的,这样我们就不要去考虑增加自定义按钮了。

相关资料

http://www.tutorialsface.com/2015/08/android-custom-notification-tutorial/

http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html#Heads-up

http://glgjing.github.io/blog/2015/11/18/android-kai-fa-zhi-notification-xiang-jie/

http://www.codeceo.com/article/android-notification-4-types.html

http://www.itnose.net/detail/6169442.html

http://www.cnblogs.com/over140/p/4249503.html

http://blog.csdn.net/loongggdroid/article/details/17616509/

http://www.2cto.com/kf/201408/327782.html

http://blog.csdn.net/xxbs2003/article/details/19167331

http://www.jianshu.com/p/4d76b2bc8784

http://home.bdqn.cn/thread-42153-1-1.html

图标数字

  

  虽然说这是iOS上的风格,但是在某些手机上还是支持的,比如三星和HTC(m8t,6.0)的有些手机都可以,小米手机是个特例,它是根据notification的数量来自动生成的。

  一般情况下,HTC和三星可以使用下面的函数生成

public static void setBadge(Context context, int count) {
    String launcherClassName = getLauncherClassName(context);
    if (launcherClassName == null) {
        return;
    }
    Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
    intent.putExtra("badge_count", count);
    intent.putExtra("badge_count_package_name", context.getPackageName());
    intent.putExtra("badge_count_class_name", launcherClassName);
    context.sendBroadcast(intent);
}

public static String getLauncherClassName(Context context) {

    PackageManager pm = context.getPackageManager();

    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);

    List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
    for (ResolveInfo resolveInfo : resolveInfos) {
        String pkgName = resolveInfo.activityInfo.applicationInfo.packageName;
        if (pkgName.equalsIgnoreCase(context.getPackageName())) {
            String className = resolveInfo.activityInfo.name;
            return className;
        }
    }
    return null;
}

  由于android碎片化太严重,所以在不同手机上适配起来是非常麻烦,不过还好在github上国人写了一个库可以覆盖挺多机型:ShortcutBadger,也可以参考一下:http://stackoverflow.com/questions/17565307/how-to-display-count-of-notifications-in-app-launcher-icon

源码

https://github.com/zhaozepeng/notification

时间: 2024-12-10 05:06:02

android 特殊用户通知用法汇总的相关文章

【Android】Android背景选择器selector用法汇总

一.创建xml文件,位置:drawable/xxx.xml,同目录下记得要放相关图片 <?xml version="1.0" encoding="utf-8" ?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 默认时的背景图片--> <item android:drawable="@draw

android背景选择器selector用法汇总

一.创建xml文件,位置:drawable/xxx.xml,同目录下记得要放相关图片 <?xml version="1.0" encoding="utf-8" ?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 默认时的背景图片--> <item android:drawable="@draw

Android UI相关开源项目库汇总

最近做了一个Android UI相关开源项目库汇总,里面集合了OpenDigg 上的优质的Android开源项目库,方便移动开发人员便捷的找到自己需要的项目工具等,感兴趣的可以到GitHub上给个star. 抽屉菜单 MaterialDrawer ★7337 - 安卓抽屉效果实现方案 Side-Menu.Android ★3865 - 创意边侧菜单 FlowingDrawer ★1744 - 向右滑动流动抽屉效果 SlidingRootNav ★1338 - 仿DrawerLayout的View

Android Wear - 归档通知(Stacking Notifications)

原文地址:http://developer.android.com/wear/notifications/stacks.html 前言 当在手持设备上创建通知的时候,你应该经常将一些类似的通知归并到一个单一的摘要通知中.比如,如果你的应用接收到信息后会创建通知,你不应该在手持设备上创建多条通知.当接收到多条信息的时候,你应该使用一条单一的通知并显示类似"2 new messages"这样的摘要信息. 但是,一个摘要通知在Android Wear设备上就显得没那么有用,因为用户不能够在穿

【Android】状态栏通知Notification、NotificationManager详解(转)

在Android系统中,发一个状态栏通知还是很方便的.下面我们就来看一下,怎么发送状态栏通知,状态栏通知又有哪些参数可以设置? 首先,发送一个状态栏通知必须用到两个类:  NotificationManager . Notification. NotificationManager :  是状态栏通知的管理类,负责发通知.清楚通知等. NotificationManager 是一个系统Service,必须通过 getSystemService()方法来获取. [java] view plainc

android之Notification通知

android之Notification通知 我们在用手机的时候,如果来了短信,而我们没有点击查看的话,是不是在手机的最上边的状态栏里有一个短信的小图标提示啊?你是不是也想实现这种功能呢?今天的Notification就是解决这个问题的. [java] view plaincopy package cn.com.chenzheng_java; import android.app.Activity; import android.app.Notification; import android.

Android listview与adapter用法

listview与adapter用法 博客分类: android 一个ListView通常有两个职责. (1)将数据填充到布局. (2)处理用户的选择点击等操作. 第一点很好理解,ListView就是实现这个功能的.第二点也不难做到,在后面的学习中读者会发现,这非常简单. 一个ListView的创建需要3个元素. (1)ListView中的每一列的View. (2)填入View的数据或者图片等. (3)连接数据与ListView的适配器. 也就是说,要使用ListView,首先要了解什么是适配器

C#中DllImport用法汇总

(转) 最近使用DllImport,从网上google后发现,大部分内容都是相同,又从MSDN中搜集下,现将内容汇总,与大家分享. 大家在实际工作学习C#的时候,可能会问:为什么我们要为一些已经存在的功能(比如Windows中的一些功能,C++中已经编写好的一些方法)要重新编写代码,C#有没有方法可以直接都用这些原本已经存在的功能呢?答案是肯定的,大家可以通过C#中的DllImport直接调用这些功能. DllImport是System.Runtime.InteropServices命名空间下的

Android 实现用户列表信息滑动删除功能和选择删除功能

在项目开发过程中,常常需要对用户列表的信息进行删除的操作.Android中常用的删除操作方式有两种 ,一种就是类似微信的滑动出现删除按钮方式,还有一种是通过CheckBox进行选择,然后通过按钮进行删除的方式.本来的实例集成上述的两种操作方式来实现用户列表删除的效果. 设计思路:在适配器类MyAdapter一个滑动删除按钮显示或隐藏的Map,一个用于CheckBox是否选中的Map和一个与MainAcitivyt进行数据交互的接口ContentsDeleteListener,同时该接口包含两个方