关于Notification通知的一点愚见(自定义通知栏)

来源:互联网 发布:语文试卷编制软件 编辑:程序博客网 时间:2024/06/05 16:08

今天在复习Notification通知栏的时候,好奇翻了一下源码,终于弄懂了PendingIntent在Notification中的机制以及工作流程,这对我研究Activity的启动流程有了一定的帮助。

通知的实现

我们复习一下常规的通知栏是怎么样实现的:

 //声明一个新的Notification,在里面设置参数            Notification notification = new Notification();            notification.icon = R.drawable.ic_launcher;            notification.tickerText = "hello world";            notification.when = System.currentTimeMillis();            notification.flags = Notification.FLAG_AUTO_CANCEL;            Intent intent = new Intent(this, DemoActivity_2.class);            //PendingIntent是延时Intent是指当点击通知栏之后弹出intent指向activity            PendingIntent pendingIntent = PendingIntent.getActivity(this,                    0, intent, PendingIntent.FLAG_UPDATE_CURRENT);            //这里是指给予通知栏一个标准布局            notification.setLatestEventInfo(this, "chapter_5", "this is notification.", pendingIntent);            //声明一个NotificationManager            NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);            //根据ID发送            manager.notify(sId, notification);

第一步:声明好Notification之后,我们要在notification中设置好参数,比如图标,text,时间,flag等等。
第二步:声明一个Intent,接着将Intent放入PendingIntent中。这个时候PendingIntent中我们要将Intent封装如PendingIntent中。
第三步:声明一个NotificationManager之后,调用notify(int id,Notification n)来发送通知请求。

在这里我们可以清晰的知道NotificationManager其实就是发送notification通知相关的参数出发送端的进程之外,那么这里一定用到了进程间的通讯Binder,而发送的数据notification一定是序列化。

public class Notification implements Parcelable

下面是部分参数源码:

    /**     * A timestamp related to this notification, in milliseconds since the epoch.     *     * Default value: {@link System#currentTimeMillis() Now}.     *     * Choose a timestamp that will be most relevant to the user. For most finite events, this     * corresponds to the time the event happened (or will happen, in the case of events that have     * yet to occur but about which the user is being informed). Indefinite events should be     * timestamped according to when the activity began.     *     * Some examples:     *     * <ul>     *   <li>Notification of a new chat message should be stamped when the message was received.</li>     *   <li>Notification of an ongoing file download (with a progress bar, for example) should be stamped when the download started.</li>     *   <li>Notification of a completed file download should be stamped when the download finished.</li>     *   <li>Notification of an upcoming meeting should be stamped with the time the meeting will begin (that is, in the future).</li>     *   <li>Notification of an ongoing stopwatch (increasing timer) should be stamped with the watch's start time.     *   <li>Notification of an ongoing countdown timer should be stamped with the timer's end time.     * </ul>     *     */    public long when;    /**     * The resource id of a drawable to use as the icon in the status bar.     * This is required; notifications with an invalid icon resource will not be shown.     */    public int icon;    /**     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,     * leave it at its default value of 0.     *     * @see android.widget.ImageView#setImageLevel     * @see android.graphics.drawable.Drawable#setLevel     */    public int iconLevel;    /**     * The number of events that this notification represents. For example, in a new mail     * notification, this could be the number of unread messages.     *     * The system may or may not use this field to modify the appearance of the notification. For     * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was     * superimposed over the icon in the status bar. Starting with     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by     * {@link Notification.Builder} has displayed the number in the expanded notification view.     *     * If the number is 0 or negative, it is never shown.     */    public int number;    /**     * The intent to execute when the expanded status entry is clicked.  If     * this is an activity, it must include the     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires     * that you take care of task management as described in the     * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back     * Stack</a> document.  In particular, make sure to read the notification section     * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling     * Notifications</a> for the correct ways to launch an application from a     * notification.     */    public PendingIntent contentIntent;        /**     * The intent to execute when the notification is explicitly dismissed by the user, either with     * the "Clear All" button or by swiping it away individually.     *     * This probably shouldn't be launching an activity since several of those will be sent     * at the same time.     */    public PendingIntent deleteIntent;        /**     * The view that will represent this notification in the expanded status bar.     */    public RemoteViews contentView;...

上面这些就是notification要通过Binder传输到AMS的数据。那么对应的,如果我们想要自定义一个通知栏的话,其实就是将相关的View数据通过RemoteView的contentView(上面的注释明确的写出了这个View将代表了通知在状态栏上)通信到AMS中。这样子就可以办到自定义的通知栏了。

相对应的setLastEventInfo是设置默认模板的通知样式,下面是源码:

    public void setLatestEventInfo(Context context,            CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {        Notification.Builder builder = new Notification.Builder(context);        // First, ensure that key pieces of information that may have been set directly        // are preserved        builder.setWhen(this.when);        builder.setSmallIcon(this.icon);        builder.setPriority(this.priority);        builder.setTicker(this.tickerText);        builder.setNumber(this.number);        builder.setColor(this.color);        builder.mFlags = this.flags;        builder.setSound(this.sound, this.audioStreamType);        builder.setDefaults(this.defaults);        builder.setVibrate(this.vibrate);        // now apply the latestEventInfo fields        if (contentTitle != null) {            builder.setContentTitle(contentTitle);        }        if (contentText != null) {            builder.setContentText(contentText);        }        builder.setContentIntent(contentIntent);        builder.buildInto(this);    }

在Notification的Builder内部类中已经将通知的默认模板给设定好了。

自定义通知栏

所谓自定义通知栏知道原理之后,我们就很好的实现这个自定义的通知栏了。我们先自定义一个布局文件出来。

下面是布局文件xml的配置:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@color/light_green"    android:padding="10dp"    android:gravity="center"    android:orientation="horizontal" >    <ImageView        android:id="@+id/icon"        android:background="#000000"        android:layout_width="40dp"        android:scaleType="centerInside"        android:layout_height="40dp" />    <LinearLayout        android:id="@+id/layout"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="right"        android:orientation="vertical" >        <TextView            android:id="@+id/msg"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginBottom="5dp"            android:textColor="@android:color/white"            android:visibility="visible"            android:text="TextView" />        <TextView            android:id="@+id/open_activity2"            android:padding="2dp"            android:background="@drawable/common_bkg"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textColor="@android:color/white"            android:text="open DemoActivity_2" />    </LinearLayout></LinearLayout>

配置好了之后,我们来实现notification中的参数:

            //声明一个新的Notification,在里面设置参数            Notification notification = new Notification();            notification.icon = R.drawable.ic_launcher;            notification.tickerText = "hello world";            notification.when = System.currentTimeMillis();            notification.flags = Notification.FLAG_AUTO_CANCEL;            Intent intent = new Intent(this, DemoActivity_1.class);            intent.putExtra("sid", "" + sId);          //PendingIntent是延时Intent是指当点击通知栏之后启动intent指向activity            PendingIntent pendingIntent = PendingIntent.getActivity(this,                    0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

这里和前面相似,接下来我们要透过RemoteView来重新设置整个通知的View:

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notification);            remoteViews.setTextViewText(R.id.msg, "chapter_5: " + sId);            remoteViews.setImageViewResource(R.id.icon, R.drawable.icon1);          //PendingIntent是延时Intent是指当点击通知栏之后启动intent指向activity            PendingIntent openActivity2PendingIntent = PendingIntent.getActivity(this,                    0, new Intent(this, DemoActivity_2.class), PendingIntent.FLAG_UPDATE_CURRENT);            remoteViews.setOnClickPendingIntent(R.id.open_activity2, openActivity2PendingIntent);            //设置contentview            notification.contentView = remoteViews;            //设置pendingItent            notification.contentIntent = pendingIntent;            NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);            manager.notify(sId, notification);

这样子就完成了自定义通知栏的实现了,而RemoteView的工作原理之后再另外说一下吧。
下一章将总结一下,之前明白的PendingIntent在Notification中工作原理。

感谢郭霖大神和任玉刚大神的博客和书籍。

0 0