

昨天一天只寫了兩篇文章,效率超低。追其原因呢,其實我一直在研究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
