Android之通知的基本用法

首先需要一个NotificationManager()方法来对通知进行管理。
可以调用Context的getSystemService()方法获取到。
getSystemService()方法接收一个字符串参数用于确定获取系统的哪个服务,
这里我们传入Content.NOTIFICATION_SERVICE即可。
因此获取NotificationManager的实例就可以写成:

NotificationManager manager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);

接下来需要使用一个Builder构造器来创建Notification对象,但问题是,几乎Android系统的每一个版本都会对通知这部分功能进行或多或少的修改,API不稳定性问题在通知上面突显的尤为严重。所以使用support库中提供的兼容API。support-v4库中提供了一个NotificationCompat类,使用这个类的构造器来创建Notification对象,就可以保证我们的程序在所有Android系统版本上都能正常工作了,代码如下:

Notification notification = new NotificationCompat.Builder(context).build();

当然,上述代码只是创建了一个空的Notification对象,并没有什么实际作用,我们可以在最终的build()方法之前连缀任意多的设置方法来创建一个丰富的Notification对象,先来看一些最基本的设置:

Notification notification = new NotificationCompat.Builder(context)
		.setContentTitle("This is content title")
		.setContentText("This is content text")
		.setWhen(System.currentTimeMillis())
		.setSmallIcon(R.drawable.small_icon)
		.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.large_icon))
		.build();

上述代码中一共调用了五个设置方法,下面一一解析。

**setContentTitle()**方法用于指定通知的标题内容,下拉系统状态栏就可以看到这部分内容。

**setContentText()**方法用于指定通知的正文内容,同样下拉系统状态栏就可以看到这部分内容。

**setWhen()**方法用于指定通知被创建的时间,以毫秒为单位,当下拉系统状态栏时,这里指定的时间会显示在相应的通知上。

**setSmallIcon()**方法用于设置通知的小图标,注意只能使用纯alpha图层的图片进行设置,小图标会显示在系统状态栏上。

**setLargeIcon()**方法用于设置通知的大图标,当下拉系统状态栏时,都可以看到设置的大图标了。

以上工作都完成之后,只需要调用NottificationManager的nitify()方法就可以让通知显示出来了。

**notify()**方法接收两个参数

第一个参数是id,要保证为每个通知所指定的id都是不同的。

第二个参数则是Notification对象,这里直接将我们刚刚创建好的Notification对象传入即可。因此一个通知就可以写成:

manager.notify(1,notification);

具体的话通过一个例子来看通知到底是什么样:

新建一个NotificationTest项目,并修改activity_main中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="net.nyist.lenovo.notificationtest.MainActivity"
    android:orientation="vertical"
    >

   <Button
       android:id="@+id/send_notice"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Send notice"
       />

</LinearLayout>

布局文件很简单,里面只有一个Send notice按钮,用于发出一条通知。接下来修改MainActivity中的代码:

public class MainActivity extends AppCompatActivity  implements View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button sendNotice = (Button) findViewById(R.id.send_notice);
        sendNotice.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
     switch (v.getId()){
         case R.id.send_notice:
             NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
             Notification notification = new NotificationCompat.Builder(this)
                     .setContentTitle("This is content title")
                     .setContentText("This is content text")
                     .setWhen(System.currentTimeMillis())
                     .setSmallIcon(R.mipmap.ic_launcher)
                     .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                     .build();
             manager.notify(1,notification);
             break;
         default:
             break;
     }
    }
}

运行如下:
这里写图片描述
如果你使用过Android手机,此时应该会下意识地认为这条通知是可以点击的。但是当你去点击它的时候,你会发现没有任何效果。
如果想实现通知的点击效果,我们还需要在代码中进行相应的设置,这就涉及了一个新的概念:PendingIntent

PendingIntent从名字上看起来和Intent有些类似,它们之间也确实存在着不少共同点。比如他们都可以去指明某一个"意图",都可以用于启动活动,启动服务以及发送广播等。不同的是,Intent更加倾向于去立即执行某个动作,而PendingIntent更加倾向于在某个合适时机去执行某个动作,所以,也可以把PendingIntent简单地理解为延迟执行的Intent。

PendingIntent的用法同样很简单,他主要提供了几个静态方法用于获取PendingIntent的实例,可以根据需求来选择是使用getActivity()方法,getBroadcast()方法还是getService()方法。这几个方法所接收的参数都是相同的。

第一个参数依旧是Context,不用多做解释。

第二个参数一般用不到,通常都是传入0即可。

第三个参数是一个Intent对象,我们可以通过这个对象构建出PendingIntent的"意图"。

第四个参数用于确定PendingIntent的行为,有FLAG_ONE_SHOTFLAG_NO_CREATEFLAG_CANCEL_CURRENTFLAG_UPDATE_CURRENT这四种值可选,
每种值的具体含义你可以查看文档,通常情况这个参数传入0就可以了。

这里我查了一下参数的含义可以看一下:

FLAG_ONE_SHOT:
this PendingIntent can only be used once. If set, after send() is called on it, it will be automatically canceled for you and any future attempt to send through it will fail.
利用 FLAG_ONE_SHOT获取的PendingIntent只能使用一次,即使再次利用上面三个方法重新获取,再使用PendingIntent也将失败。

FLAG_NO_CREATE:
if the described PendingIntent does not already exist, then simply return null instead of creating it.
利用FLAG_NO_CREAT获取的PendingIntent,若描述的Intent不存在则返回NULL值.

FLAG_CANCEL_CURRENT:
if the described PendingIntent already exists, the current one is canceled before generating a new one. You can use this to retrieve a new PendingIntent when you are only changing the extra data in the Intent; by canceling the previous pending intent, this ensures that only entities given the new data will be able to launch it. If this assurance is not an issue, consider FLAG_UPDATE_CURRENT.
如果描述的PendingIntent已经存在,则在产生新的Intent之前会先取消掉当前的。你可用使用它去检索新的Intent,如果你只是想改变Intent中的额外数据的话。通过取消先前的Intent,可用确保只有最新的实体可用启动它。如果这一保证不是问题,考虑flag_update_current。

FLAG_UPDATE_CURRENT:
if the described PendingIntent already exists, then keep it but its replace its extra data with what is in this new Intent. This can be used if you are creating intents where only the extras change, and don’t care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.
最经常使用的是FLAG_UPDATE_CURRENT,因为描述的Intent有 更新的时候需要用到这个flag去更新你的描述,否则组件在下次事件发生或时间到达的时候extras永远是第一次Intent的extras。

PendingIntent有了一定的了解后,我们再回过头来看一下,NotificationCompat.Builder。这个构造器还可以再连缀一个**setContentIntent()**方法,接收的参数正是一个PengdingIntent对象,因此,这里就可以通过PengdingIntent构建出一个延迟执行的“意图”,当用户点击这条通知时就会执行相应的逻辑。

下面来优化一下上面的项目,给刚才的通知加上点击功能,让用户点击它的时候启动另一个活动。

首先需要准备好另一个活动,要新建一个Activity,命名为NotificationActivity,布局起名为notification_layout。然后修改notification_layout.xml中的代码,如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="net.nyist.lenovo.notificationtest.NotificationActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="24sp"
        android:text="This is notification layout"
        />

</RelativeLayout>

下面修改MainActivity中的代码,加入点击功能:

public class MainActivity extends AppCompatActivity  implements View.OnClickListener{

········

    @Override
    public void onClick(View v) {
     switch (v.getId()){
         case R.id.send_notice:
             Intent intent = new Intent(this,NotificationActivity.class);
			//先创建Intent表达出我们想要启动NotificationActivity的"意图"
             PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
			//得到PendingIntent的实例。
             NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
             Notification notification = new NotificationCompat.Builder(this)
                     .setContentTitle("This is content title")
                     .setContentText("This is content text")
                     .setWhen(System.currentTimeMillis())
                     .setSmallIcon(R.mipmap.ic_launcher)
                     .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                     .setContentIntent(pi)
					 //在这里调用setContentIntent()方法,把它作为参数传入。
                     .setAutoCancel(true)
                     .build();
             manager.notify(1,notification);
             break;
         default:
             break;
     }
    }
}

通知点击事件

可以发现状态上的通知图标还没有消失呢,是这样,如果我们没有在代码中对该同志进行取消,它会一直显示在系统的状态栏上,解决的方法有两种,一种是在NotificationCompat.Builder中再连缀一个setAutoCancel()方法,一种是显示地调用NotificationManagrer的cancle()方法将它取消。两种方法可以学习。

第一种方法:
Notification notification = new NotificationCompat.Builder(this)
·········
.setAutoCancel(true)
.build();

可以看到,setAutoCancel()方法传入true,就表示当点击了这个通知的时候,通知会自动取消。

第二种方法:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    **NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    manager.cancel(1);**
    Button sendNotice = (Button) findViewById(R.id.send_notice);
    sendNotice.setOnClickListener(this);
}

这里我们在cancel()方法中传入了1,这个1是当时我们给这条通知设置的id就是1 ,因此,如果你想取消哪条通知,在cancel()方法中就传入该通知的id机就行了。

#通知的进阶技巧

先来看看setSound()方法,它可以在通知发出的时候放一段音频,这样就能够更好的告诉用户有通知到来。setSound()方法接收一个Uri参数,所以在指定
音频文件的时候还需要先获取到音频文件对应的URI。比如说,每个手机的/system/media/audio/ringtones目录下都有很多的音频文件,我们可以从中选一个音频文件,那么在代码中就可以这样指定:

//播放音频
.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))

//手机振动
.setVibrate(new long[]{0,1000,1000,1000})
想要控制手机振动还需要声明权限,因此,我们还得编辑AndroidManifest.xml文件,加入如下声明:

//闪光灯
.setLights(Color.GREEN,1000,1000)

第一个参数用于指定LED灯的颜色,第二个参数用于指定LED灯亮起的时长,以毫秒为单位,第三个参数用于指定LED灯暗去的时长,也是以毫秒为单位。

当然如果你不想进行那么多繁杂的设置,也可以直接使用通知的默认效果,它会根据当前手机的环境来决定播放什么铃声,以及如何振动,写法如下:

				.setDefaults(NotificationCompat.DEFAULT_ALL)

注意以上所涉及的进阶技巧都要在手机上运行才能看到效果,模拟器是无法表现出振动以及LED灯闪烁等功能。

通知的高级进阶:

继续观察NotificationCompat.Builder这个类,有更强大的API的用法。
先来看看setStyle()方法,这个方法允许我们构建出富文本的通知内容。也就是说通知中不光可以有文字和图标,还可以包含更多的东西。setStyle()方法接收一个NotificationCompat.Builder.Style参数,这个参数就是用来构建具体的富文本信息的,如长文字、图片等。在开始使用setStyle()方法之前,我们先来
做一个试验,之前的通知内容都比较短,如果设置成很长的文字会是什么效果,下面运行一下看看:
长文通知

可以看到,通知内容是无法显示完整的,多余的部分会用省略号来代替。其实这也是很正常的,因为通知的内容本来就应该言简意赅,详细内容放到点击后打开的活动当中会更加适合。

但是如果你真的非常需要在通知当中显示一段长文字,Android也是支持的,通过setStyle()方法就可以做到,具体写法如下:

.setStyle(new android.support.v4.app.NotificationCompat.BigTextStyle().bigText("Learn how to build notifications,send and sync data,and use voice actions.Get the official Android IDE and deceliper tools to build apps for Android."))

我们在setStyle()方法中创建了一个NotificationCompat.BigTextStyle对象,这个对象就是用于封装长文字信息的,我们调用它的bifText()方法并将文字内容传入就可以了。
再次运行效果如图:
setStyle长文

除了显示长文字之外,通知里还可以显式一张大图片,具体用法也是基本相似的:

 .setStyle(new android.support.v4.app.NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(),R.drawable.big_image)))

这里仍然是调用的setStyle()方法,这次我们在参数中创建了一个NotificationCompat.BigPictureStyle对象,这个对象就是用于设置大图片的,然后调用它的bigPicture()方法并将图片传入。这里我事先准备好了一张图片,通过BitmapFactory的decodeResource()方法将图片解析成Bitmap对象,,再传入到bigPicture()方法中就可以了。

这样setStyle()方法中的重要内容基本掌握。

接下来学习一下setPriority()方法,它可以用于设置通知的重要程度。

**setPriority()**方法接收一个整型参数用于设置这条通知的重要程度,一共有5个常量值可选:

PRIORITY_DEFAULT表示默认的重要程度,和不设效果是一样的。

PRIORITY_MIN表示最低的重要程度,系统可能只会在特定的场景才显示这条通知,比如用户下拉状态栏的时候,

PRIORITY_LOW表示较低的重要程度,系统可能会将这类通知缩小,或改变其显示的顺序,将其排在更重要的通知之后;

PRIORITY_HIGH表示较高的重要程度,系统可能会将这类通知放大,或改变其显示的顺序,将其排在比较靠前的位置,

PRIORITY_MAX表示最高的重要程度,这类通知消息必须要让用户立刻看到,甚至需要用户做出响应操作。具体写法如下:
//最高重要程度

     .setPriority(NotificationCompat.PRIORITY_MAX)

这里我们将通知的重要程度设置成了最高,表示这是一条非常重要的通知,要求用户必须立刻看到。现在运行程序如下:
最高级别通知
可以看到,这次的通知不是在系统状态栏显示一个小图标了,而是弹出了一个横幅,并附带了通知的详细内容,表示这是一条非常重要的通知。

猜你喜欢

转载自blog.csdn.net/i_nclude/article/details/77688566