標籤:android notification
通知的使用網上有各種總結,csdn上也有很多總結非常到位,在此就不做重複的總結了,需要的同學可以自行搜尋或者參考下面給出的連結。開始學習的時候認真的讀了一些,現在功能開發完畢,把自己最近遇到的一些問題和心得分享給大家。
一、很難逃避de相容問題
1、直接new Notification()這種方式已經過時,因此自己也沒有去細究這種方式,直接使用的是new NotificationCompat.Builder(context).build()(這個在support v4包中,下面的內容全是以這種方式來實現的)
2、自訂布局的相容
使用NotificationCampat來做自訂布局我們可以這樣做:
RemoteViews rvMain = new RemoteViews(context.getPackageName(), R.layout.notification_layout);//TODO rvMain...NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setContent(rvMain);// TOOD ...
在4.0以上,這樣是沒問題,但是在2.3的時候,你會發現這樣根本無效,因此我們需要換一種方式:
RemoteViews rvMain = new RemoteViews(context.getPackageName(), R.layout.notification_layout);//TODO rmMain...NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setContent(rvMain);// TOOD ...Notification notification = builder.build();if(Build.VERSION.SDK_INT <= 10){notification.contentView = rvMain;}
3、通知欄上的操作事件
先說說我們可以處理的通知事件:
setContentIntent():使用者點擊通知時觸發
setFullScreenIntent()://TODO 這個在通知顯示的時候會被調用
setDeleteIntent():使用者清除通知時觸發,可以是點擊清除按鈕,也可以是左右滑動刪除(當然了,前提是高版本)
2.3及以下是無法處理自訂布局中的操作事件的,這樣我們就不要去考慮增加自訂按鈕了。
二、可能會遇到的問題
1、Ticker表徵圖顯示只有中間一部分
new NotificationCompat.Builder(context).setSmallIcon(R.drawable.ic_notice_small, 0)
我們可以通過這樣的方式來設定Ticker時顯示的表徵圖。在我們測試的時候小米和sony的機器上出現過,解決辦法是把之前的大表徵圖(我們最初是72×72)替換成現在的32×32的小表徵圖,並把它從之前的xxhdpi移到hdpi檔案夾中。
2、Ticker不顯示:直接顯示通知的表徵圖,中間的Ticker過程沒有顯示
這個沒有找到是什麼原因,直接把setFullScreenIntent(mPIFullScreen, false)這行登出即可
3、點擊通知,通知清單不消失
這個只在華為的一個機器上遇到過,解決辦法是在點擊事件之後發一個關閉的廣播:
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
參考:http://stackoverflow.com/questions/18261969/clicking-android-notification-actions-does-not-close-notification-drawer
4、出現各種亂
這裡說的混亂是指通知沒有顯示出來、多條通知點擊觸發的事件相同、多條通知的Intent相同等等。這個時候你可能需要去檢查通知的ID和PendingIntent的requestCode。
5、各種機型的適配
這個是相當混亂的,比如大多數是黑底白字,但是部分華為機型是灰底黑字;有些不支援設定自訂布局中的字型顏色;有些會屏蔽自訂布局的背景顏色和透明度,有些甚至你只能自訂通知欄的部分布局(左面的表徵圖是改不了的):
曾經為了追求自訂布局的左側表徵圖和預設通知的左側表徵圖寬度相同,大小相仿,做了很多適配,比如各種dimens,但是僅僅是適配,還是不能支援所有機型,遂放棄了。到目前為止沒找到一個完美的解決方案,市面上很多優秀的應用做的也不是非常好,對比下左側表徵圖寬度你就知道。最近在墨跡天氣中發現這個功能:
這算不算對混亂的一種妥協呢?
三、自訂的一些擴充
從開始處理通知中的操作事件,到實現一個比現有通知更高的通知,我們的慾望在不斷的增加。雖然美好的東西總是來得晚一些,但是目前來看,這些想法我們都可以實現了。
4.1中預設的三種big style可以滿足我們很多時候的需求,比如:
從左至右依次應該為BigTextStyle、BigPictureStyle、InboxStyle,這個就不多說了,照著demo就能弄出來。下面是百度音樂播放器的通知效果,在此簡單實現下,效果
知道怎麼做了,其實是很容易實現的,但關鍵的是不知道怎麼做。首先看到這個效果,自己去嘗試了各種方法,比如指定視圖的高度,在不同的機器(主要是高版本的)機器上運行,發現都不行,google一下,沒有結果。怎麼辦?反編譯吧,在資源檔中發現了layout-v16檔案夾下有個布局,這個布局就是我們的布局,在一大堆java檔案中找到這樣一行代碼:
notification.bigContentView = *****;
怎麼樣?明白了吧~~就是關鍵句,查看api,這個屬性需要16及以上才支援,因此我們在實現的時候可以這樣寫:
if(Build.VERSION.SDK_INT >= 16){notification.bigContentView = rvMain;}將我們自己的RemoteView付給bigContentView。真正實現的時候你可能會發現,這個高度不是我們任意指定的,是的,卻是如此,他的高度是100dp。這樣我們就可以通過自訂RemoteView來實現各種絢麗的通知了。
四、通知NotificationManager的源碼
本想在分析下NotificationManager,但是發現他的代碼很少,只要完成自己的Notification然後調用它的方法就可以。具體的實現就是底層的事情了,又到軟肋的
不過簡單瀏覽還是發現了一點點——和Toast的關聯,他們都使用了INotificationManager:
static private INotificationManager getService() { if (sService != null) { return sService; } sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification")); return sService; }
Toast的show():
/** * Show the view for the specified duration. */ public void show() { if (mNextView == null) { throw new RuntimeException("setView must have been called"); } INotificationManager service = getService(); String pkg = mContext.getPackageName(); TN tn = mTN; tn.mNextView = mNextView; try { service.enqueueToast(pkg, tn, mDuration); } catch (RemoteException e) { // Empty } }NotificatioManager的notify():
/** * Post a notification to be shown in the status bar. If a notification with * the same tag and id has already been posted by your application and has not yet been * canceled, it will be replaced by the updated information. * * @param tag A string identifier for this notification. May be {@code null}. * @param id An identifier for this notification. The pair (tag, id) must be unique * within your application. * @param notification A {@link Notification} object describing what to * show the user. Must not be null. */ public void notify(String tag, int id, Notification notification) { int[] idOut = new int[1]; INotificationManager service = getService(); String pkg = mContext.getPackageName(); if (notification.sound != null) { notification.sound = notification.sound.getCanonicalUri(); if (StrictMode.vmFileUriExposureEnabled()) { notification.sound.checkFileUriExposed("Notification.sound"); } } if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); try { service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, notification, idOut, UserHandle.myUserId()); if (id != idOut[0]) { Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]); } } catch (RemoteException e) { } }
參考(引用):
http://blog.csdn.net/vipzjyno1/article/details/25248021
http://blog.csdn.net/feng88724/article/details/6259071