精华内容
下载资源
问答
  • 实现Notification的通知栏常驻.zip,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 通知栏常驻 通知栏常在 锁屏黑屏界面手势绘图打开手电筒 === 不同手机,方法类似。 手机设置选项中有一项手势控制自己打开设置下就好了 进入手机"设置"界面后,找到"手势体感"点击进入 进入"手势体感"设置...

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha

    通知栏添加手电筒

    通知栏常驻

    通知栏常在

    锁屏黑屏界面手势绘图打开手电筒

    ===

    不同手机,方法类似。

    手机设置选项中有一项手势控制自己打开设置下就好了

     

    进入手机"设置"界面后,找到"手势体感"点击进入

    进入"手势体感"设置界面后,点击"黑屏手势"按钮

     

    黑屏解锁

    ======

     

    转载于:https://www.cnblogs.com/yue31313/p/7401668.html

    展开全文
  • 常驻Notification的通知栏的实例
  • Notification最新用法、实现Notification的通知栏常驻、Notification的各种样式big View、解决Notification点击无效
  • 另外类似于墨迹天气,清理大师等 app,也会将通知栏常驻,利用自定义的布局,方便用户及时快捷的查看所需的信息和使用快捷的功能。所以Notification的使用,也在开发当中, 使用的越来越频繁。今天我就来跟大

    Android的Notification是android系统中很重要的一个机制, 产品人员常常利用通知栏的方式,跟用户进行弱沟通。拥有推送通知的app要比没有此类功能的app活跃率要高很多。另外类似于墨迹天气,清理大师等 app,也会将通知栏常驻,利用自定义的布局,方便用户及时快捷的查看所需的信息和使用快捷的功能。所以Notification的使用,也在开发当中, 使用的越来越频繁。今天我就来跟大家分享一下Notification的常用事项。

    我不了解大家平时怎么使用Notification,我常常看到有些人的代码是这样写的:

    1. Notification notification=new Notification(notificationIcon, notificationTitle, when);    
    2.             
    3.         notification.defaults=Notification.DEFAULT_ALL;    
    4.             
    5.         Intent intent=new Intent(MainActivity.this,SecondActivity.class);    
    6.         PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this, 0, intent, 0);    
    7.         notification.setLatestEventInfo(this,"测试展开title", "测试展开内容",pendingIntent);   
    8. 。。。。。。。。。。。。。  


    具体的代码我就不贴全了,因为大家如果注意IDE的提示的话,就会发现,其实这是一种不推荐 的用法,API的支持已经过时了。最新的Notification的用法,是推荐使用V4包下的NotificationCompat.Builder, 利用它,进行各种设置,具体的用法先别着急,我们慢慢道来。

    1. NotificationCompat.Builder notifyBuilder = new NotificationCompat.Builder(  
    2.         this);  

    首先,我们需要先初始化一个notifyBuilder,然后利用它的各种set方法,进行相关设置,具体的设置,我们参考下图:

    技术分享

    图示中的序号1,叫做

    1. notifyBuilder.setContentTitle("This is My Notification");  

    图示中的序号3,叫做

    1. notifyBuilder.setContentText("Hello World");  

    图示中的需要5,叫做利用下面的方法来设置:

    这三个参数的设定是必须的,每次调用Notification,必须得设定这三个参数。除去这三个以外,另外的2,4,6区域,分别是Large Icon,Content Info,Time,设置方法如下所示:

    • Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bigicon);  
    • notifyBuilder.setLargeIcon(bitmap);  
    • // 这里用来显示右下角的数字  
    • notifyBuilder.setNumber(10);  
    • notifyBuilder.setWhen(System.currentTimeMillis());  

    以上就是关于Notification的基本设置,下面,我们继续看看其它方面的设置,直接上代码:

     

    1. // 将AutoCancel设为true后,当你点击通知栏的notification后,它会自动被取消消失  
    2.         notifyBuilder.setAutoCancel(true);  
    3.         // 将Ongoing设为true 那么notification将不能滑动删除  
    4.         // notifyBuilder.setOngoing(true);  
    5.         // 从Android4.1开始,可以通过以下方法,设置notification的优先级,优先级越高的,通知排的越靠前,优先级低的,不会在手机最顶部的状态栏显示图标  
    6.         notifyBuilder.setPriority(NotificationCompat.PRIORITY_MAX);  
    7.         // notifyBuilder.setPriority(NotificationCompat.PRIORITY_MIN);  
    8.   
    9.         notifyBuilder.setTicker("Hi,Notification is here");  
    10.           
    11.         // Uri uri =  
    12.         // Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.cat);  
    13.         // Uri uri = Uri.parse("file:///mnt/sdcard/cat.mp3");  
    14.         // notifyBuilder.setSound(uri);  
    15.   
    16.         // Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。  
    17.         // Notification.DEFAULT_SOUND:系统默认铃声。  
    18.         // Notification.DEFAULT_VIBRATE:系统默认震动。  
    19.         // Notification.DEFAULT_LIGHTS:系统默认闪光。  
    20.         // notifyBuilder.setDefaults(Notification.DEFAULT_ALL);  
    21.   
    22.         NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    23.         mNotificationManager.notify(NOTIFY_ID, notifyBuilder.build());  

    如上面的注释所示,如果你想点击完notification后,该通知自动消失,那么你就需要调用setAutoCancel(boolean b)这个方法,并且将其设为true,如果你想让你的通知栏常驻,用户无法滑动删除,也不能通过手机的清除键 删除,类似于墨迹天气等app的通知栏,那么你可以设置setOngoing方法,也设为true,这样,通知栏只能通过代码调用cancel方法才能消失,很霸道地,有木有!另外,从Android4.1时代开始,系统允许设置Notification的优先级,对于优先级高的通知,会排在 通知栏的前面,并在会在手机最上端的Status Bar显示一个图标,如果优先级设定的较低,那么就会被系统显示在通知栏的后面,并且Status Bar不再显示相应的图标,设置优先级的方法,就是调用setPriority(int p)。另外,当启动通知栏的时候,我们常常可以在手机最上端的Status Bar上面,会闪现一段提示语,用来提醒用户,这段提示语具体显示的文字,就是靠setTicker() 这个方法来实现的。除此之外,我们还可以设置,推送通知时的铃声、震动效果,闪光灯效果等等,具体的我就不一一列举了,参考上面的示例代码即可,需要注意 一点的是,设置通知的铃声,除去调用系统自带的外,还有两种方式,分别是调用SD卡中的声音文件和项目工程自带的声音文件,这两种方式都需要用到Uri的 地址,具体如何获取这两种的Uri,我已经在上面的代码中,写的很详细了,大家可以参考上面的代码,在自己的项目中实验一下。

    说了这么多,还有最重要的一点没有讲,那就是在你设置完notification的各 种属性后,你需要启动这个notification,否则就前功尽弃了,启动的方法,如上面的示例代码所示,你需要先获取一个 NotificationManager的实例,然后调用notify的方法,notifyBuilder.build()这个方法,可以实例化一个 notification的实例,另外,你还需要为这个notification分配一个独一无二的的id号,将来notification的更新和删 除,都是依靠这个id号来做索引对应的。

    有时候,我们会涉及到这么一个需求,那就是,产品设计,希望我们能够监听 notification的销毁,意思就是说,当用户手动滑动通知将其删除或者通过手机的删除按钮将其清空时,我们希望可以捕获到这一信息,并作出相应的 处理。比如说,我们在通知栏发送了一个通知,用来更新一个资源的下载进度,当用户删除这个通知后,我们希望可以监听到这一变化,作出相应的处理,比如取消 下载,比如重新下载等等,那么,应该如何监听取消的行为呢?请看代码:

    1. Intent deleteIntent = new Intent(this, DeleteService.class);  
    2. int deleteCode = (int) SystemClock.uptimeMillis();  
    3. PendingIntent deletePendingIntent = PendingIntent.getService(this,  
    4.         deleteCode, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    5. notifyBuilder.setDeleteIntent(deletePendingIntent);  

    我 们给notifyBuilder设置一个DeleteIntent,这里指向了一个service,当删除的行为发生后,系统就会启动这个 service,我们就可以在这个service中,做相应的逻辑处理了,当然,这里我只是举了一个例子,用来启动service,大家也可以将 Intent指向一个Activity或者一个广播,不过PendingIntent.getService()这个方法,就需要换成 PendingIntent.getActivity()或者PendingIntent.getBroadCast()这两个方法。

    上面的内容,我们大概了解了如何给notification设定显示的内容,和如何监 听销毁的行为。但是常常,我们会发现,除了以上功能外,我们经常遇见的情形时,当我们点击了一个notification后,就会自动打开一个页面,展示 出信息来源的具体页面,接下来,我们就针对这种情况,来看看代码是如何控制的。

    刚刚提到的自动跳转页面的功能,看似很简单的一个逻辑,其实也包含了各种逻辑处理情况,其中最主要的是有两种:

    一:当我们处在手机桌面主屏的时候,突然来了一条邮箱的信息,来了一 封新邮件,我们点击通知栏,系统会为我们打开最新收到的邮件,当我们看完邮件后,按返回键,我们并不会马上回到手机桌面的主屏上,而是先返回到收件箱界 面,然后再返回到邮件APP的主界面,然后再返回到手机桌面的主屏上,它是按照邮件APP的页面队列返回的。

    二:还是举刚才那个例子,当我们收到新邮件的通知后,我们点击打开新收到的邮件,当我们阅读完之后,我们想要点击返回键,立刻返回到我们刚刚所处的界面,继续进行刚才还在进行的任务。

    这两种情况,在产品设计中,常常出现,所以我们也要想办法去实现,那么如何去实现这两种情况呢,我们一个一个来看。

    首先请看第一种情况的代码:

     

    1. Intent notifyIntent = new Intent(this, NotifyRegularActivity.class);  
    2. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);  
    3. stackBuilder.addParentStack(NotifyRegularActivity.class);  
    4. stackBuilder.addNextIntent(notifyIntent);  
    5. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6. int requestCode = (int) SystemClock.uptimeMillis();  
    7. PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(  
    8.         requestCode, PendingIntent.FLAG_UPDATE_CURRENT);  
    9. notifyBuilder.setContentIntent(resultPendingIntent);  

    我们继续贴上AndroidManist.xml的配置代码:

     

    1. <activity  
    2.             android:name="com.example.notificationtest.MainActivity"  
    3.             android:label="@string/app_name" >  
    4.             <intent-filter>  
    5.                 <action android:name="android.intent.action.MAIN" />  
    6.   
    7.                 <category android:name="android.intent.category.LAUNCHER" />  
    8.             </intent-filter>  
    9.         </activity>  
    10.         <activity  
    11.             android:name="com.example.notificationtest.OtherActivity"  
    12.             android:label="OtherActivity"  
    13.             android:parentActivityName="com.example.notificationtest.MainActivity" >  
    14.             <meta-data  
    15.                 android:name="android.support.PARENT_ACTIVITY"  
    16.                 android:value="com.example.notificationtest.MainActivity" />  
    17.         </activity>  
    18.         <activity  
    19.             android:name="com.example.notificationtest.NotifyRegularActivity"  
    20.             android:label="NotifyRegularActivity"  
    21.             android:parentActivityName="com.example.notificationtest.OtherActivity" >  
    22.             <meta-data  
    23.                 android:name="android.support.PARENT_ACTIVITY"  
    24.                 android:value="com.example.notificationtest.OtherActivity" />  
    25.         </activity>  

    好,我们来分析一下上面的代码。首先我们设置了一个Intent,将其指向 NotifyRegularActivity,然后我们用到了TaskStackBuilder,它可以用来控制界面返回的导航堆栈。

     

    1. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);  
    2. stackBuilder.addParentStack(NotifyRegularActivity.class);  
    3. stackBuilder.addNextIntent(notifyIntent);  

    我们利用这段代码,首先实例化了一个TaskStackBuilder,然后调用addParentStack()addNextIntent(), 设置它的返回堆栈和跳转页面,跳转页面的Intent很好理解,跟大家平时的设置方式是一样的,那么它的返回堆栈是如何控制的呢?这就需要上面xml配置 文件的配置了,大家请看,在上面的配置文件中,一共有三个Activity,分别是MainActivity,OtherActivity,和 NotifyRegularActivity,其中NotifyRegularActivity就是我们点击通知栏后,要自动跳转的界面。在配置文件当 中,
    我们给后面两个Activity,设置了这么一个属性android:parentActivityName,它指的就是该activity的返回路径,因为刚刚我们在调用addParentStack()这个方法的时候,设置的参数是NotifyRegularActivity.class所以根据上面配置文件的配置内容,那么它的返回堆栈的顺序就是:

    技术分享

    需要注意的是,为了向下兼容版本,我们在设置android:parentActivityName这个属性的时候,还需要在配置文件中,为每个Activity进行如下设置:

     

    1. <meta-data  
    2.     android:name="android.support.PARENT_ACTIVITY"  
    3.     android:value="com.example.notificationtest.MainActivity" />  

    具体的value的指向,就需要你自己设定了,总之,它指向了该activity的返回页面。对TaskStackBuilder设置完成之后,我们再通过下面的代码获取PendingIntent,,然后赋值给notifyBuilder即可:

     

    1. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    2. int requestCode = (int) SystemClock.uptimeMillis();  
    3. PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(  
    4.         requestCode, PendingIntent.FLAG_UPDATE_CURRENT);  
    5. notifyBuilder.setContentIntent(resultPendingIntent);  

    这里有两点需要注意一下:

    1:PendingIntent.FLAG_UPDATE_CURRENT这个参数一般有四种选择分别是:

    FLAG_CANCEL_CURRENT:如果构建的PendingIntent已经存在,则取消前一个,重新构建一个。
    FLAG_NO_CREATE:如果前一个PendingIntent已经不存在了,将不再构建它。
    FLAG_ONE_SHOT:表明这里构建的PendingIntent只能使用一次。
    FLAG_UPDATE_CURRENT:如果构建的PendingIntent已经存在,那么系统将不会重复创建,只是把之前不同的传值替换掉。

    如果没有特殊要求的话,我们常常会使用FLAG_UPDATE_CURRENT这个参数来构造PendingIntent,但是这样常常会引发第二个问题,什么问题呢?呵呵~

    2:如上所述我们使用 FLAG_UPDATE_CURRENT这个参数后,常常会发现,我们点击通知栏后,系统没有响应,时灵时不灵的,很是忧郁,这是为什么呢?原来使用 FLAG_UPDATE_CURRENT这个参数后,系统不会重新创建新的PendingIntent,这样一来,如果你传递的Intent的 extra参数没有变化的话,那么系统就会认为你没有发送新的PendingIntent,这样就不会重新响应你的点击事件。一般情况下,为了能够区分每 次的PendingIntent不一样,我们常常会在构造Intent的时候,设置不同的Action或者Extra值,这样一来,及时是使用 FLAG_UPDATE_CURRENT这个参数,系统也会因为传值参数的变化而去响应每次的点击跳转事件。不过这种解决方法还是有些麻烦,有时候,我们 根本不需要传递额外的Aciton或者参数值,这该怎么办呢?哈哈,解决代码已经在上面的代码中写出来了,在stackBuilder.getPendingIntent(requestCode, PendingIntent.FLAG_UPDATE_CURRENT)这个方法中,我们注意到第一个参数,这里,我们只要为这个参数设置一个独一无二的标识,那么刚刚提到的点击无响应的问题就迎刃而解了,我平时的设置办法就是利用这段代码:

     

    1. int requestCode = (int) SystemClock.uptimeMillis();  

    获取发布通知时的时间,将它作为requestCode,这样就可以避免这些问题了。不过如果你要是使用FLAG_CANCEL_CURRENT这个参数的话,就会每次都创建一个新的,那么刚刚提到的这两个问题,也都不存在了,具体怎么用,看你实际的业务要求了。

    上面的讲解,我们就可以解决刚刚讨论的第一种情形了,下面我们来说一下,第二种情形,也就是点击返回键后,直接返回刚刚任务所处的界面,看看这个如何实现。来,看代码:

     

    1. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    2.         notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    3.                 | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    4.         // Creates the PendingIntent  
    5.         // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6.         int requestCode = (int) SystemClock.uptimeMillis();  
    7.         PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    8.                 notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    9.         notifyBuilder.setContentIntent(pendIntent);  

    继续看配置文件的设置:

     

    1. <activity  
    2.     android:name="com.example.notificationtest.NotifySpecialActivity"  
    3.     android:excludeFromRecents="true"  
    4.     android:label="NotifySpecialActivity"  
    5.     android:launchMode="singleTask"  
    6.     android:taskAffinity="" >  
    7. </activity>  

    在代码中,我们设置NotifySpecialActivity为我们要跳转的界面,然后在xml的配置文件中,我们重点设置了这三个属性:android:excludeFromRecents="true",android:launchMode="singleTask",android:taskAffinity="",第一个属性的设置,是将该界面从最近任务栏当中移除,防止用户通过最近任务栏而进入到该界面,这样一来,只能通过通知来的点击来进入。第二种属性的设置就很常见了,是为了防止该界面存在的情况下,重复创建该Activity,第三属性是为了配置代码中的这段来设置的:

     

    1. notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    2.         | Intent.FLAG_ACTIVITY_CLEAR_TASK);  

    这样的作用是为此次跳转界面的行为重新分配一个任务堆栈,而不从属于其它的任务堆栈,这样的话,当我们点击返回键后,就可以直接返回到刚刚用户所处的任务界面了。由于这里我们不再使用TaskStackBuilder,所以最后需要调用PendingIntent.getActivity(this, requestCode,notifyIntent,PendingIntent.FLAG_UPDATE_CURRENT)这个方法来构造一个PendingIntent,然后赋值给notifyBuilder。这样,刚刚讨论过的第二种情形,我们就可以解决了,相比较第一种来说,这种解决方式更为简洁,不过处理的业务逻辑也不一样,大家斟酌而定。


    Notificaton在平时的产品设计中,常常用来显示跟网络交互的进度,我们常常的做法是在通知栏上面,显示一个进度条,用来更新交互的进度,这个的实现方式很简单,主要依赖于mBuilder.setProgress()这个方法,具体的做法可以参考下面的代码:

     

    1.     final NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    2.     final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(  
    3.             this);  
    4.     mBuilder.setContentTitle("Picture Download")  
    5.             .setContentText("Download in progress")  
    6.             .setSmallIcon(R.drawable.small);  
    7.     new Thread(new Runnable() {  
    8.         @Override  
    9.         public void run() {  
    10.             int incr;  
    11.             for (incr = 0; incr <= 100; incr += 5) {  
    12.                 // mBuilder.setProgress(100, incr, false);  
    13.                 mBuilder.setProgress(0, 0, true);  
    14.                 mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    15.                 try {  
    16.                     Thread.sleep(1 * 1000);  
    17.                 } catch (InterruptedException e) {  
    18.                 }  
    19.             }  
    20.             mBuilder.setContentText("Download complete").setProgress(0, 0,  
    21.                     false);  
    22.             mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    23.         }  
    24.     }  
    25.     // Starts the thread by calling the run() method in its Runnable  
    26.     ).start();  
    27. }  

    在代码中,我们开启了一个线程,里面进行20次for循环,每次循环都会调用setProgress这个方法,因为每次调用的NOTIFY_ID都是相同的,所以系统会根据这个ID来更新notification的进度而不会重新创建一个新的Notification。setProgress这个方法一共有两种方法,一种是这样的:

     

    1. mBuilder.setProgress(100, incr, false);  

    第一个参数指的的是进度的总长度,第二个参数是目前进行的长度,然后将第三个参数设为false,我们可以看到的效果就如下图:

    技术分享

    我们可以看见进度条的确切位置和进度情况。还有一种使用方法是这样的:

     

    1. mBuilder.setProgress(0, 0, true);  

    将前两个参数都设为0,然后将最后这个参数设为true,这样的进度条效果是一种连续模糊的,适合进行时间不确定的网络连接,效果图如下:

    技术分享
    最后,当我们的任务完成后,我们需要取消进度条的显示,这时候我们需要调用如下方法:

     

    1. mBuilder.setContentText("Download complete").setProgress(0, 0,  
    2.         false);  

    设置一个任务完成后的文本描述,然后将setProgress的前两个参数都设为0,最后一个参数设为false,这样进度条就不会在通知栏上面显示了,效果图:

    技术分享

    Notification的进度条的使用方法就是这些,如果大家平时用的不多,最好还是根据上面贴出的源代码,自己联系一遍,稍候我也会把本次工程的源代码打包,上传到CSDN的资源库中,供大家参考。


    上面跟大家介绍的,都是Notification的一种常规样式,自从Android4.1之后,谷歌引入了一种新的样式,叫做Big View,效果就是相对于传统的Notification,它的显示区域更大,显示的内容也更多一些。关于Big View,谷歌支持了三种模式,分别是:

    Big text style 还有 new NotificationCompat.Builder(  

    •         this).setSmallIcon(R.drawable.small)  
    •         .setContentTitle("Picture tracker")  
    •         .setContentText("Picture received");  
    • NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle();  
    • Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bigpic);  
    • picStyle.bigPicture(bitmap);  
    • mBuilder.setStyle(picStyle);  
    • NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    • mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  

    首先我们实例化一个NotificationCompat.BigPictureStyle,然后读取要展示的图片资源,调用picStyle.bigPicture(bitmap)这个方法设置图片,最后调用notifyBuilder的mBuilder.setStyle(picStyle)方法,设置好BIG VIEW的样式,就OK了,代码简单的令人发指,我就不多解释了,大家参考上面的示例代码即可。

    接下来,我们再看看Inbox style这种样式是如何设置的:

    1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(  
    2.         this).setSmallIcon(R.drawable.small)  
    3.         .setContentTitle("Inbox tracker")  
    4.         .setContentText("Inbox received");  
    5. NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();  
    6. String[] events = new String[6];  
    7. events[0] = "Hello my one world";  
    8. events[1] = "Hello my two world";  
    9. events[2] = "Hello my three world";  
    10. events[3] = "Hello my four world";  
    11. events[4] = "Hello my five world";  
    12. events[5] = "Hello my six world";  
    13. inboxStyle.setBigContentTitle("Inbox tracker details:");  
    14. for (int i = 0; i < events.length; i++) {  
    15.     inboxStyle.addLine(events[i]);  
    16. }  
    17. inboxStyle.setBigContentTitle("Thers are six messages");  
    18. inboxStyle.setSummaryText("It‘s so easy,right?");  
    19. mBuilder.setStyle(inboxStyle);  
    20. NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    21. mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  

    唉,代码是不是再简单不过了,我都不好意思班门弄斧的介绍这段代码了。主要声明一下三个方法的使用吧,inboxStyle.addLine(),这个方法是用来设置下图中黄色区域的文字,inboxStyle.setBigContentTitle("Thers are six messages")这个方法是用来设置红色区域的文字内容,inboxStyle.setSummaryText("It‘s so easy,right?")是用来设置绿色区域的内容显示,其他的基本设置在之前的内容中,都已经介绍了很多了,我就不重复介绍了。

    技术分享

    通过上面的学习,想必大家已经对Notification有了一个比较全面的了解了,最后, 我再给大家介绍一种自定义 Notification布局的用法。自定义Notification布局的app有很多,比如像墨迹天气,Clean Master等等,利用自定义布局,将用户所需信息和快捷功能,多样化的展示在通知栏上面,给大家看一下Clean Master的截图:

    技术分享

    其实要是实现这种自定义布局的Notification,非常简单,我们这就给大家展示代码设置和布局配置:

    先看看java代码:

    1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);  
    2. RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);  
    3. remoteView.setTextViewText(R.id.text, "Custom Text");  
    4. remoteView.setTextViewText(R.id.btn, "Custom Button");  
    5. remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);  
    6.   
    7. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    8. notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    9.         | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    10. // Creates the PendingIntent  
    11. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    12. int requestCode = (int) SystemClock.uptimeMillis();  
    13. PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    14.         notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    15. remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);  
    16.   
    17. mBuilder.setSmallIcon(R.drawable.small);  
    18. mBuilder.setContent(remoteView);  
    19. NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    20. mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  

    再来看看xml布局文件是什么样的:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="match_parent"  
    4.     android:layout_height="64dp" >  
    5.   
    6.     <ImageView  
    7.         android:id="@+id/image"  
    8.         android:layout_width="wrap_content"  
    9.         android:layout_height="match_parent"  
    10.         android:layout_alignParentLeft="true"  
    11.         android:gravity="center" />  
    12.   
    13.     <TextView  
    14.         android:id="@+id/text"  
    15.         android:layout_width="wrap_content"  
    16.         android:layout_height="match_parent"  
    17.         android:layout_centerInParent="true"  
    18.         android:gravity="center" />  
    19.   
    20.     <Button  
    21.         android:id="@+id/btn"  
    22.         android:layout_width="wrap_content"  
    23.         android:layout_height="wrap_content"  
    24.         android:layout_alignParentRight="true"  
    25.         android:gravity="center" />  
    26.   
    27. </RelativeLayout>  


    我们首先利用下面这行代码去解析上面的布局文件

    1. RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);  

    然后根据每个控件的id号进行资源设置:

    1. remoteView.setTextViewText(R.id.text, "Custom Text");  
    2. remoteView.setTextViewText(R.id.btn, "Custom Button");  
    3. remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);  

    我们也可以为这些控件单独设置点击事件,比如设置Button的点击事件:

    1. remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);  

    上面第二个参数pendingIntent的获取,在之前的讲解中,已经介绍了好几种方式了,这里我们随便选择一种来实现了:

    1. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    2.         notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    3.                 | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    4.         // Creates the PendingIntent  
    5.         // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6.         int requestCode = (int) SystemClock.uptimeMillis();  
    7.         PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    8.                 notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  


    最后,我们要调用下面这段代码,将自定义的RemoteView设置给notifyBuilder,然后调用发送通知的方法就OK了。

    1. mBuilder.setContent(remoteView);  


    最后的最后,需要再给大家介绍两个方法,那就是通过代码来取消Notification,咱不能只管杀不管埋啊,哈哈~

    1. NotificationManager cancelNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    2. cancelNotificationManager.cancel(NOTIFY_ID);  
    3. cancelNotificationManager.cancelAll();  

    cancelNotificationManager.cancel(NOTIFY_ID)这个方法是根据之前发布通知时,分配的ID号,来取消对应的通知栏。cancelNotificationManager.cancelAll()这个方法是取消所有之前发布过的通知栏,比较暴力一点哈。

    展开全文
  • Android的Notification是android系统中很重要的一个机制, 产品人员常常利用通知栏的方式,跟用户进行弱沟通。...另外类似于墨迹天气,清理大师等 app,也会将通知栏常驻,利用自定义的布局,方便用户及时快捷的...

    转自:http://blog.csdn.net/xy_nyle/article/details/19853591

    Android的Notification是android系统中很重要的一个机制, 产品人员常常利用通知栏的方式,跟用户进行弱沟通。拥有推送通知的app要比没有此类功能的app活跃率要高很多。另外类似于墨迹天气,清理大师等 app,也会将通知栏常驻,利用自定义的布局,方便用户及时快捷的查看所需的信息和使用快捷的功能。所以Notification的使用,也在开发当中, 使用的越来越频繁。今天我就来跟大家分享一下Notification的常用事项。

    我不了解大家平时怎么使用Notification,我常常看到有些人的代码是这样写的:

    1. Notification notification=new Notification(notificationIcon, notificationTitle, when);    
    2.             
    3.         notification.defaults=Notification.DEFAULT_ALL;    
    4.             
    5.         Intent intent=new Intent(MainActivity.this,SecondActivity.class);    
    6.         PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this, 0, intent, 0);    
    7.         notification.setLatestEventInfo(this,"测试展开title", "测试展开内容",pendingIntent);   
    8. 。。。。。。。。。。。。。  


    具体的代码我就不贴全了,因为大家如果注意IDE的提示的话,就会发现,其实这是一种不推荐 的用法,API的支持已经过时了。最新的Notification的用法,是推荐使用V4包下的NotificationCompat.Builder, 利用它,进行各种设置,具体的用法先别着急,我们慢慢道来。

    1. NotificationCompat.Builder notifyBuilder = new NotificationCompat.Builder(  
    2.         this);  

    首先,我们需要先初始化一个notifyBuilder,然后利用它的各种set方法,进行相关设置,具体的设置,我们参考下图:

    图示中的序号1,叫做

    1. notifyBuilder.setContentTitle("This is My Notification");  

    图示中的序号3,叫做

    1. notifyBuilder.setContentText("Hello World");  

    图示中的需要5,叫做利用下面的方法来设置:

    这三个参数的设定是必须的,每次调用Notification,必须得设定这三个参数。除去这三个以外,另外的2,4,6区域,分别是Large Icon,Content Info,Time,设置方法如下所示:

    • Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bigicon);  
    • notifyBuilder.setLargeIcon(bitmap);  
    • // 这里用来显示右下角的数字  
    • notifyBuilder.setNumber(10);  
    • notifyBuilder.setWhen(System.currentTimeMillis());  

    以上就是关于Notification的基本设置,下面,我们继续看看其它方面的设置,直接上代码:

     

    1. // 将AutoCancel设为true后,当你点击通知栏的notification后,它会自动被取消消失  
    2.         notifyBuilder.setAutoCancel(true);  
    3.         // 将Ongoing设为true 那么notification将不能滑动删除  
    4.         // notifyBuilder.setOngoing(true);  
    5.         // 从Android4.1开始,可以通过以下方法,设置notification的优先级,优先级越高的,通知排的越靠前,优先级低的,不会在手机最顶部的状态栏显示图标  
    6.         notifyBuilder.setPriority(NotificationCompat.PRIORITY_MAX);  
    7.         // notifyBuilder.setPriority(NotificationCompat.PRIORITY_MIN);  
    8.   
    9.         notifyBuilder.setTicker("Hi,Notification is here");  
    10.           
    11.         // Uri uri =  
    12.         // Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.cat);  
    13.         // Uri uri = Uri.parse("file:///mnt/sdcard/cat.mp3");  
    14.         // notifyBuilder.setSound(uri);  
    15.   
    16.         // Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。  
    17.         // Notification.DEFAULT_SOUND:系统默认铃声。  
    18.         // Notification.DEFAULT_VIBRATE:系统默认震动。  
    19.         // Notification.DEFAULT_LIGHTS:系统默认闪光。  
    20.         // notifyBuilder.setDefaults(Notification.DEFAULT_ALL);  
    21.   
    22.         NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    23.         mNotificationManager.notify(NOTIFY_ID, notifyBuilder.build());  

    如上面的注释所示,如果你想点击完notification后,该通知自动消失,那么你就需要调用setAutoCancel(boolean b)这个方法,并且将其设为true,如果你想让你的通知栏常驻,用户无法滑动删除,也不能通过手机的清除键 删除,类似于墨迹天气等app的通知栏,那么你可以设置setOngoing方法,也设为true,这样,通知栏只能通过代码调用cancel方法才能消失,很霸道地,有木有!另外,从Android4.1时代开始,系统允许设置Notification的优先级,对于优先级高的通知,会排在 通知栏的前面,并在会在手机最上端的Status Bar显示一个图标,如果优先级设定的较低,那么就会被系统显示在通知栏的后面,并且Status Bar不再显示相应的图标,设置优先级的方法,就是调用setPriority(int p)。另外,当启动通知栏的时候,我们常常可以在手机最上端的Status Bar上面,会闪现一段提示语,用来提醒用户,这段提示语具体显示的文字,就是靠setTicker() 这个方法来实现的。除此之外,我们还可以设置,推送通知时的铃声、震动效果,闪光灯效果等等,具体的我就不一一列举了,参考上面的示例代码即可,需要注意 一点的是,设置通知的铃声,除去调用系统自带的外,还有两种方式,分别是调用SD卡中的声音文件和项目工程自带的声音文件,这两种方式都需要用到Uri的 地址,具体如何获取这两种的Uri,我已经在上面的代码中,写的很详细了,大家可以参考上面的代码,在自己的项目中实验一下。

    说了这么多,还有最重要的一点没有讲,那就是在你设置完notification的各 种属性后,你需要启动这个notification,否则就前功尽弃了,启动的方法,如上面的示例代码所示,你需要先获取一个 NotificationManager的实例,然后调用notify的方法,notifyBuilder.build()这个方法,可以实例化一个 notification的实例,另外,你还需要为这个notification分配一个独一无二的的id号,将来notification的更新和删 除,都是依靠这个id号来做索引对应的。

    有时候,我们会涉及到这么一个需求,那就是,产品设计,希望我们能够监听 notification的销毁,意思就是说,当用户手动滑动通知将其删除或者通过手机的删除按钮将其清空时,我们希望可以捕获到这一信息,并作出相应的 处理。比如说,我们在通知栏发送了一个通知,用来更新一个资源的下载进度,当用户删除这个通知后,我们希望可以监听到这一变化,作出相应的处理,比如取消 下载,比如重新下载等等,那么,应该如何监听取消的行为呢?请看代码:

    1. Intent deleteIntent = new Intent(this, DeleteService.class);  
    2. int deleteCode = (int) SystemClock.uptimeMillis();  
    3. PendingIntent deletePendingIntent = PendingIntent.getService(this,  
    4.         deleteCode, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    5. notifyBuilder.setDeleteIntent(deletePendingIntent);  

    我 们给notifyBuilder设置一个DeleteIntent,这里指向了一个service,当删除的行为发生后,系统就会启动这个 service,我们就可以在这个service中,做相应的逻辑处理了,当然,这里我只是举了一个例子,用来启动service,大家也可以将 Intent指向一个Activity或者一个广播,不过PendingIntent.getService()这个方法,就需要换成 PendingIntent.getActivity()或者PendingIntent.getBroadCast()这两个方法。

    上面的内容,我们大概了解了如何给notification设定显示的内容,和如何监 听销毁的行为。但是常常,我们会发现,除了以上功能外,我们经常遇见的情形时,当我们点击了一个notification后,就会自动打开一个页面,展示 出信息来源的具体页面,接下来,我们就针对这种情况,来看看代码是如何控制的。

    刚刚提到的自动跳转页面的功能,看似很简单的一个逻辑,其实也包含了各种逻辑处理情况,其中最主要的是有两种:

    一:当我们处在手机桌面主屏的时候,突然来了一条邮箱的信息,来了一 封新邮件,我们点击通知栏,系统会为我们打开最新收到的邮件,当我们看完邮件后,按返回键,我们并不会马上回到手机桌面的主屏上,而是先返回到收件箱界 面,然后再返回到邮件APP的主界面,然后再返回到手机桌面的主屏上,它是按照邮件APP的页面队列返回的。

    二:还是举刚才那个例子,当我们收到新邮件的通知后,我们点击打开新收到的邮件,当我们阅读完之后,我们想要点击返回键,立刻返回到我们刚刚所处的界面,继续进行刚才还在进行的任务。

    这两种情况,在产品设计中,常常出现,所以我们也要想办法去实现,那么如何去实现这两种情况呢,我们一个一个来看。

    首先请看第一种情况的代码:

     

    1. Intent notifyIntent = new Intent(this, NotifyRegularActivity.class);  
    2. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);  
    3. stackBuilder.addParentStack(NotifyRegularActivity.class);  
    4. stackBuilder.addNextIntent(notifyIntent);  
    5. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6. int requestCode = (int) SystemClock.uptimeMillis();  
    7. PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(  
    8.         requestCode, PendingIntent.FLAG_UPDATE_CURRENT);  
    9. notifyBuilder.setContentIntent(resultPendingIntent);  

    我们继续贴上AndroidManist.xml的配置代码:

     

    1. <activity  
    2.             android:name="com.example.notificationtest.MainActivity"  
    3.             android:label="@string/app_name" >  
    4.             <intent-filter>  
    5.                 <action android:name="android.intent.action.MAIN" />  
    6.   
    7.                 <category android:name="android.intent.category.LAUNCHER" />  
    8.             </intent-filter>  
    9.         </activity>  
    10.         <activity  
    11.             android:name="com.example.notificationtest.OtherActivity"  
    12.             android:label="OtherActivity"  
    13.             android:parentActivityName="com.example.notificationtest.MainActivity" >  
    14.             <meta-data  
    15.                 android:name="android.support.PARENT_ACTIVITY"  
    16.                 android:value="com.example.notificationtest.MainActivity" />  
    17.         </activity>  
    18.         <activity  
    19.             android:name="com.example.notificationtest.NotifyRegularActivity"  
    20.             android:label="NotifyRegularActivity"  
    21.             android:parentActivityName="com.example.notificationtest.OtherActivity" >  
    22.             <meta-data  
    23.                 android:name="android.support.PARENT_ACTIVITY"  
    24.                 android:value="com.example.notificationtest.OtherActivity" />  
    25.         </activity>  

    好,我们来分析一下上面的代码。首先我们设置了一个Intent,将其指向 NotifyRegularActivity,然后我们用到了TaskStackBuilder,它可以用来控制界面返回的导航堆栈。

     

    1. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);  
    2. stackBuilder.addParentStack(NotifyRegularActivity.class);  
    3. stackBuilder.addNextIntent(notifyIntent);  

    我们利用这段代码,首先实例化了一个TaskStackBuilder,然后调用addParentStack()addNextIntent(), 设置它的返回堆栈和跳转页面,跳转页面的Intent很好理解,跟大家平时的设置方式是一样的,那么它的返回堆栈是如何控制的呢?这就需要上面xml配置 文件的配置了,大家请看,在上面的配置文件中,一共有三个Activity,分别是MainActivity,OtherActivity,和 NotifyRegularActivity,其中NotifyRegularActivity就是我们点击通知栏后,要自动跳转的界面。在配置文件当 中,
    我们给后面两个Activity,设置了这么一个属性android:parentActivityName,它指的就是该activity的返回路径,因为刚刚我们在调用addParentStack()这个方法的时候,设置的参数是NotifyRegularActivity.class所以根据上面配置文件的配置内容,那么它的返回堆栈的顺序就是:


    需要注意的是,为了向下兼容版本,我们在设置android:parentActivityName这个属性的时候,还需要在配置文件中,为每个Activity进行如下设置:

     

    1. <meta-data  
    2.     android:name="android.support.PARENT_ACTIVITY"  
    3.     android:value="com.example.notificationtest.MainActivity" />  

    具体的value的指向,就需要你自己设定了,总之,它指向了该activity的返回页面。对TaskStackBuilder设置完成之后,我们再通过下面的代码获取PendingIntent,,然后赋值给notifyBuilder即可:

     

    1. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    2. int requestCode = (int) SystemClock.uptimeMillis();  
    3. PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(  
    4.         requestCode, PendingIntent.FLAG_UPDATE_CURRENT);  
    5. notifyBuilder.setContentIntent(resultPendingIntent);  

    这里有两点需要注意一下:

    1:PendingIntent.FLAG_UPDATE_CURRENT这个参数一般有四种选择分别是:

    FLAG_CANCEL_CURRENT:如果构建的PendingIntent已经存在,则取消前一个,重新构建一个。
    FLAG_NO_CREATE:如果前一个PendingIntent已经不存在了,将不再构建它。
    FLAG_ONE_SHOT:表明这里构建的PendingIntent只能使用一次。
    FLAG_UPDATE_CURRENT:如果构建的PendingIntent已经存在,那么系统将不会重复创建,只是把之前不同的传值替换掉。

    如果没有特殊要求的话,我们常常会使用FLAG_UPDATE_CURRENT这个参数来构造PendingIntent,但是这样常常会引发第二个问题,什么问题呢?呵呵~

    2:如上所述我们使用 FLAG_UPDATE_CURRENT这个参数后,常常会发现,我们点击通知栏后,系统没有响应,时灵时不灵的,很是忧郁,这是为什么呢?原来使用 FLAG_UPDATE_CURRENT这个参数后,系统不会重新创建新的PendingIntent,这样一来,如果你传递的Intent的 extra参数没有变化的话,那么系统就会认为你没有发送新的PendingIntent,这样就不会重新响应你的点击事件。一般情况下,为了能够区分每 次的PendingIntent不一样,我们常常会在构造Intent的时候,设置不同的Action或者Extra值,这样一来,及时是使用 FLAG_UPDATE_CURRENT这个参数,系统也会因为传值参数的变化而去响应每次的点击跳转事件。不过这种解决方法还是有些麻烦,有时候,我们 根本不需要传递额外的Aciton或者参数值,这该怎么办呢?哈哈,解决代码已经在上面的代码中写出来了,在stackBuilder.getPendingIntent(requestCode, PendingIntent.FLAG_UPDATE_CURRENT)这个方法中,我们注意到第一个参数,这里,我们只要为这个参数设置一个独一无二的标识,那么刚刚提到的点击无响应的问题就迎刃而解了,我平时的设置办法就是利用这段代码:

     

    1. int requestCode = (int) SystemClock.uptimeMillis();  

    获取发布通知时的时间,将它作为requestCode,这样就可以避免这些问题了。不过如果你要是使用FLAG_CANCEL_CURRENT这个参数的话,就会每次都创建一个新的,那么刚刚提到的这两个问题,也都不存在了,具体怎么用,看你实际的业务要求了。

    上面的讲解,我们就可以解决刚刚讨论的第一种情形了,下面我们来说一下,第二种情形,也就是点击返回键后,直接返回刚刚任务所处的界面,看看这个如何实现。来,看代码:

     

    1. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    2.         notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    3.                 | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    4.         // Creates the PendingIntent  
    5.         // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6.         int requestCode = (int) SystemClock.uptimeMillis();  
    7.         PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    8.                 notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    9.         notifyBuilder.setContentIntent(pendIntent);  

    继续看配置文件的设置:

     

    1. <activity  
    2.     android:name="com.example.notificationtest.NotifySpecialActivity"  
    3.     android:excludeFromRecents="true"  
    4.     android:label="NotifySpecialActivity"  
    5.     android:launchMode="singleTask"  
    6.     android:taskAffinity="" >  
    7. </activity>  

    在代码中,我们设置NotifySpecialActivity为我们要跳转的界面,然后在xml的配置文件中,我们重点设置了这三个属性:android:excludeFromRecents="true",android:launchMode="singleTask",android:taskAffinity="",第一个属性的设置,是将该界面从最近任务栏当中移除,防止用户通过最近任务栏而进入到该界面,这样一来,只能通过通知来的点击来进入。第二种属性的设置就很常见了,是为了防止该界面存在的情况下,重复创建该Activity,第三属性是为了配置代码中的这段来设置的:

     

    1. notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    2.         | Intent.FLAG_ACTIVITY_CLEAR_TASK);  

    这样的作用是为此次跳转界面的行为重新分配一个任务堆栈,而不从属于其它的任务堆栈,这样的话,当我们点击返回键后,就可以直接返回到刚刚用户所处的任务界面了。由于这里我们不再使用TaskStackBuilder,所以最后需要调用PendingIntent.getActivity(this, requestCode,notifyIntent,PendingIntent.FLAG_UPDATE_CURRENT)这个方法来构造一个PendingIntent,然后赋值给notifyBuilder。这样,刚刚讨论过的第二种情形,我们就可以解决了,相比较第一种来说,这种解决方式更为简洁,不过处理的业务逻辑也不一样,大家斟酌而定。


    Notificaton在平时的产品设计中,常常用来显示跟网络交互的进度,我们常常的做法是在通知栏上面,显示一个进度条,用来更新交互的进度,这个的实现方式很简单,主要依赖于mBuilder.setProgress()这个方法,具体的做法可以参考下面的代码:

     

    1.     final NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    2.     final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(  
    3.             this);  
    4.     mBuilder.setContentTitle("Picture Download")  
    5.             .setContentText("Download in progress")  
    6.             .setSmallIcon(R.drawable.small);  
    7.     new Thread(new Runnable() {  
    8.         @Override  
    9.         public void run() {  
    10.             int incr;  
    11.             for (incr = 0; incr <= 100; incr += 5) {  
    12.                 // mBuilder.setProgress(100, incr, false);  
    13.                 mBuilder.setProgress(0, 0, true);  
    14.                 mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    15.                 try {  
    16.                     Thread.sleep(1 * 1000);  
    17.                 } catch (InterruptedException e) {  
    18.                 }  
    19.             }  
    20.             mBuilder.setContentText("Download complete").setProgress(0, 0,  
    21.                     false);  
    22.             mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    23.         }  
    24.     }  
    25.     // Starts the thread by calling the run() method in its Runnable  
    26.     ).start();  
    27. }  

    在代码中,我们开启了一个线程,里面进行20次for循环,每次循环都会调用setProgress这个方法,因为每次调用的NOTIFY_ID都是相同的,所以系统会根据这个ID来更新notification的进度而不会重新创建一个新的Notification。setProgress这个方法一共有两种方法,一种是这样的:

     

    1. mBuilder.setProgress(100, incr, false);  

    第一个参数指的的是进度的总长度,第二个参数是目前进行的长度,然后将第三个参数设为false,我们可以看到的效果就如下图:



    我们可以看见进度条的确切位置和进度情况。还有一种使用方法是这样的:

     

    1. mBuilder.setProgress(0, 0, true);  

    将前两个参数都设为0,然后将最后这个参数设为true,这样的进度条效果是一种连续模糊的,适合进行时间不确定的网络连接,效果图如下:


    最后,当我们的任务完成后,我们需要取消进度条的显示,这时候我们需要调用如下方法:

     

    1. mBuilder.setContentText("Download complete").setProgress(0, 0,  
    2.         false);  

    设置一个任务完成后的文本描述,然后将setProgress的前两个参数都设为0,最后一个参数设为false,这样进度条就不会在通知栏上面显示了,效果图:



    Notification的进度条的使用方法就是这些,如果大家平时用的不多,最好还是根据上面贴出的源代码,自己联系一遍,稍候我也会把本次工程的源代码打包,上传到CSDN的资源库中,供大家参考。


    上面跟大家介绍的,都是Notification的一种常规样式,自从Android4.1之后,谷歌引入了一种新的样式,叫做Big View,效果就是相对于传统的Notification,它的显示区域更大,显示的内容也更多一些。关于Big View,谷歌支持了三种模式,分别是:

    Big text style 还有 new NotificationCompat.Builder(  

    •         this).setSmallIcon(R.drawable.small)  
    •         .setContentTitle("Picture tracker")  
    •         .setContentText("Picture received");  
    • NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle();  
    • Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bigpic);  
    • picStyle.bigPicture(bitmap);  
    • mBuilder.setStyle(picStyle);  
    • NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    • mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  

    首先我们实例化一个NotificationCompat.BigPictureStyle,然后读取要展示的图片资源,调用picStyle.bigPicture(bitmap)这个方法设置图片,最后调用notifyBuilder的mBuilder.setStyle(picStyle)方法,设置好BIG VIEW的样式,就OK了,代码简单的令人发指,我就不多解释了,大家参考上面的示例代码即可。

    接下来,我们再看看Inbox style这种样式是如何设置的:

    1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(  
    2.         this).setSmallIcon(R.drawable.small)  
    3.         .setContentTitle("Inbox tracker")  
    4.         .setContentText("Inbox received");  
    5. NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();  
    6. String[] events = new String[6];  
    7. events[0] = "Hello my one world";  
    8. events[1] = "Hello my two world";  
    9. events[2] = "Hello my three world";  
    10. events[3] = "Hello my four world";  
    11. events[4] = "Hello my five world";  
    12. events[5] = "Hello my six world";  
    13. inboxStyle.setBigContentTitle("Inbox tracker details:");  
    14. for (int i = 0; i < events.length; i++) {  
    15.     inboxStyle.addLine(events[i]);  
    16. }  
    17. inboxStyle.setBigContentTitle("Thers are six messages");  
    18. inboxStyle.setSummaryText("It's so easy,right?");  
    19. mBuilder.setStyle(inboxStyle);  
    20. NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    21. mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  

    唉,代码是不是再简单不过了,我都不好意思班门弄斧的介绍这段代码了。主要声明一下三个方法的使用吧,inboxStyle.addLine(),这个方法是用来设置下图中黄色区域的文字,inboxStyle.setBigContentTitle("Thers are six messages")这个方法是用来设置红色区域的文字内容,inboxStyle.setSummaryText("It's so easy,right?")是用来设置绿色区域的内容显示,其他的基本设置在之前的内容中,都已经介绍了很多了,我就不重复介绍了。



    通过上面的学习,想必大家已经对Notification有了一个比较全面的了解了,最后, 我再给大家介绍一种自定义 Notification布局的用法。自定义Notification布局的app有很多,比如像墨迹天气,Clean Master等等,利用自定义布局,将用户所需信息和快捷功能,多样化的展示在通知栏上面,给大家看一下Clean Master的截图:


    其实要是实现这种自定义布局的Notification,非常简单,我们这就给大家展示代码设置和布局配置:

    先看看java代码:

    1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);  
    2. RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);  
    3. remoteView.setTextViewText(R.id.text, "Custom Text");  
    4. remoteView.setTextViewText(R.id.btn, "Custom Button");  
    5. remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);  
    6.   
    7. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    8. notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    9.         | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    10. // Creates the PendingIntent  
    11. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    12. int requestCode = (int) SystemClock.uptimeMillis();  
    13. PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    14.         notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    15. remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);  
    16.   
    17. mBuilder.setSmallIcon(R.drawable.small);  
    18. mBuilder.setContent(remoteView);  
    19. NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    20. mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  

    再来看看xml布局文件是什么样的:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="match_parent"  
    4.     android:layout_height="64dp" >  
    5.   
    6.     <ImageView  
    7.         android:id="@+id/image"  
    8.         android:layout_width="wrap_content"  
    9.         android:layout_height="match_parent"  
    10.         android:layout_alignParentLeft="true"  
    11.         android:gravity="center" />  
    12.   
    13.     <TextView  
    14.         android:id="@+id/text"  
    15.         android:layout_width="wrap_content"  
    16.         android:layout_height="match_parent"  
    17.         android:layout_centerInParent="true"  
    18.         android:gravity="center" />  
    19.   
    20.     <Button  
    21.         android:id="@+id/btn"  
    22.         android:layout_width="wrap_content"  
    23.         android:layout_height="wrap_content"  
    24.         android:layout_alignParentRight="true"  
    25.         android:gravity="center" />  
    26.   
    27. </RelativeLayout>  


    我们首先利用下面这行代码去解析上面的布局文件

    1. RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);  

    然后根据每个控件的id号进行资源设置:

    1. remoteView.setTextViewText(R.id.text, "Custom Text");  
    2. remoteView.setTextViewText(R.id.btn, "Custom Button");  
    3. remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);  

    我们也可以为这些控件单独设置点击事件,比如设置Button的点击事件:

    1. remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);  

    上面第二个参数pendingIntent的获取,在之前的讲解中,已经介绍了好几种方式了,这里我们随便选择一种来实现了:

    1. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    2.         notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    3.                 | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    4.         // Creates the PendingIntent  
    5.         // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6.         int requestCode = (int) SystemClock.uptimeMillis();  
    7.         PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    8.                 notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  


    最后,我们要调用下面这段代码,将自定义的RemoteView设置给notifyBuilder,然后调用发送通知的方法就OK了。

    1. mBuilder.setContent(remoteView);  


    最后的最后,需要再给大家介绍两个方法,那就是通过代码来取消Notification,咱不能只管杀不管埋啊,哈哈~

    1. NotificationManager cancelNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    2. cancelNotificationManager.cancel(NOTIFY_ID);  
    3. cancelNotificationManager.cancelAll();  

    cancelNotificationManager.cancel(NOTIFY_ID)这个方法是根据之前发布通知时,分配的ID号,来取消对应的通知栏。 cancelNotificationManager.cancelAll()这个方法是取消所有之前发布过的通知栏,比较暴力一点哈。

    转载于:https://www.cnblogs.com/wangziqiang/p/4287454.html

    展开全文
  • Android 弹无虚发之第四弹:你应该掌握的Notification(Notification的通知栏常驻、Notification的各种样式、Notification点击无效) 标签: Notification通知栏TaskStackBuilderandroidstyle 2014-02-25 18:...

    Android 弹无虚发之第四弹:你应该掌握的Notification(Notification的通知栏常驻、Notification的各种样式、Notification点击无效)

    标签: Notification通知栏TaskStackBuilderandroidstyle
     9826人阅读 评论(11) 收藏 举报
     分类:

    Android的Notification是android系统中很重要的一个机制,产品人员常常利用通知栏的方式,跟用户进行弱沟通。拥有推送通知的app要比没有此类功能的app活跃率要高很多。另外类似于墨迹天气,清理大师等app,也会将通知栏常驻,利用自定义的布局,方便用户及时快捷的查看所需的信息和使用快捷的功能。所以Notification的使用,也在开发当中,使用的越来越频繁。今天我就来跟大家分享一下Notification的常用事项。

    我不了解大家平时怎么使用Notification,我常常看到有些人的代码是这样写的:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. Notification notification=new Notification(notificationIcon, notificationTitle, when);    
    2.             
    3.         notification.defaults=Notification.DEFAULT_ALL;    
    4.             
    5.         Intent intent=new Intent(MainActivity.this,SecondActivity.class);    
    6.         PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this0, intent, 0);    
    7.         notification.setLatestEventInfo(this,"测试展开title""测试展开内容",pendingIntent);   
    8. 。。。。。。。。。。。。。  

    具体的代码我就不贴全了,因为大家如果注意IDE的提示的话,就会发现,其实这是一种不推荐的用法,API的支持已经过时了。最新的Notification的用法,是推荐使用V4包下的NotificationCompat.Builder,利用它,进行各种设置,具体的用法先别着急,我们慢慢道来。

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. NotificationCompat.Builder notifyBuilder = new NotificationCompat.Builder(  
    2.         this);  
    首先,我们需要先初始化一个notifyBuilder,然后利用它的各种set方法,进行相关设置,具体的设置,我们参考下图:

    图示中的序号1,叫做Content title,通过这个方法来设置:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. notifyBuilder.setContentTitle("This is My Notification");  

    图示中的序号3,叫做Content text,利用下面的方法来设置:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. notifyBuilder.setContentText("Hello World");  
    图示中的需要5,叫做Small icon,利用下面的方法来设置:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. notifyBuilder.setSmallIcon(R.drawable.small);  
    这三个参数的设定是必须的,每次调用Notification,必须得设定这三个参数。除去这三个以外,另外的2,4,6区域,分别是Large Icon,Content Info,Time,设置方法如下所示:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. // 如果不设置LargeIcon,那么系统会默认将上面的SmallIcon显示在通知选项的最左侧,右下角的小图标将不再显示  
    2. Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bigicon);  
    3. notifyBuilder.setLargeIcon(bitmap);  
    4. // 这里用来显示右下角的数字  
    5. notifyBuilder.setNumber(10);  
    6. notifyBuilder.setWhen(System.currentTimeMillis());  

    以上就是关于Notification的基本设置,下面,我们继续看看其它方面的设置,直接上代码:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. // 将AutoCancel设为true后,当你点击通知栏的notification后,它会自动被取消消失  
    2.         notifyBuilder.setAutoCancel(true);  
    3.         // 将Ongoing设为true 那么notification将不能滑动删除  
    4.         // notifyBuilder.setOngoing(true);  
    5.         // 从Android4.1开始,可以通过以下方法,设置notification的优先级,优先级越高的,通知排的越靠前,优先级低的,不会在手机最顶部的状态栏显示图标  
    6.         notifyBuilder.setPriority(NotificationCompat.PRIORITY_MAX);  
    7.         // notifyBuilder.setPriority(NotificationCompat.PRIORITY_MIN);  
    8.   
    9.         notifyBuilder.setTicker("Hi,Notification is here");  
    10.           
    11.         // Uri uri =  
    12.         // Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.cat);  
    13.         // Uri uri = Uri.parse("file:///mnt/sdcard/cat.mp3");  
    14.         // notifyBuilder.setSound(uri);  
    15.   
    16.         // Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。  
    17.         // Notification.DEFAULT_SOUND:系统默认铃声。  
    18.         // Notification.DEFAULT_VIBRATE:系统默认震动。  
    19.         // Notification.DEFAULT_LIGHTS:系统默认闪光。  
    20.         // notifyBuilder.setDefaults(Notification.DEFAULT_ALL);  
    21.   
    22.         NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    23.         mNotificationManager.notify(NOTIFY_ID, notifyBuilder.build());  
    如上面的注释所示,如果你想点击完notification后,该通知自动消失,那么你就需要调用setAutoCancel(boolean b)这个方法,并且将其设为true,如果你想让你的通知栏常驻,用户无法滑动删除,也不能通过手机的清除键 删除,类似于墨迹天气等app的通知栏,那么你可以设置setOngoing方法,也设为true,这样,通知栏只能通过代码调用cancel方法才能消失,很霸道地,有木有!另外,从Android4.1时代开始,系统允许设置Notification的优先级,对于优先级高的通知,会排在 通知栏的前面,并在会在手机最上端的Status Bar显示一个图标,如果优先级设定的较低,那么就会被系统显示在通知栏的后面,并且Status Bar不再显示相应的图标,设置优先级的方法,就是调用setPriority(int p)。另外,当启动通知栏的时候,我们常常可以在手机最上端的Status Bar上面,会闪现一段提示语,用来提醒用户,这段提示语具体显示的文字,就是靠setTicker() 这个方法来实现的。除此之外,我们还可以设置,推送通知时的铃声、震动效果,闪光灯效果等等,具体的我就不一一列举了,参考上面的示例代码即可,需要注意一点的是,设置通知的铃声,除去调用系统自带的外,还有两种方式,分别是调用SD卡中的声音文件和项目工程自带的声音文件,这两种方式都需要用到Uri的地址,具体如何获取这两种的Uri,我已经在上面的代码中,写的很详细了,大家可以参考上面的代码,在自己的项目中实验一下。

    说了这么多,还有最重要的一点没有讲,那就是在你设置完notification的各种属性后,你需要启动这个notification,否则就前功尽弃了,启动的方法,如上面的示例代码所示,你需要先获取一个NotificationManager的实例,然后调用notify的方法,notifyBuilder.build()这个方法,可以实例化一个notification的实例,另外,你还需要为这个notification分配一个独一无二的的id号,将来notification的更新和删除,都是依靠这个id号来做索引对应的。

    有时候,我们会涉及到这么一个需求,那就是,产品设计,希望我们能够监听notification的销毁,意思就是说,当用户手动滑动通知将其删除或者通过手机的删除按钮将其清空时,我们希望可以捕获到这一信息,并作出相应的处理。比如说,我们在通知栏发送了一个通知,用来更新一个资源的下载进度,当用户删除这个通知后,我们希望可以监听到这一变化,作出相应的处理,比如取消下载,比如重新下载等等,那么,应该如何监听取消的行为呢?请看代码:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. Intent deleteIntent = new Intent(this, DeleteService.class);  
    2. int deleteCode = (int) SystemClock.uptimeMillis();  
    3. PendingIntent deletePendingIntent = PendingIntent.getService(this,  
    4.         deleteCode, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    5. notifyBuilder.setDeleteIntent(deletePendingIntent);  
    我们给notifyBuilder设置一个DeleteIntent,这里指向了一个service,当删除的行为发生后,系统就会启动这个service,我们就可以在这个service中,做相应的逻辑处理了,当然,这里我只是举了一个例子,用来启动service,大家也可以将Intent指向一个Activity或者一个广播,不过PendingIntent.getService()这个方法,就需要换成PendingIntent.getActivity()或者PendingIntent.getBroadCast()这两个方法。

    上面的内容,我们大概了解了如何给notification设定显示的内容,和如何监听销毁的行为。但是常常,我们会发现,除了以上功能外,我们经常遇见的情形时,当我们点击了一个notification后,就会自动打开一个页面,展示出信息来源的具体页面,接下来,我们就针对这种情况,来看看代码是如何控制的。

    刚刚提到的自动跳转页面的功能,看似很简单的一个逻辑,其实也包含了各种逻辑处理情况,其中最主要的是有两种:

    一:当我们处在手机桌面主屏的时候,突然来了一条邮箱的信息,来了一封新邮件,我们点击通知栏,系统会为我们打开最新收到的邮件,当我们看完邮件后,按返回键,我们并不会马上回到手机桌面的主屏上,而是先返回到收件箱界面,然后再返回到邮件APP的主界面,然后再返回到手机桌面的主屏上,它是按照邮件APP的页面队列返回的。

    二:还是举刚才那个例子,当我们收到新邮件的通知后,我们点击打开新收到的邮件,当我们阅读完之后,我们想要点击返回键,立刻返回到我们刚刚所处的界面,继续进行刚才还在进行的任务。

    这两种情况,在产品设计中,常常出现,所以我们也要想办法去实现,那么如何去实现这两种情况呢,我们一个一个来看。

    首先请看第一种情况的代码:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. Intent notifyIntent = new Intent(this, NotifyRegularActivity.class);  
    2. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);  
    3. stackBuilder.addParentStack(NotifyRegularActivity.class);  
    4. stackBuilder.addNextIntent(notifyIntent);  
    5. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6. int requestCode = (int) SystemClock.uptimeMillis();  
    7. PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(  
    8.         requestCode, PendingIntent.FLAG_UPDATE_CURRENT);  
    9. notifyBuilder.setContentIntent(resultPendingIntent);  
    我们继续贴上AndroidManist.xml的配置代码:

    [html] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. <activity  
    2.             android:name="com.example.notificationtest.MainActivity"  
    3.             android:label="@string/app_name" >  
    4.             <intent-filter>  
    5.                 <action android:name="android.intent.action.MAIN" />  
    6.   
    7.                 <category android:name="android.intent.category.LAUNCHER" />  
    8.             </intent-filter>  
    9.         </activity>  
    10.         <activity  
    11.             android:name="com.example.notificationtest.OtherActivity"  
    12.             android:label="OtherActivity"  
    13.             android:parentActivityName="com.example.notificationtest.MainActivity" >  
    14.             <meta-data  
    15.                 android:name="android.support.PARENT_ACTIVITY"  
    16.                 android:value="com.example.notificationtest.MainActivity" />  
    17.         </activity>  
    18.         <activity  
    19.             android:name="com.example.notificationtest.NotifyRegularActivity"  
    20.             android:label="NotifyRegularActivity"  
    21.             android:parentActivityName="com.example.notificationtest.OtherActivity" >  
    22.             <meta-data  
    23.                 android:name="android.support.PARENT_ACTIVITY"  
    24.                 android:value="com.example.notificationtest.OtherActivity" />  
    25.         </activity>  
    好,我们来分析一下上面的代码。首先我们设置了一个Intent,将其指向 NotifyRegularActivity,然后我们用到了TaskStackBuilder,它可以用来控制界面返回的导航堆栈。

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);  
    2. stackBuilder.addParentStack(NotifyRegularActivity.class);  
    3. stackBuilder.addNextIntent(notifyIntent);  
    我们利用这段代码,首先实例化了一个TaskStackBuilder,然后调用addParentStack()addNextIntent(),设置它的返回堆栈和跳转页面,跳转页面的Intent很好理解,跟大家平时的设置方式是一样的,那么它的返回堆栈是如何控制的呢?这就需要上面xml配置文件的配置了,大家请看,在上面的配置文件中,一共有三个Activity,分别是MainActivity,OtherActivity,和NotifyRegularActivity,其中NotifyRegularActivity就是我们点击通知栏后,要自动跳转的界面。在配置文件当中,
    我们给后面两个Activity,设置了这么一个属性android:parentActivityName,它指的就是该activity的返回路径,因为刚刚我们在调用addParentStack()这个方法的时候,设置的参数是NotifyRegularActivity.class所以根据上面配置文件的配置内容,那么它的返回堆栈的顺序就是:


    需要注意的是,为了向下兼容版本,我们在设置android:parentActivityName这个属性的时候,还需要在配置文件中,为每个Activity进行如下设置:

    [html] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. <meta-data  
    2.     android:name="android.support.PARENT_ACTIVITY"  
    3.     android:value="com.example.notificationtest.MainActivity" />  
    具体的value的指向,就需要你自己设定了,总之,它指向了该activity的返回页面。对TaskStackBuilder设置完成之后,我们再通过下面的代码获取PendingIntent,,然后赋值给notifyBuilder即可:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    2. int requestCode = (int) SystemClock.uptimeMillis();  
    3. PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(  
    4.         requestCode, PendingIntent.FLAG_UPDATE_CURRENT);  
    5. notifyBuilder.setContentIntent(resultPendingIntent);  
    这里有两点需要注意一下:

    1:PendingIntent.FLAG_UPDATE_CURRENT这个参数一般有四种选择分别是:

    FLAG_CANCEL_CURRENT:如果构建的PendingIntent已经存在,则取消前一个,重新构建一个。
    FLAG_NO_CREATE:如果前一个PendingIntent已经不存在了,将不再构建它。
    FLAG_ONE_SHOT:表明这里构建的PendingIntent只能使用一次。
    FLAG_UPDATE_CURRENT:如果构建的PendingIntent已经存在,那么系统将不会重复创建,只是把之前不同的传值替换掉。

    如果没有特殊要求的话,我们常常会使用FLAG_UPDATE_CURRENT这个参数来构造PendingIntent,但是这样常常会引发第二个问题,什么问题呢?呵呵~

    2:如上所述我们使用FLAG_UPDATE_CURRENT这个参数后,常常会发现,我们点击通知栏后,系统没有响应,时灵时不灵的,很是忧郁,这是为什么呢?原来使用FLAG_UPDATE_CURRENT这个参数后,系统不会重新创建新的PendingIntent,这样一来,如果你传递的Intent的 extra参数没有变化的话,那么系统就会认为你没有发送新的PendingIntent,这样就不会重新响应你的点击事件。一般情况下,为了能够区分每次的PendingIntent不一样,我们常常会在构造Intent的时候,设置不同的Action或者Extra值,这样一来,及时是使用FLAG_UPDATE_CURRENT这个参数,系统也会因为传值参数的变化而去响应每次的点击跳转事件。不过这种解决方法还是有些麻烦,有时候,我们根本不需要传递额外的Aciton或者参数值,这该怎么办呢?哈哈,解决代码已经在上面的代码中写出来了,在stackBuilder.getPendingIntent(requestCode, PendingIntent.FLAG_UPDATE_CURRENT)这个方法中,我们注意到第一个参数,这里,我们只要为这个参数设置一个独一无二的标识,那么刚刚提到的点击无响应的问题就迎刃而解了,我平时的设置办法就是利用这段代码:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. int requestCode = (int) SystemClock.uptimeMillis();  
    获取发布通知时的时间,将它作为requestCode,这样就可以避免这些问题了。不过如果你要是使用FLAG_CANCEL_CURRENT这个参数的话,就会每次都创建一个新的,那么刚刚提到的这两个问题,也都不存在了,具体怎么用,看你实际的业务要求了。

    上面的讲解,我们就可以解决刚刚讨论的第一种情形了,下面我们来说一下,第二种情形,也就是点击返回键后,直接返回刚刚任务所处的界面,看看这个如何实现。来,看代码:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    2.         notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    3.                 | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    4.         // Creates the PendingIntent  
    5.         // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6.         int requestCode = (int) SystemClock.uptimeMillis();  
    7.         PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    8.                 notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    9.         notifyBuilder.setContentIntent(pendIntent);  
    继续看配置文件的设置:

    [html] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. <activity  
    2.     android:name="com.example.notificationtest.NotifySpecialActivity"  
    3.     android:excludeFromRecents="true"  
    4.     android:label="NotifySpecialActivity"  
    5.     android:launchMode="singleTask"  
    6.     android:taskAffinity="" >  
    7. </activity>  
    在代码中,我们设置NotifySpecialActivity为我们要跳转的界面,然后在xml的配置文件中,我们重点设置了这三个属性:android:excludeFromRecents="true",android:launchMode="singleTask",android:taskAffinity="",第一个属性的设置,是将该界面从最近任务栏当中移除,防止用户通过最近任务栏而进入到该界面,这样一来,只能通过通知来的点击来进入。第二种属性的设置就很常见了,是为了防止该界面存在的情况下,重复创建该Activity,第三属性是为了配置代码中的这段来设置的:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    2.         | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    这样的作用是为此次跳转界面的行为重新分配一个任务堆栈,而不从属于其它的任务堆栈,这样的话,当我们点击返回键后,就可以直接返回到刚刚用户所处的任务界面了。由于这里我们不再使用TaskStackBuilder,所以最后需要调用PendingIntent.getActivity(this, requestCode,notifyIntent,PendingIntent.FLAG_UPDATE_CURRENT)这个方法来构造一个PendingIntent,然后赋值给notifyBuilder。这样,刚刚讨论过的第二种情形,我们就可以解决了,相比较第一种来说,这种解决方式更为简洁,不过处理的业务逻辑也不一样,大家斟酌而定。


    Notificaton在平时的产品设计中,常常用来显示跟网络交互的进度,我们常常的做法是在通知栏上面,显示一个进度条,用来更新交互的进度,这个的实现方式很简单,主要依赖于mBuilder.setProgress()这个方法,具体的做法可以参考下面的代码:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1.     final NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    2.     final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(  
    3.             this);  
    4.     mBuilder.setContentTitle("Picture Download")  
    5.             .setContentText("Download in progress")  
    6.             .setSmallIcon(R.drawable.small);  
    7.     new Thread(new Runnable() {  
    8.         @Override  
    9.         public void run() {  
    10.             int incr;  
    11.             for (incr = 0; incr <= 100; incr += 5) {  
    12.                 // mBuilder.setProgress(100, incr, false);  
    13.                 mBuilder.setProgress(00true);  
    14.                 mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    15.                 try {  
    16.                     Thread.sleep(1 * 1000);  
    17.                 } catch (InterruptedException e) {  
    18.                 }  
    19.             }  
    20.             mBuilder.setContentText("Download complete").setProgress(00,  
    21.                     false);  
    22.             mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    23.         }  
    24.     }  
    25.     // Starts the thread by calling the run() method in its Runnable  
    26.     ).start();  
    27. }  
    在代码中,我们开启了一个线程,里面进行20次for循环,每次循环都会调用setProgress这个方法,因为每次调用的NOTIFY_ID都是相同的,所以系统会根据这个ID来更新notification的进度而不会重新创建一个新的Notification。setProgress这个方法一共有两种方法,一种是这样的:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. mBuilder.setProgress(100, incr, false);  
    第一个参数指的的是进度的总长度,第二个参数是目前进行的长度,然后将第三个参数设为false,我们可以看到的效果就如下图:



    我们可以看见进度条的确切位置和进度情况。还有一种使用方法是这样的:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. mBuilder.setProgress(00true);  
    将前两个参数都设为0,然后将最后这个参数设为true,这样的进度条效果是一种连续模糊的,适合进行时间不确定的网络连接,效果图如下:


    最后,当我们的任务完成后,我们需要取消进度条的显示,这时候我们需要调用如下方法:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. mBuilder.setContentText("Download complete").setProgress(00,  
    2.         false);  
    设置一个任务完成后的文本描述,然后将setProgress的前两个参数都设为0,最后一个参数设为false,这样进度条就不会在通知栏上面显示了,效果图:



    Notification的进度条的使用方法就是这些,如果大家平时用的不多,最好还是根据上面贴出的源代码,自己联系一遍,稍候我也会把本次工程的源代码打包,上传到CSDN的资源库中,供大家参考。


    上面跟大家介绍的,都是Notification的一种常规样式,自从Android4.1之后,谷歌引入了一种新的样式,叫做Big View,效果就是相对于传统的Notification,它的显示区域更大,显示的内容也更多一些。关于Big View,谷歌支持了三种模式,分别是:

    Big picture style 和 Big text style 还有 Inbox style

    在这里,我向大家重点介绍一下第一种样式和第三种样式,先给大家贴一下,这两种的效果图:

    Big picture style


    Inbox style



    我们来看看代码是如何设置Big picture style 的:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(  
    2.         this).setSmallIcon(R.drawable.small)  
    3.         .setContentTitle("Picture tracker")  
    4.         .setContentText("Picture received");  
    5. NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle();  
    6. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bigpic);  
    7. picStyle.bigPicture(bitmap);  
    8. mBuilder.setStyle(picStyle);  
    9. NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    10. mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    首先我们实例化一个NotificationCompat.BigPictureStyle,然后读取要展示的图片资源,调用picStyle.bigPicture(bitmap)这个方法设置图片,最后调用notifyBuilder的mBuilder.setStyle(picStyle)方法,设置好BIG VIEW的样式,就OK了,代码简单的令人发指,我就不多解释了,大家参考上面的示例代码即可。

    接下来,我们再看看Inbox style这种样式是如何设置的:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(  
    2.         this).setSmallIcon(R.drawable.small)  
    3.         .setContentTitle("Inbox tracker")  
    4.         .setContentText("Inbox received");  
    5. NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();  
    6. String[] events = new String[6];  
    7. events[0] = "Hello my one world";  
    8. events[1] = "Hello my two world";  
    9. events[2] = "Hello my three world";  
    10. events[3] = "Hello my four world";  
    11. events[4] = "Hello my five world";  
    12. events[5] = "Hello my six world";  
    13. inboxStyle.setBigContentTitle("Inbox tracker details:");  
    14. for (int i = 0; i < events.length; i++) {  
    15.     inboxStyle.addLine(events[i]);  
    16. }  
    17. inboxStyle.setBigContentTitle("Thers are six messages");  
    18. inboxStyle.setSummaryText("It's so easy,right?");  
    19. mBuilder.setStyle(inboxStyle);  
    20. NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    21. mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    唉,代码是不是再简单不过了,我都不好意思班门弄斧的介绍这段代码了。主要声明一下三个方法的使用吧,inboxStyle.addLine(),这个方法是用来设置下图中黄色区域的文字,inboxStyle.setBigContentTitle("Thers are six messages")这个方法是用来设置红色区域的文字内容,inboxStyle.setSummaryText("It's so easy,right?")是用来设置绿色区域的内容显示,其他的基本设置在之前的内容中,都已经介绍了很多了,我就不重复介绍了。



    通过上面的学习,想必大家已经对Notification有了一个比较全面的了解了,最后,我再给大家介绍一种自定义 Notification布局的用法。自定义Notification布局的app有很多,比如像墨迹天气,Clean Master等等,利用自定义布局,将用户所需信息和快捷功能,多样化的展示在通知栏上面,给大家看一下Clean Master的截图:


    其实要是实现这种自定义布局的Notification,非常简单,我们这就给大家展示代码设置和布局配置:

    先看看Java代码:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);  
    2. RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);  
    3. remoteView.setTextViewText(R.id.text, "Custom Text");  
    4. remoteView.setTextViewText(R.id.btn, "Custom Button");  
    5. remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);  
    6.   
    7. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    8. notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    9.         | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    10. // Creates the PendingIntent  
    11. // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    12. int requestCode = (int) SystemClock.uptimeMillis();  
    13. PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    14.         notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
    15. remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);  
    16.   
    17. mBuilder.setSmallIcon(R.drawable.small);  
    18. mBuilder.setContent(remoteView);  
    19. NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    20. mNotifyManager.notify(NOTIFY_ID, mBuilder.build());  
    再来看看xml布局文件是什么样的:

    [html] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="match_parent"  
    4.     android:layout_height="64dp" >  
    5.   
    6.     <ImageView  
    7.         android:id="@+id/image"  
    8.         android:layout_width="wrap_content"  
    9.         android:layout_height="match_parent"  
    10.         android:layout_alignParentLeft="true"  
    11.         android:gravity="center" />  
    12.   
    13.     <TextView  
    14.         android:id="@+id/text"  
    15.         android:layout_width="wrap_content"  
    16.         android:layout_height="match_parent"  
    17.         android:layout_centerInParent="true"  
    18.         android:gravity="center" />  
    19.   
    20.     <Button  
    21.         android:id="@+id/btn"  
    22.         android:layout_width="wrap_content"  
    23.         android:layout_height="wrap_content"  
    24.         android:layout_alignParentRight="true"  
    25.         android:gravity="center" />  
    26.   
    27. </RelativeLayout>  

    我们首先利用下面这行代码去解析上面的布局文件

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);  
    然后根据每个控件的id号进行资源设置:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. remoteView.setTextViewText(R.id.text, "Custom Text");  
    2. remoteView.setTextViewText(R.id.btn, "Custom Button");  
    3. remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);  
    我们也可以为这些控件单独设置点击事件,比如设置Button的点击事件:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);  
    上面第二个参数pendingIntent的获取,在之前的讲解中,已经介绍了好几种方式了,这里我们随便选择一种来实现了:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);  
    2.         notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK  
    3.                 | Intent.FLAG_ACTIVITY_CLEAR_TASK);  
    4.         // Creates the PendingIntent  
    5.         // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode  
    6.         int requestCode = (int) SystemClock.uptimeMillis();  
    7.         PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,  
    8.                 notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);  

    最后,我们要调用下面这段代码,将自定义的RemoteView设置给notifyBuilder,然后调用发送通知的方法就OK了。

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. mBuilder.setContent(remoteView);  


    最后的最后,需要再给大家介绍两个方法,那就是通过代码来取消Notification,咱不能只管杀不管埋啊,哈哈~

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. NotificationManager cancelNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    2. cancelNotificationManager.cancel(NOTIFY_ID);  
    3. cancelNotificationManager.cancelAll();  
    cancelNotificationManager.cancel(NOTIFY_ID)这个方法是根据之前发布通知时,分配的ID号,来取消对应的通知栏。

    cancelNotificationManager.cancelAll()这个方法是取消所有之前发布过的通知栏,比较暴力一点哈。


    以上就是我今天给大家分享的内容,关于Notification的内容,在上面的内容中,可能还没有覆盖完所有的知识点,但是基本上涵盖了我平时工作中用到的几个关键用途,罗哩罗嗦的写了一大篇,可能有些地方没有讲清楚或者我理解的有错误,还希望大家能够帮我指点一二,共同进步。最后,还是老样子,附上本次所有示例代码的下载地址,方便大家调试学习:

    下载地址:http://download.csdn.net/detail/pringlee2011/6960743

    展开全文
  • 另外类似于墨迹天气,清理大师等app,也会将通知栏常驻,利用自定义的布局,方便用户及时快捷的查看所需的信息和使用快捷的功能。所以Notification的使用,也在开发当中, 使用的越来越频繁。今天我就来跟大家...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 339
精华内容 135
关键字:

通知栏常驻