1. 程式人生 > >Notification的基本用法以及使用RemoteView實現自定義布局

Notification的基本用法以及使用RemoteView實現自定義布局

解決 edi ngs 取消 ets lsp 過程 net tde

Notification的作用

Notification是一種全局效果的通知,在系統的通知欄中顯示。既然作為通知,其基本作用有:

  • 顯示接收到短消息、即時信息等
  • 顯示客戶端的推送(廣告、優惠、新聞等)
  • 顯示正在進行的事物(後臺運行的程序,如音樂播放進度、下載進度)

Notification的基本操作:

Notification的基本操作主要有創建、更新和取消三種。一個Notification的必要屬性有三項,如果不設置的話在運行時會拋出異常:

  1. 小圖標,通過setSmallIcon方法設置
  2. 標題,通過setContentTitle方法設置
  3. 內容,通過setContentText方法設置。

除了以上三項,其他均為可選項,不過一般而言,通知需要有交互的功能,所以一般Notification具有Action屬性,這樣就能跳轉到App的某一個Activity、啟動一個service或者發送一個Broadcast。

當系統受到通知時,可以通過震動、鈴聲、呼吸燈等多種方式進行提醒。

下面就從Notification的基本操作逐條介紹:

  1. Notification的創建

Notification的創建過程主要涉及到Notification.Builder、Notification、NotificationManager

Notification.Builder:

使用建造者模式構建Notification對象。由於Notification.Builder僅支持Android4.1及之後的版本,為了解決兼容性的問題,使用V4兼容庫中的NotifivationCompat.Builder類。

Notification:通知對應類,保存通知相關的數據。NotificationManager向系統發送通知時會用到。

NotificationManager:通知管理類,調用NotificationManager的notify方法可以向系統發送通知。

獲取 NotificationManager 對象:

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

前面講到,Notification有三個必要屬性以及一個很有必要的屬性Action。下面我們就創建一個簡單的Notification,主要有以下三步:

  1. 獲取NotificationManager實例
  2. 實例化NotificationCompat.Builder並設置相關屬性
  3. 通過builder.build方法來生成Notification對象,並發送通知
技術分享
private void sendNotification(){

    Intent intent = new Intent(this,SettingsActivity.class);

    PendingIntent mPendingIntent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_ONE_SHOT);

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

    NotificationCompat.Builder builder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)

            //設置小圖標

            .setSmallIcon(R.mipmap.ic_launcher)

            //點擊後自動清除

            .setAutoCancel(true)

            //設置通知標題

            .setContentTitle("最簡單的通知")

            //設置通知內容

            .setContentText("真的很簡單很簡單很簡單")

            //設置通知的動作

            .setContentIntent(mPendingIntent)

            //設置通知時間,默認為系統發出通知的時間

            .setWhen(System.currentTimeMillis());

            //第一個參數為Notification的id

    notificationManager.notify(2,builder.build());

}
技術分享

其中為了實現Action屬性,我們需要創建Intent、PendingIntent和setContentIntent()這幾步。

不難發現,其中的PendingIntent的設置才是其中的關鍵。

PendingIntent支持三種待定的意圖:啟動Activity,啟動Service和發送Broadcast。對應於它的三個接口方法。

static PendingIntent

getActivity(Context context,int requestCode,Intent intent,int flags)

獲取一個PendingIntent,該意圖發生時,相當於Context.startActivity(Intent)

static PendingIntent

getService (Context context,int requestCode,Intent intent,int flags)

獲取一個PendingIntent,該意圖發生時,相當於Context.startService (Intent)

static PendingIntent

getBroadcast(Context context,int requestCode,Intent intent,int flags)

獲取一個PendingIntent,該意圖發生時,相當於Context.sendBroadcast(Intent)

其中context和intent不需要講,主要說一下requestCode和flags。其中requestCode是PendingIntent發送發的請求碼,多數情況下設置為0即可,requestCode會影響到flags的效果。

PendingIntent相同:Intent相同且requestCode也相同。(Intent相同需要ComponentName和intent-filter相同)

flags的常見類型有:

FLAG_ONE_SHOT:只能被使用一次,然後就會被自動cancel,如果後續還有相同的PendingIntent。那麽他們的send方法就會調用失敗。
FLAG_NO_CREATE:如果當前系統中不存在相同的PendingIntent對象,系統不會創建該PendingIntent對象,而是直接返回null。(很少使用)

FLAG_CANCEL_CURRENT:如果當前系統中已經存在一個相同的 PendingIntent 對象,那麽就將先將已有的 PendingIntent 取消,然後重新生成一個 PendingIntent 對象。

FLAG_UPDATE_CURRENT:當前描述的PendingIntent如果已經存在,那麽它們會被更新,即Intent中的Extras會被替換到最新的。

  1. Notification的更新

更新通知的操作很簡單,只需要再次發送一次相同ID的通知即可,如果之前的通知還沒有被取消,則會直接更新該通知相關的屬性;如果之前的通知已經被取消,則會重新創建一個新的通知。

更新通知和發送通知采用同樣的方法。

  1. Notification的取消

取消通知的方式主要有以下5種:

  1. 點擊通知欄的清除按鈕,會清除所有可清除的通知
  2. 設置了setAutoCancel()或者設置了flags為FLAG_AUTO_CANCEL的通知,點擊通知時會自動清除。
  3. 通過NotificationManager調用cancel(int id)來取消指定id的通知
  4. 通過NotificationManager調用cancel(String tag,int id)方法清除指定Tag和ID的通知。
  5. 通過NotificationManager調用cancelAll()清除所有該應用之前發送的通知

如果是通過NotificationManager.notify(String tag, int id, Notification notify) 方法創建的通知,那麽只能通過 NotificationManager.cancel(String tag, int id) 或cancelAll()方法才能清除對應的通知,調用NotificationManager.cancel(int id) 無效。

  1. Notification的通知效果

前面提到了Notification的通知效果,有了通知效果更能提醒用戶去查看Notification。

Notification的通知效果有震動、呼吸燈、鈴聲三種,可以通過builder中的setDefaults(int defaults)方法來設置,屬性有以下四種,一旦設置了默認效果,自定義效果就會失效。

技術分享
//添加默認震動效果,需要申請震動權限

//<uses-permission android:name="android.permission.VIBRATE" />

Notification.DEFAULT_VIBRATE

//添加系統默認聲音效果,設置此值後,調用setSound()設置自定義聲音無效

Notification.DEFAULT_SOUND

//添加默認呼吸燈效果,使用時須與 Notification.FLAG_SHOW_LIGHTS 結合使用,否則無效

Notification.DEFAULT_LIGHTS

//添加上述三種默認提醒效果

Notification.DEFAULT_ALL
技術分享

鈴聲:

技術分享
//調用系統默認響鈴,設置此屬性後setSound()會無效

//.setDefaults(Notification.DEFAULT_SOUND)

//調用系統多媒體褲內的鈴聲

//.setSound(Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"2"));

//調用自己提供的鈴聲,位於 /res/values/raw 目錄下

.setSound(Uri.parse("android.resource://com.littlejie.notification/" + R.raw.sound))
技術分享

震動:

技術分享
long[] vibrate = new long[]{0, 500, 1000, 1500};
 

//使用系統默認的震動參數,會與自定義的沖突

//.setDefaults(Notification.DEFAULT_VIBRATE)

//自定義震動效果

.setVibrate(vibrate);
技術分享

呼吸燈

//ledARGB 表示燈光顏色、 ledOnMS 亮持續時間、ledOffMS 暗的時間

.setLights(0xFF0000, 3000, 3000);

另一種方式:

技術分享
Notification notification = builder.build();

//只有在設置了標誌符Flags為Notification.FLAG_SHOW_LIGHTS的時候,才支持呼吸燈提醒。

notify.flags = Notification.FLAG_SHOW_LIGHTS;

//設置lights參數的另一種方式

//notify.ledARGB = 0xFF0000;

//notify.ledOnMS = 500;

//notify.ledOffMS = 5000;
技術分享

還可以通過以下幾種Flag來設置通知效果

技術分享
 //提醒效果常用 Flag
//三色燈提醒,在使用三色燈提醒時候必須加該標誌符

        Notification.FLAG_SHOW_LIGHTS

//發起正在運行事件(活動中)

        Notification.FLAG_ONGOING_EVENT

//讓聲音、振動無限循環,直到用戶響應 (取消或者打開)

        Notification.FLAG_INSISTENT



//發起Notification後,鈴聲和震動均只執行一次

        Notification.FLAG_ONLY_ALERT_ONCE

//用戶單擊通知後自動消失

        Notification.FLAG_AUTO_CANCEL


//只有調用NotificationManager.cancel()時才會清除

        Notification.FLAG_NO_CLEAR

//表示正在運行的服務

        Notification.FLAG_FOREGROUND_SERVICE
技術分享

上面講到的Notification的布局都是系統默認的,當然有時候處於需求,我們可能需要自定義Notification的布局。

那如何實現Notification的自定義布局呢?

這裏就需要提出一個新的知識點RemoteView,望文生義,即遠程View。

RemoteView表示的是一種View結構,它可以在其他進程中顯示(具體來講是SystemServer進程),由於它是在其他進程中顯示,為了更新它的界面,我們不能簡單地使用普通View的那一套方法,RemoteView提供了一系列Set方法用於更新界面。

下面就是一個簡單的示例;

技術分享
package com.pignet.remoteviewtest;

import android.app.Notification;

import android.app.NotificationManager;

import android.app.PendingIntent;

import android.content.Context;

import android.content.Intent;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.RemoteViews;

public class MainActivity extends AppCompatActivity {


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Button btnNotification = (Button) findViewById(R.id.btn_notification);

        btnNotification.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                sendNotification();

            }

        });

    }

    private void sendNotification(){

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

        Notification notification =new Notification();

        notification.icon=R.mipmap.ic_launcher;

        notification.when=System.currentTimeMillis();

        notification.flags=Notification.FLAG_AUTO_CANCEL;

        //跳轉意圖

        Intent intent = new Intent(this,SettingsActivity.class);

        //建立一個RemoteView的布局,並通過RemoteView加載這個布局

        RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.layout_notification);

        //為remoteView設置圖片和文本

        remoteViews.setTextViewText(R.id.message,"第一條通知");

        remoteViews.setImageViewResource(R.id.image,R.mipmap.ic_launcher_round);

        //設置PendingIntent

        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);

        //為id為openActivity的view設置單擊事件

        remoteViews.setOnClickPendingIntent(R.id.openActivity,pendingIntent);

        //將RemoteView作為Notification的布局

        notification.contentView =remoteViews;

        //將pendingIntent作為Notification的intent,這樣當點擊其他部分時,也能實現跳轉

        notification.contentIntent=pendingIntent;

        notificationManager.notify(1,notification);

    }

}
 
技術分享

有圖:

技術分享

Notification的基本用法以及使用RemoteView實現自定義布局