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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM