Android 之 Notification 必须掌握知识点

SamuelMccar 7年前
   <p><strong>创建并发送一个系统通知</strong></p>    <p>activity_main.xml</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      android:layout_width="match_parent"      android:layout_height="match_parent"      tools:context="com.example.mu_16jj.notificationdemo.MainActivity">      <TextView          android:id="@+id/tv_send_notification"          android:layout_width="wrap_content"          android:layout_height="35dp"          android:layout_centerInParent="true"          android:gravity="center"          android:background="@color/colorAccent"          android:text="send notification"          android:textSize="16sp" />  </RelativeLayout></code></pre>    <p>很简单的布局,就一个 TextView 利用其点击事件来发送通知。</p>    <p>创建 Notification</p>    <pre>  <code class="language-java">private void createNotification() {          notification = new NotificationCompat.Builder(MainActivity.this)                  .setContentTitle("Notification title")                  .setTicker("Ticker method function...")                  .setContentText("Notification content text")                  .setSubText("subtext...")                  .setWhen(System.currentTimeMillis())                  .setSmallIcon(R.mipmap.ic_launcher_round)                  .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon))                  .build();      }</code></pre>    <p>通过 NotificationCompat.Build 来构建一个 Notification 对象,并设置一系列属性(每个属性对应的效果后面展示)。</p>    <p>发送按钮监听</p>    <pre>  <code class="language-java">notificationManager.notify(1, notification);</code></pre>    <p>这里需要说明的是,Notification 的发送还是由 NotificationManager 来管理的,第一个参数用来标识一个唯一的 Notification;第二个参数就是需要发送的 Notification 对象。我们在 onCreate 方法中通过以下代码初始化了通知管理器对象:</p>    <pre>  <code class="language-java">notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);</code></pre>    <p>运行效果</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d612210c7d59ee348da6cc33bda54c2c.png"></p>    <p>通知效果</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/cb34b106a791db97c30d1ed66135e397.png"></p>    <p>属性介绍</p>    <p>创建通知时的一些基本属性就利用效果图解释完了,其中的 setTicker 需要真机运行才可以看到效果。</p>    <p>可是,这个时候我们点击这条通知后,该通知一直在系统状态栏,既没有消失,也没有页面跳转,这并不是我们想要的效果,所以下面就来实现点击通知跳转页面,这里以系统提供的登录 Activity 为目的界面。</p>    <ul>     <li> <p><strong>实现点击跳转界面</strong></p> </li>    </ul>    <p>修改我们创建通知的方法</p>    <pre>  <code class="language-java">private void createNotification() {          Intent intent = new Intent(this, LoginActivity.class);          PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);          notification = new NotificationCompat.Builder(MainActivity.this)                  .setContentTitle("Notification title")                  .setContentText("Notification content text")                  .setSubText("subtext...")                  .setWhen(System.currentTimeMillis())                  .setSmallIcon(R.mipmap.ic_launcher_round)                  .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon))                  .setContentIntent(pendingIntent)                  .setAutoCancel(true)                  .build();      }</code></pre>    <p>可以看到,这里增加了一个 setContentIntent 方法,该方法接收一个 PendingIntent 参数,而获取该实例则可以有三种途径:getActivity(),getBroadcast(),getService();这几个方法所接收的参数都是相同的,第一个是上下文,第二个参数一般很少使用,传 0 即可,第三个参数便是点击通知需要跳转的 Intent 意图对象(LoginActivity直接使用 AS 提供的模板),第四个参数用于确定 PendingIntent 的行为,有 4 种植可选:FLAG_ONE_SHOT,FLAG_NO_CREATE,CANCEL_CURRENT 和 FLAG_UPDATE_CURRENT。</p>    <p>运行效果</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/683f5c94534c72b5a469003355e44aa2.gif"></p>    <p><strong>主要常量</strong></p>    <p>FLAG_CANCEL_CURRENT:如果当前系统中已经存在一个相同的 PendingIntent 对象,那么就将先前已有的 PendingIntent 取消,然后重新生成一个 PendingIntent 对象。</p>    <p>FLAG_NO_CREATE:如果当前系统中不存在相同的 PendingIntent 对象,系统将不会创建该 PendingIntent 对象而是直接返回 null。</p>    <p>FLAG_ONE_SHOT:该 PendingIntent 只作用一次。在该 PendingIntent 对象通过send() 方法触发过后,PendingIntent 将自动调用 cancel() 进行销毁,那么如果你再调用 send() 方法的话,系统将会返回一个 SendIntentException。</p>    <p>FLAG_UPDATE_CURRENT:如果系统中有一个和你描述的 PendingIntent 对等的PendingInent,那么系统将使用该 PendingIntent 对象,但是会使用新的 Intent 来更新之前 PendingIntent 中的 Intent 对象数据,例如更新 Intent 中的 Extras。</p>    <p><strong>PendingIntent 和 Intent</strong></p>    <p>PendingIntent 是一个特殊的 Intent,主要区别是 intent 是立马执行,PendingIntent 是待确定的 Intent。PendingIntent 的操作实际上是传入的 intent 的操作。使用 pendingIntent 的目的主要是用于所包含的 intent 执行是否满足某些条件。</p>    <ul>     <li><strong>实现点击通知后,这条通知从系统状态栏消失</strong></li>    </ul>    <p>有两种办法,一种是给 Notification 设置</p>    <pre>  <code class="language-java">setAutoCancel(true)</code></pre>    <p>另一种是通过通知管理器调用 cancel 方法,该方法有一个参数,就是我们前面发送的时候设置的唯一标识。</p>    <p><strong>通知,设置特效</strong></p>    <p>我们常见的手机 APP 当有推送消息或者电话之类的通知时,我们的手机 LED 灯会亮起来,而且颜色也会不一样,有时候还会有声音,或者震动之类的,下面就来学习这些方法,这里我通过监听手机锁屏的广播来发送通知(效果会更好),不再使用上面的按钮来发送(锁屏速度快的话效果还是可以看到的)。</p>    <p>创建通知代码</p>    <pre>  <code class="language-java">private void createNotification() {          Intent intent = new Intent(this, LoginActivity.class);          PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);          notification = new NotificationCompat.Builder(MainActivity.this)                  .setContentTitle("Notification title")                  .setContentText("Notification content text")                  .setSubText("subtext...")                  .setWhen(System.currentTimeMillis())                  .setSmallIcon(R.mipmap.ic_launcher_round)                  .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon))                  // 跳转界面 系统状态栏通知消失                  .setContentIntent(pendingIntent)                  .setAutoCancel(true)                  // 收到通知时播放声音并震动                  .setDefaults(NotificationCompat.DEFAULT_SOUND) // 默认通知声音  //                .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))                  .setVibrate(new long[]{0, 1000, 1000, 1000})                  // LED 灯颜色                  .setLights(Color.RED, 1000, 1000)                  // 根据手机的当前环境使用默认  //                .setDefaults(NotificationCompat.DEFAULT_ALL)                  .build();      }</code></pre>    <p>这里的注释已经很清楚了,需要注意的是震动是需要权限的:</p>    <pre>  <code class="language-java"><uses-permission android:name="android.permission.VIBRATE" /></code></pre>    <p>广播接收器</p>    <pre>  <code class="language-java">/**       * 监听手机锁屏       */      public class MyReceiver extends BroadcastReceiver {            @Override          public void onReceive(Context context, Intent intent) {              if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {                  notificationManager.notify(1, notification);              }          }      }</code></pre>    <p>关注注册广播问题,请看《 <a href="/misc/goto?guid=4959747034134038084" rel="nofollow,noindex"> <strong>Android 广播介绍以及使用示例</strong> </a> 》</p>    <ol>     <li> <p>高级之 setStyle() 和 setPriority() 方法</p>      <ul>       <li> <p>通知内容支持长文本</p> <pre>  <code class="language-java">.setStyle(new NotificationCompat.BigTextStyle().bigText("The failures and reverses which await men - and one after another sadden the brow of youth - add a dignity to the prospect of human life, which no Arcadian success would do. -- Henry David Thoreau"))</code></pre> <p>运行效果</p> </li>      </ul> </li>    </ol>    <p style="text-align:center"><img src="https://simg.open-open.com/show/c6b4fdddebfb36d4da461b03b849271a.png"></p>    <ul>     <li>通知内容支持大图片 <pre>  <code class="language-java">.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon)))</code></pre> 运行效果</li>    </ul>    <p style="text-align:center"><img src="https://simg.open-open.com/show/ab296dc0e2d3f21700cb3dd4f5b0befd.png"></p>    <ul>     <li> <p>通知优先级</p> <p>通知的优先级共有五个常量值可选:PRIORITY_DEFAULT(默认);PRIORITY_MIN 最低优先级,系统可能在特定场景才会显示这条通知,比如用户下拉状态栏;PRIORITY_LOW 较低优先级,系统可能会将这类通知缩小,或改变其显示的顺序,将其排在更重要的通知之后;PRIORITY_HIGH 表示较高优先级,系统可能会将这类通知放大、改变其显示的顺序,将其排在靠前的位置; PRIORITY_MAX 表示最高的重要通知,这类通知必须要让用户立刻看到,甚至需要用户做出响应操作。</p> <pre>  <code class="language-java">.setPriority(NotificationCompat.PRIORITY_MAX)</code></pre> </li>    </ul>    <p>运行效果(PRIORITY_MAX)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9ae43cdf27851431d83b942d25af1057.png"></p>    <p><strong>自定义布局通知</strong></p>    <p>我们在已有的界面基础上再增加一个 TextView 用它的点击事件来发送自定义通知,自定义通知代码如下:</p>    <pre>  <code class="language-java">/**       * 创建自定义布局通知       */      private void createCustomNotification() {          RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);          remoteViews.setImageViewResource(R.id.iv_cus_notification, R.mipmap.ic_launcher);          remoteViews.setTextViewText(R.id.tv_cus_notification, "Notification of Android");          remoteViews.setTextViewText(R.id.btn_cus_notification, "Button");            cusNotification = new NotificationCompat.Builder(MainActivity.this)                  // 切记,一定要设置,否则通知显示不出来                  .setSmallIcon(R.mipmap.ic_launcher)                  .setContent(remoteViews)                  .setTicker("Custom Notification")                  .setAutoCancel(true)                  .setDefaults(NotificationCompat.DEFAULT_ALL)                  .build();      }</code></pre>    <p>可以看到,相比系统通知的创建,这里多了一个新的 API——RemoteViews. 我们的自定义布局就是通过它来加载,通过它的一系列 setXXX 方法可以给我们的布局中控件设置相关属性,然后通过 Builder 的 setContent 方法将其设置上去,这样我们的自定义通知效果就实现了。</p>    <p>点击事件</p>    <pre>  <code class="language-java">notificationManager.notify(2, cusNotification);</code></pre>    <p>运行效果</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f2dcb75609967082efd4c8b9b694e23a.png"></p>    <p>关于通知的自定义布局从效果就可以看到,很简单,这里不贴出。</p>    <p><strong>注意点</strong></p>    <p>自定义通知布局的可用高度取决于通知视图。普通视图布局限制为 64 dp,扩展视图布局限制为 256 dp。</p>    <p>无论是系统通知还是自定义布局通知,smallIcon 是必须设置的。</p>    <p> </p>    <p> </p>    <p>来自:https://juejin.im/post/58ec1c210ce463006babbba8</p>    <p> </p>