码迷,mamicode.com
首页 > 移动开发 > 详细

android 特殊用户通知用法汇总

时间:2016-04-12 17:20:43      阅读:351      评论:0      收藏:0      [点我收藏+]

标签:

  一直用的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

android 特殊用户通知用法汇总

标签:

原文地址:http://blog.csdn.net/self_study/article/details/51055769

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!