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

今天在复习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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值