• Notification详解(含工具类)


                                                               

        

      

    昨天一天只写了两篇文章,效率超低。追其原因呢,其实我一直在研究notification的实现方式,今天研究完了给大家分享一下。本来想写个工具类来封装一下代码的,但是我发现notification的个性化元素太多了,做成一个方法的话参数又多的要死,于是我就将比较常见的方法做了封装,写了个不是很规整的工具类,至于内部的逻辑啊,点击跳转的事件啊,大家下载demo后看看代码应该就能明白了,最重要的是根据自己的需要选择好的方法。还有一点需要建议的是,如果你发的通知都是用同一个ID的话可能会出现通知叠加的情况,这点需要注意一下。还是那句话根据实际需要吧,如果我的通知类型都是一样的,用同一个ID叠加就让他叠加吧。好啦,下面我们来看代码。

    首先还是布局文件,这里用的全是button,在布局界面直接绑定了监听器。

    <LinearLayout 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"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.kale.notification.MainActivity" 
        android:orientation="vertical">
    
        <Button
            android:id="@+id/normal_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="普通的通知" 
            android:onClick="buttonListener"/>
    
        <Button
            android:id="@+id/view_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="较为特别的通知" 
            android:onClick="buttonListener"/>
    
        <Button
            android:id="@+id/private_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="自定义布局的通知" 
            android:onClick="buttonListener"/>
    
        <Button
            android:id="@+id/big_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="可以显示多行信息的通知" 
            android:onClick="buttonListener"/>
    
        <Button
            android:id="@+id/progress_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="有进度条的通知" 
            android:onClick="buttonListener"/>
    
        <Button
            android:id="@+id/pic_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="有大图片的通知" 
            android:onClick="buttonListener"/>
    
        <Button
            android:id="@+id/btn_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="有两个按钮的通知" 
            android:onClick="buttonListener"/>
            
        <Button
            android:id="@+id/clear_button_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="40dp"
            android:text="清除所有的通知" 
            android:onClick="buttonListener"/>
    
    
    
    </LinearLayout>

    自定义的通知布局

    notification.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        android:background="#000000">
    
        <ImageView
            android:id="@+id/image"
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:layout_alignParentLeft="true"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp"
            android:layout_marginLeft="8.0dip"
            android:layout_marginRight="10dp" 
            android:src="@drawable/ic_launcher"/>
    
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/title"
            android:layout_marginTop="3.0dip"
            android:layout_toLeftOf="@+id/button"
            android:layout_toRightOf="@id/image"
            android:text="This is the text"
            android:textColor="#ffffff"
            android:textSize="16sp" />
    
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/text"
            android:layout_alignTop="@+id/image"
            android:textStyle="bold"
            android:text="title"
            android:textColor="#ffffff"
            android:textSize="16sp" />
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@+id/image"
            android:layout_alignParentRight="true"
            android:gravity="center_vertical"
            android:text="跳转"
            android:textColor="#ffffff" />
    
    </RelativeLayout>

    点击通知信息,跳转的activity界面

    other.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:orientation="horizontal" >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0.50"
            android:layout_gravity="center"
            android:gravity="center_horizontal"
            android:text="用PendingIntent跳转到的界面"
            android:textAppearance="?android:attr/textAppearanceLarge" />
    
    </LinearLayout>

    这个界面对应的activity就是个空的activity——OtherActivity.java,代码就不贴了。

    主界面

    MainAcitivity.java

    package com.kale.notification;
    
    import android.app.Activity;
    import android.app.PendingIntent;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.SystemClock;
    import android.view.View;
    import android.widget.RemoteViews;
    
    public class MainActivity extends Activity {
    
        NotificationAdmain admain;
        static int NOTIFICATION_ID = 13565400;
        Intent intent;
        int smallIcon = R.drawable.ic_launcher;
        String ticker = "来了条新的通知";
    
        int LargeIcon = R.drawable.kale;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 设置点击后启动的activity
            intent = new Intent(MainActivity.this, OtherActivity.class);
            admain = new NotificationAdmain(this,NOTIFICATION_ID);
        }
    
        public void buttonListener(View v) {
            switch (v.getId()) {
            case R.id.normal_button_id:
                admain.normal_notification(intent, smallIcon, ticker, "普通的通知",
                        "采用默认配置,这里的文字只能显示一行,会将多余的字影藏");
                break;
            case R.id.view_button_id:
                admain.special_notification(intent, smallIcon, ticker, LargeIcon,
                        "特殊的通知", "这里面大小图标同时存在,并且有数字");
                break;
            case R.id.private_button_id:
                //设置自定义布局中按钮的跳转界面
                Intent btnIntent = new Intent(MainActivity.this,OtherActivity.class);
                btnIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                //如果是启动activity,那么就用PendingIntent.getActivity,如果是启动服务,那么是getService
                PendingIntent Pintent = PendingIntent.getActivity(this,
                         (int) SystemClock.uptimeMillis(), btnIntent, PendingIntent.FLAG_UPDATE_CURRENT); 
                
                // 自定义布局
                RemoteViews remoteViews = new RemoteViews(getPackageName(),
                        R.layout.notification);
                remoteViews.setImageViewResource(R.id.image, R.drawable.kale);
                remoteViews.setTextViewText(R.id.title, "自定义通知视图");
                remoteViews.setTextViewText(R.id.text, "这个自定义通知栏只能这么高了,不能有再多的内容了");
                remoteViews.setOnClickPendingIntent(R.id.button, Pintent);//定义按钮点击后的动作
                admain.view_notification(remoteViews, intent, smallIcon, ticker);
                break;
            case R.id.big_button_id:
                admain.big_notification(intent, smallIcon, ticker, "可以随内容变长的通知",
                        "《天之界线》是Jack.Tony在2009年3月开始动笔的一本小说。"
                                + "其内容包涵了悬疑,穿越,魔法,冒险等元素。 Jack.Tony于2009年秋季完成了"
                                + "《天之界线》的序章——沉睡的容器。");
                break;
    
            case R.id.progress_button_id:
                admain.progress_notification(intent, smallIcon, ticker, "有进度条的通知信息","正在下载中……");
                break;
            case R.id.pic_button_id:
                admain.pic_notification(intent, smallIcon, ticker, "有大图片的通知信息", LargeIcon);
                break;
            case R.id.btn_button_id:
                admain.btn_notification(intent,smallIcon, ticker, "有按钮的通知", "下面的按钮可点击");
                break;
            case R.id.clear_button_id:
                admain.clear();
                break;
    
            default:
                break;
            }
    
        }
    
    }

    好,现在重头戏来了。

    NotificationAdmain.java

    package com.kale.notification;
    
    import android.app.Activity;
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.SystemClock;
    import android.support.v4.app.NotificationCompat;
    import android.widget.RemoteViews;
    
    public class NotificationAdmain {
    
        private static int NOTIFICATION_ID;
        private NotificationManager nm;
        private Notification notification;
        private NotificationCompat.Builder cBuilder;
        private Notification.Builder nBuilder;
        private Context mContext;
        int requestCode = (int) SystemClock.uptimeMillis();
        private static final int FLAG = Notification.FLAG_INSISTENT;
    
        public NotificationAdmain(Context context, int ID) {
            this.NOTIFICATION_ID = ID;
            mContext = context;
            // 获取系统服务来初始化对象
            nm = (NotificationManager) mContext
                    .getSystemService(Activity.NOTIFICATION_SERVICE);
            cBuilder = new NotificationCompat.Builder(mContext);
        }
    
        /**
         * 设置在顶部通知栏中的各种信息
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         */
        private void setCompatBuilder(Intent intent, int smallIcon, String ticker,
                String title, String msg) {
            // 如果当前Activity启动在前台,则不开启新的Activity。
            intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
            // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
            // 将Intent封装进PendingIntent中,点击通知的消息后,就会启动对应的程序
            PendingIntent pIntent = PendingIntent.getActivity(mContext,
                    requestCode, intent, FLAG);
    
            cBuilder.setContentIntent(pIntent);// 该通知要启动的Intent
    
            cBuilder.setSmallIcon(smallIcon);// 设置顶部状态栏的小图标
            cBuilder.setTicker(ticker);// 在顶部状态栏中的提示信息
    
            cBuilder.setContentTitle(title);// 设置通知中心的标题
            cBuilder.setContentText(msg);// 设置通知中心中的内容
            cBuilder.setWhen(System.currentTimeMillis());
    
            /*
             * 将AutoCancel设为true后,当你点击通知栏的notification后,它会自动被取消消失,
             * 不设置的话点击消息后也不清除,但可以滑动删除
             */
            cBuilder.setAutoCancel(true);
            // 将Ongoing设为true 那么notification将不能滑动删除
            // notifyBuilder.setOngoing(true);
            /*
             * 从Android4.1开始,可以通过以下方法,设置notification的优先级,
             * 优先级越高的,通知排的越靠前,优先级低的,不会在手机最顶部的状态栏显示图标
             */
            cBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
            /*
             * Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。
             * Notification.DEFAULT_SOUND:系统默认铃声。
             * Notification.DEFAULT_VIBRATE:系统默认震动。
             * Notification.DEFAULT_LIGHTS:系统默认闪光。
             * notifyBuilder.setDefaults(Notification.DEFAULT_ALL);
             */
            cBuilder.setDefaults(Notification.DEFAULT_ALL);
        }
    
        /**
         * 设置builder的信息,在用大文本时会用到这个
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         */
        private void setBuilder(Intent intent, int smallIcon, String ticker) {
            nBuilder = new Notification.Builder(mContext);
            // 如果当前Activity启动在前台,则不开启新的Activity。
            intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent pIntent = PendingIntent.getActivity(mContext,
                    requestCode, intent, FLAG);
            nBuilder.setContentIntent(pIntent);
            nBuilder.setSmallIcon(smallIcon);
            nBuilder.setTicker(ticker);
            nBuilder.setWhen(System.currentTimeMillis());
            nBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
            nBuilder.setDefaults(Notification.DEFAULT_ALL);
        }
    
        /**
         * 普通的通知
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         * @param title
         * @param msg
         */
        public void normal_notification(Intent intent, int smallIcon,
                String ticker, String title, String msg) {
    
            setCompatBuilder(intent, smallIcon, ticker, title, msg);
            sent();
        }
    
        /**
         * 进行多项设置的通知(在小米上似乎不能设置大图标,系统默认大图标为应用图标)
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         * @param LargeIcon
         * @param title
         * @param msg
         */
        public void special_notification(Intent intent, int smallIcon,
                String ticker, int LargeIcon, String title, String msg) {
    
            setCompatBuilder(intent, smallIcon, ticker, title, msg);
    
            // 如果不设置LargeIcon,那么系统会默认将上面的SmallIcon作为主要图标,显示在通知选项的最左侧,右下角的小图标将不再显示
            Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),
                    LargeIcon);
            cBuilder.setLargeIcon(bitmap);
            
            // 将Ongoing设为true 那么notification将不能滑动删除
            cBuilder.setOngoing(true);
            // 删除时
            Intent deleteIntent = new Intent(mContext, DeleteService.class);
            int deleteCode = (int) SystemClock.uptimeMillis();
            // 删除时开启一个服务
            PendingIntent deletePendingIntent = PendingIntent.getService(mContext,
                    deleteCode, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            cBuilder.setDeleteIntent(deletePendingIntent);
    
            cBuilder.setDefaults(Notification.DEFAULT_SOUND | // 设置使用默认的声音
                    Notification.DEFAULT_LIGHTS);// 设置使用默认的LED
            cBuilder.setVibrate(new long[] { 0, 100, 200, 300 });// 设置自定义的振动
            cBuilder.setAutoCancel(true);
            // builder.setSound(Uri.parse("file:///sdcard/click.mp3"));
    
            // 设置通知样式为收件箱样式,在通知中心中两指往外拉动,就能出线更多内容,但是很少见
            cBuilder.setNumber(3);
            cBuilder.setStyle(new NotificationCompat.InboxStyle()
                    .addLine("M.Lynn 你好,我是kale").addLine("M.Lynn 已收到,保证完成任务")
                    .addLine("M.Lynn 哈哈,明白了~").setSummaryText("+3 more")); // 设置在细节区域底端添加一行文本
            sent();
        }
    
        /**
         * 自定义视图的通知
         * 
         * @param remoteViews
         * @param intent
         * @param smallIcon
         * @param ticker
         */
        public void view_notification(RemoteViews remoteViews, Intent intent,
                int smallIcon, String ticker) {
    
            setCompatBuilder(intent, smallIcon, ticker, null, null);
    
            notification = cBuilder.build();
            notification.contentView = remoteViews;
            // 发送该通知
            nm.notify(NOTIFICATION_ID, notification);
        }
    
        /**
         * 可以容纳多行提示文本的通知信息 (因为在高版本的系统中才支持,所以要进行判断)
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         * @param title
         * @param msg
         */
        public void big_notification(Intent intent, int smallIcon, String ticker,
                String title, String msg) {
    
            final int sdk = android.os.Build.VERSION.SDK_INT;
            if (sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
                normal_notification(intent, smallIcon, ticker, title, msg);
            } else {
                setBuilder(intent, smallIcon, ticker);
                nBuilder.setContentTitle(title);
                nBuilder.setPriority(Notification.PRIORITY_HIGH);
                notification = new Notification.BigTextStyle(nBuilder).bigText(msg)
                        .build();
                // 发送该通知
                nm.notify(NOTIFICATION_ID, notification);
            }
        }
    
        /**
         * 有进度条的通知,可以设置为模糊进度或者精确进度
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         * @param title
         * @param msg
         */
        public void progress_notification(Intent intent, int smallIcon,
                String ticker, String title, String msg) {
    
            setCompatBuilder(intent, smallIcon, ticker, title, msg);
            /*
             * 因为进度条要实时更新通知栏也就说要不断的发送新的提示,所以这里不建议开启通知声音。
             * 这里是作为范例,给大家讲解下原理。所以发送通知后会听到多次的通知声音。
             */
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    int incr;
                    for (incr = 0; incr <= 100; incr += 10) {
                        // 参数:1.最大进度, 2.当前进度, 3.是否有准确的进度显示
                        cBuilder.setProgress(100, incr, false);
                        // cBuilder.setProgress(0, 0, true);
                        sent();
                        try {
                            Thread.sleep(1 * 500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 进度满了后,设置提示信息
                    cBuilder.setContentText("下载完成~").setProgress(0, 0, false);
                    sent();
                }
            }).start();
        }
    
        /**
         * 容纳大图片的通知
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         * @param title
         * @param bigPic
         */
        public void pic_notification(Intent intent, int smallIcon, String ticker,
                String title, int bigPic) {
    
            setCompatBuilder(intent, smallIcon, ticker, title, null);
            NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle();
            Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),
                    bigPic);
            picStyle.bigPicture(bitmap);
            cBuilder.setStyle(picStyle);
            sent();
        }
    
        /**
         * 里面有两个按钮的通知
         * 
         * @param intent
         * @param smallIcon
         * @param ticker
         * @param title
         * @param msg
         */
        public void btn_notification(Intent intent, int smallIcon, String ticker,
                String title, String msg) {
    
            Intent notifyIntent = new Intent(mContext, OtherActivity.class);
            int requestCode = (int) SystemClock.uptimeMillis();
            PendingIntent pendIntent = PendingIntent.getActivity(mContext,
                    requestCode, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    
            setCompatBuilder(intent, smallIcon, ticker, title, msg);
            cBuilder.addAction(android.R.drawable.ic_media_previous,
                    mContext.getString(R.string.previous), pendIntent);
            cBuilder.addAction(android.R.drawable.ic_media_next,
                    mContext.getString(R.string.next), pendIntent);
            sent();
        }
    
        /**
         * 发送通知
         */
        private void sent() {
            notification = cBuilder.build();
            // 发送该通知
            nm.notify(NOTIFICATION_ID, notification);
        }
    
        /**
         * 根据id清除通知
         */
        public void clear() {
            // 取消通知
            nm.cancelAll();
    
        }
    }

    点击通知,或者是删除通知的时候都可以用intent触发一个service或者是activity,这里是删除时候触发的service

    DeleteService

    package com.kale.notification;
    
    import android.app.IntentService;
    import android.content.Intent;
    import android.util.Log;
    
    public class DeleteService extends IntentService{
    
        public DeleteService() {
            super("");
            // TODO Auto-generated constructor stub
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.i("LOG", "===========deleteService");
        }
    
    }

    最后,记得注册activity和service,把需要的权限也写上

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.kale.notification"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="18" />
        <!-- 闪光灯的权限 -->
        <uses-permission android:name="android.permission.FLASHLIGHT"/>
        <!-- 振动的权限 -->
        <uses-permission android:name="android.permission.VIBRATE"/>
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name="com.kale.notification.OtherActivity"/>
            <service android:name="com.example.notificationtest.DeleteService" />
        </application>
    
    </manifest>

    参考的文章:http://www.cnblogs.com/dyllove98/archive/2013/06/08/3127580.html

    我还参考了一个demo,也十分优秀:http://download.csdn.net/detail/pringlee2011/6960743

    源码下载:http://download.csdn.net/detail/shark0017/7668783

  • 相关阅读:
    apache solr简单搭建
    Flash学习初总结
    UWP多设备加载不同xaml布局文件
    鼠标右键多余选项删除
    用命令查看win10/win8.1等详细激活信息方法:
    win10 登陆选项 无法打开
    UWP应用开发:添加复制按钮,添加引用
    notepad++详细介绍!
    Python安装出现2503 2502 问题解决!
    Genymotion插件安装教程
  • 原文地址:https://www.cnblogs.com/tianzhijiexian/p/3862910.html
Copyright © 2020-2023  润新知