NotificationManagerService使用详解与原理分析(一)
概況
? ? ? ??Android在4.3的版本中(即API 18)加入了NotificationListenerService,根據SDK的描述(AndroidDeveloper)可以知道,當系統收到新的通知或者通知被刪除時,會觸發NotificationListenerService的回調方法。同時在Android 4.4 中新增了Notification.extras 字段,也就是說可以使用NotificationListenerService獲取系統通知具體信息,這在以前是需要用反射來實現的。
轉載請務必注明出處:http://blog.csdn.net/yihongyuelan
重要關系
? ? ? ? 對于系統通知,三方APP使用NotificationListenerService主要目的是為了獲取系統通知相關信息,主要包括:通知的新增和刪除,獲取當前通知數量,通知內容相關信息等。這些信息可以通過NotificationListenerService類提供的方法以及StatusBarNotification類對象來獲取。
NotificationListenerService主要方法(成員變量):
cancelAllNotifications()?:刪除系統中所有可被清除的通知;?
cancelNotification(String pkg, String tag, int id)?:刪除具體某一個通知;
getActiveNotifications()?:返回當前系統所有通知到StatusBarNotification[];
onNotificationPosted(StatusBarNotification sbn)?:當系統收到新的通知后出發回調;?
onNotificationRemoved(StatusBarNotification sbn)?:當系統通知被刪掉后出發回調;
以上是NotificationListenerService的主要方法,通過這些方法就可以在應用中操作系統通知,在NotificationListenerService中除了對通知的操作之外,還可以獲取到通知的StatusBarNotification對象,通過該對象可以獲取通知更詳細的數據。
StatusBarNotification主要方法(成員變量):
getId():返回通知對應的id;
getNotification():返回通知對象;
getPackageName():返回通知對應的包名;
getPostTime():返回通知發起的時間;
getTag():返回通知的Tag,如果沒有設置返回null;
getUserId():返回UserId,用于多用戶場景;
isClearable():返回該通知是否可被清楚,FLAG_ONGOING_EVENT、FLAG_NO_CLEAR;
isOngoing():檢查該通知的flag是否為FLAG_ONGOING_EVENT;
使用簡介
正確使用NotificationListenerService需要注意三點:
(1). 新建一個類并繼承自NotificationListenerService,override其中重要的兩個方法;
[java]?view plaincopy
public?class?NotificationMonitor?extends?NotificationListenerService?{??
????????@Override??
????????public?void?onNotificationPosted(StatusBarNotification?sbn)?{??
??????????????Log.i("SevenNLS","Notification?posted");??
????????}??
???
????????@Override??
????????public?void?onNotificationRemoved(StatusBarNotification?sbn)?{??
??????????????Log.i("SevenNLS","Notification?removed");???
????????}??
}??
(2). 在AndroidManifest.xml中注冊Service并聲明相關權限;
[html]?view plaincopy
<service?android:name=".NotificationMonitor"??
?????????android:label="@string/service_name"??
?????????android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">??
????<intent-filter>??
????????<action?android:name="android.service.notification.NotificationListenerService"?/>??
????</intent-filter>??
</service>??
(3). 開啟NotificationMonitor的監聽功能;
? ? ? ??完成以上兩步之后,將程序編譯并安裝到手機上,但此時該程序是無法監聽到新增通知和刪除通知的,還需要在"Settings > Security > Notification access"中,勾選NotificationMonitor。此時如果系統收到新的通知或者通知被刪除就會打印出相應的log了。
? ? ? ??這里需要注意,如果手機上沒有安裝使用NotificationListenerService類的APP,Notification access是不會顯示出來的。可以在源碼/packages/apps/Settings/src/com/android/settings/SecuritySettings.java中看到,如果沒有使用NotificationListenerService的APK,直接就不顯示這一項了。
[java]?view plaincopy
mNotificationAccess?=?findPreference(KEY_NOTIFICATION_ACCESS);??
if?(mNotificationAccess?!=?null)?{??
????final?int?total?=?NotificationAccessSettings.getListenersCount(mPM);??
????if?(total?==?0)?{??
????????if?(deviceAdminCategory?!=?null)?{??
????????????deviceAdminCategory.removePreference(mNotificationAccess);??
????????}??
????}?else?{??
????????final?int?n?=?getNumEnabledNotificationListeners();??
????????if?(n?==?0)?{??
????????????mNotificationAccess.setSummary(getResources().getString(??
????????????????????R.string.manage_notification_access_summary_zero));??
????????}?else?{??
????????????mNotificationAccess.setSummary(String.format(getResources().getQuantityString(??
????????????????????R.plurals.manage_notification_access_summary_nonzero,??
????????????????????n,?n)));??
????????}??
????}??
}??
使用詳解
通過前面的講解(實際上就是對AndroidDeveloper的解釋),已經可以正常使用NotificationListenerService了,但對于實際應用中,需要考慮的事情還比較多。比如:
1. 如何檢測應用已開啟Notification access監聽功能?
如果檢測到應用沒有激活Notification access監聽功能,需要提示用戶開啟;
2. 能不能主動跳轉到Notification access監聽頁面?
如果能夠根據第1步的判斷自動跳轉到對應的頁面,那可以省掉很多操作;
3. 如何與NotificationListenerService交互?
涉及到與Service的交互,但又與普通的Service不同,這里后文解釋;
4. NotificationListenerService使用過程中有哪些注意事項?
在使用NotificationListenerService過程中自己遇到了一些坑,后文會通過分析給出相應的解決方案;
程序運行截圖
?
圖 1 程序運行截圖
示例介紹
? ? ? ??NotificationListenerDemo主要用于獲取系統當前通知信息,并可手動創建"可清除通知",逐條刪除"可清除通知",一次性刪除"可清除通知",以及顯示系統當前活動的通知信息。實際上該示例回答了前面使用詳解中提出的各項疑問,在實際使用過程中相信大部分人都會遇到,因此這里逐條展開與大家分享。
圖 2 主界面
功能分析
1. 如何檢測應用已開啟Notification access監聽功能?
? ? ? ??在程序啟動時,執行Notification access的檢測,查看是否訪問Notification的權限。如果用戶沒有Enable Notification access,則彈出提示對話框,點擊OK跳轉到Notification access設置頁面。
圖 3 首次啟動 isEnable
? ? ? ??使用NotificationListenerService的應用如果開啟了Notification access,系統會將包名等相關信息寫入SettingsProver數據庫中,因此可以從數據庫中獲取相關信息并過濾,從而判斷應用是否開啟了Notification access,代碼如下:
[java]?view plaincopy
private?static?final?String?ENABLED_NOTIFICATION_LISTENERS?=?"enabled_notification_listeners";??
private?boolean?isEnabled()?{??
????String?pkgName?=?getPackageName();??
????final?String?flat?=?Settings.Secure.getString(getContentResolver(),??
????????????ENABLED_NOTIFICATION_LISTENERS);??
????if?(!TextUtils.isEmpty(flat))?{??
????????final?String[]?names?=?flat.split(":");??
????????for?(int?i?=?0;?i?<?names.length;?i++)?{??
????????????final?ComponentName?cn?=?ComponentName.unflattenFromString(names[i]);??
????????????if?(cn?!=?null)?{??
????????????????if?(TextUtils.equals(pkgName,?cn.getPackageName()))?{??
????????????????????return?true;??
????????????????}??
????????????}??
????????}??
????}??
????return?false;??
}??
在返回值flat中如果包含了應用的包名,即可確定應用已開啟Notification access,反之則表示沒有開啟。
2. 能不能主動跳轉到Notification access監聽頁面?
? ? ? ??通過查看可以知道,Notification access界面接收action為"android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"的intent啟動,因此使用startActivity可以很容易的跳轉到該頁面,從而避免用戶在Settings中查找。代碼如下:
[java]?view plaincopy
private?static?final?String?ACTION_NOTIFICATION_LISTENER_SETTINGS?=?"android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";??
private?void?openNotificationAccess()?{??
????startActivity(new?Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS));??
}??
3. 如何與NotificationListenerService交互?
? ? ? ??因為NotificationListenerService中包含了四個重要的方法,分別是:onNotificationPosted、onNotificationRemoved、cancelNotification、cancelAllNotifications。通過這些方法我們才能實現諸如通知信息的獲取以及刪除等功能,雖然這些方法是public的,那是不是意味著我們只要拿到NotificationListenerService的對象就可以直接調用這些方法了呢?那如何拿到Service的對象呢?在之前的博文中,曾有提到與Service的交互( 具體可參考拙作《Android中程序與Service交互的方式——交互方式》),可以看到與Service的交互有很多種方法,但如果要拿到Service的對象,歸根到底還是需要Binder。
? ? ? ??也就是說得使用bindService的辦法,將onServiceConnected回調中的IBinder對象轉型成NotificationListenerService的對象。測試代碼如下:
[java]?view plaincopy
//在MainActivity.java的onCreate方法中使用bindService幫頂NotificationMonitor服務??
bindService(new?Intent(this,NotificationMonitor.class??),?new?ServiceConnection()?{??
??@Override??
??public?void?onServiceDisconnected(ComponentName?arg0)?{??
??}??
????
??@Override??
??public?void?onServiceConnected(ComponentName?arg0,?IBinder?arg1)?{??
????NotificationMonitor.MyBinder?localBinder?=?(MyBinder)arg1;??
????NotificationMonitor?mMonitor?=?localBinder.getService();??
??}??
},?BIND_AUTO_CREATE);??
[java]?view plaincopy
//NotificationMonitor的onBind方法返回構造的Binder對象??
public?class?NotificationMonitor?extends?NotificationListenerService?{??
??private?MyBinder?mBinder?=?new?MyBinder();??
??public??class?MyBinder?extends?Binder{??
????public?NotificationMonitor?getService(){??
??????return?NotificationMonitor.this;??
????}??
??}??
??
??@Override??
??public?IBinder?onBind(Intent?arg0)?{??
????return?mBinder;??
??}??
??
??@Override??
??public?void?onNotificationPosted(StatusBarNotification?sbn)?{??
????getActiveNotifications();??
????cancelAllNotifications();??
??}??
??
??@Override??
??public?void?onNotificationRemoved(StatusBarNotification?sbn)?{??
??}??
}??
那這樣操作之后是不是就意味著可以拿到NotificationMonitor的對象并直接調用getActiveNotifications()方法,用于獲取當前系統通知的信息了呢?很抱歉,事實證明這樣是不行的。這里簡單的分析下,在后面的NotificationListenerService原理分析中再詳細講解。在NotificationListenerService的源碼中可以看到:
[java]?view plaincopy
@Override??
public?IBinder?onBind(Intent?intent)?{??
????if?(mWrapper?==?null)?{??
????????mWrapper?=?new?INotificationListenerWrapper();??
????}?????
????return?mWrapper;??
}??
這里的INotificationListenerWrapper是NotificationListenerService的一個內部類:
[java]?view plaincopy
private?class?INotificationListenerWrapper?extends?INotificationListener.Stub??
而NotificationMonitor繼承自NotificationListenerService,默認的onBind方法卻是:
[java]?view plaincopy
@Override??
public?IBinder?onBind(Intent?intent)?{??
????return?super.onBind(intent);??
}??
? ? ? ??這里注意,一般情況下service的onBind方法返回要么是null要么是Binder對象,可這里直接調用父類NotificationListenerService的onBind方法,而父類返回的是INotificationListenerWrapper的對象。這說明Binder對象已經被指定了,不能再給NotificationMonitor指定其它的Binder對象。如果你非要給NotificationMonitor指定其它的Binder對象,那么就無法使用INotificationListenerWrapper提供的方法。也就是說要么就用系統NotificationListenerService提供的方法,要么就把NotificationMonitor當一個普通的Service來用,系統提供的方法都不能使用。
? ? ? ??那應該如何使用NotificationListenerService中的方法呢?在拙作《Android中程序與Service交互的方式——交互方式》中,已經提供了很多的例子,這里僅以廣播的方式為例。
? ? ? ??既然NotificationMonitor可以使用NotificationListenerService的方法,那通過NotificationMonitor把通知狀態的改變以及數據獲取到,并使用static數據進行存儲,之后再在MainActivity中直接使用即可。在MainActivity中控制通知的單個刪除和全部刪除,則使用廣播的方式發送給NotificationMonitor進行處理。MainActivity與NotificationMonitor的關系類圖如下:
圖 4 結構類圖
NotificationMonitor和MainActivity關鍵代碼如下:
[java]?view plaincopy
public?class?NotificationMonitor?extends?NotificationListenerService?{??
????private?static?final?String?TAG?=?"SevenNLS";??
????private?static?final?String?TAG_PRE?=?"["?+?NotificationMonitor.class.getSimpleName()?+?"]?";??
????private?static?final?int?EVENT_UPDATE_CURRENT_NOS?=?0;??
????public?static?final?String?ACTION_NLS_CONTROL?=?"com.seven.notificationlistenerdemo.NLSCONTROL";??
????//用于存儲當前所有的Notification的StatusBarNotification對象數組??
????public?static?List<StatusBarNotification[]>?mCurrentNotifications?=?new?ArrayList<StatusBarNotification[]>();??
????public?static?int?mCurrentNotificationsCounts?=?0;??
????//收到新通知后將通知的StatusBarNotification對象賦值給mPostedNotification??
????public?static?StatusBarNotification?mPostedNotification;??
????//刪除一個通知后將通知的StatusBarNotification對象賦值給mRemovedNotification??
????public?static?StatusBarNotification?mRemovedNotification;??
????private?CancelNotificationReceiver?mReceiver?=?new?CancelNotificationReceiver();??
????//?String?a;??
????private?Handler?mMonitorHandler?=?new?Handler()?{??
????????@Override??
????????public?void?handleMessage(Message?msg)?{??
????????????switch?(msg.what)?{??
????????????????case?EVENT_UPDATE_CURRENT_NOS:??
????????????????????updateCurrentNotifications();??
????????????????????break;??
????????????????default:??
????????????????????break;??
????????????}??
????????}??
????};??
??
????class?CancelNotificationReceiver?extends?BroadcastReceiver?{??
??
????????@Override??
????????public?void?onReceive(Context?context,?Intent?intent)?{??
????????????String?action;??
????????????if?(intent?!=?null?&&?intent.getAction()?!=?null)?{??
????????????????action?=?intent.getAction();??
????????????????if?(action.equals(ACTION_NLS_CONTROL))?{??
????????????????????String?command?=?intent.getStringExtra("command");??
????????????????????if?(TextUtils.equals(command,?"cancel_last"))?{??
????????????????????????if?(mCurrentNotifications?!=?null?&&?mCurrentNotificationsCounts?>=?1)?{??
????????????????????????????//每次刪除通知最后一個??
????????????????????????????StatusBarNotification?sbnn?=?getCurrentNotifications()[mCurrentNotificationsCounts?-?1];??
????????????????????????????cancelNotification(sbnn.getPackageName(),?sbnn.getTag(),?sbnn.getId());??
????????????????????????}??
????????????????????}?else?if?(TextUtils.equals(command,?"cancel_all"))?{??
????????????????????????//刪除所有通知??
????????????????????????cancelAllNotifications();??
????????????????????}??
????????????????}??
????????????}??
????????}??
??
????}??
??
????@Override??
????public?void?onCreate()?{??
????????super.onCreate();??
????????logNLS("onCreate...");??
????????IntentFilter?filter?=?new?IntentFilter();??
????????filter.addAction(ACTION_NLS_CONTROL);??
????????registerReceiver(mReceiver,?filter);??
????//在onCreate時第一次調用getActiveNotifications()??
????????mMonitorHandler.sendMessage(mMonitorHandler.obtainMessage(EVENT_UPDATE_CURRENT_NOS));??
????}??
??
????@Override??
????public?void?onDestroy()?{??
????????super.onDestroy();??
????????unregisterReceiver(mReceiver);??
????}??
??
????@Override??
????public?IBinder?onBind(Intent?intent)?{??
????????//?a.equals("b");??
????????logNLS("onBind...");??
????????return?super.onBind(intent);??
????}??
??
????@Override??
????public?void?onNotificationPosted(StatusBarNotification?sbn)?{??
????????//當系統收到新的通知后,更新mCurrentNotifications列表??
????????updateCurrentNotifications();??
????????logNLS("onNotificationPosted...");??
????????logNLS("have?"?+?mCurrentNotificationsCounts?+?"?active?notifications");??
????????mPostedNotification?=?sbn;??
????????//通過以下方式可以獲取Notification的詳細信息??
????????/*?
?????????*?Bundle?extras?=?sbn.getNotification().extras;?String?
?????????*?notificationTitle?=?extras.getString(Notification.EXTRA_TITLE);?
?????????*?Bitmap?notificationLargeIcon?=?((Bitmap)?
?????????*?extras.getParcelable(Notification.EXTRA_LARGE_ICON));?Bitmap?
?????????*?notificationSmallIcon?=?((Bitmap)?
?????????*?extras.getParcelable(Notification.EXTRA_SMALL_ICON));?CharSequence?
?????????*?notificationText?=?extras.getCharSequence(Notification.EXTRA_TEXT);?
?????????*?CharSequence?notificationSubText?=?
?????????*?extras.getCharSequence(Notification.EXTRA_SUB_TEXT);?
?????????*?Log.i("SevenNLS",?"notificationTitle:"+notificationTitle);?
?????????*?Log.i("SevenNLS",?"notificationText:"+notificationText);?
?????????*?Log.i("SevenNLS",?"notificationSubText:"+notificationSubText);?
?????????*?Log.i("SevenNLS",?
?????????*?"notificationLargeIcon?is?null:"+(notificationLargeIcon?==?null));?
?????????*?Log.i("SevenNLS",?
?????????*?"notificationSmallIcon?is?null:"+(notificationSmallIcon?==?null));?
?????????*/??
????}??
??
????@Override??
????public?void?onNotificationRemoved(StatusBarNotification?sbn)?{??
????????//當有通知被刪除后,更新mCurrentNotifications列表??
????????updateCurrentNotifications();??
????????logNLS("removed...");??
????????logNLS("have?"?+?mCurrentNotificationsCounts?+?"?active?notifications");??
????????mRemovedNotification?=?sbn;??
????}??
??
????private?void?updateCurrentNotifications()?{??
????????try?{??
????????????StatusBarNotification[]?activeNos?=?getActiveNotifications();??
????????????if?(mCurrentNotifications.size()?==?0)?{??
????????????????mCurrentNotifications.add(null);??
????????????}??
????????????mCurrentNotifications.set(0,?activeNos);??
????????????mCurrentNotificationsCounts?=?activeNos.length;??
????????}?catch?(Exception?e)?{??
????????????logNLS("Should?not?be?here!!");??
????????????e.printStackTrace();??
????????}??
????}??
??
????//獲取當前狀態欄顯示通知總數??
????public?static?StatusBarNotification[]?getCurrentNotifications()?{??
????????if?(mCurrentNotifications.size()?==?0)?{??
????????????logNLS("mCurrentNotifications?size?is?ZERO!!");??
????????????return?null;??
????????}??
????????return?mCurrentNotifications.get(0);??
????}??
??
????private?static?void?logNLS(Object?object)?{??
????????Log.i(TAG,?TAG_PRE?+?object);??
????}??
??
}??
而MainActivity主要負責界面顯示與交互,關鍵代碼如下:
[java]?view plaincopy
public?class?MainActivity?extends?Activity?{??
??
????private?static?final?String?TAG?=?"SevenNLS";??
????private?static?final?String?TAG_PRE?=?"["+MainActivity.class.getSimpleName()+"]?";??
????private?static?final?int?EVENT_SHOW_CREATE_NOS?=?0;??
????private?static?final?int?EVENT_LIST_CURRENT_NOS?=?1;??
????private?static?final?String?ENABLED_NOTIFICATION_LISTENERS?=?"enabled_notification_listeners";??
????private?static?final?String?ACTION_NOTIFICATION_LISTENER_SETTINGS?=?"android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";??
????private?boolean?isEnabledNLS?=?false;??
????private?TextView?mTextView;??
??
????private?Handler?mHandler?=?new?Handler()?{??
????????@Override??
????????public?void?handleMessage(Message?msg)?{??
????????????switch?(msg.what)?{??
????????????????case?EVENT_SHOW_CREATE_NOS:??
????????????//顯示創建的Notification對應的pkgName、Tag、Id??
????????????????????showCreateNotification();??
????????????????????break;??
????????????????case?EVENT_LIST_CURRENT_NOS:??
????????????//顯示當前所有的Notification數量及其包名??
????????????????????listCurrentNotification();??
????????????????????break;??
??
????????????????default:??
????????????????????break;??
????????????}??
????????}??
????};??
??
????@Override??
????protected?void?onCreate(Bundle?savedInstanceState)?{??
????????super.onCreate(savedInstanceState);??
????????setContentView(R.layout.activity_main);??
????????mTextView?=?(TextView)?findViewById(R.id.textView);??
????}??
??
????@Override??
????protected?void?onResume()?{??
????????super.onResume();??
????????//判斷是否有開啟Notification?access??
????????isEnabledNLS?=?isEnabled();??
????????logNLS("isEnabledNLS?=?"?+?isEnabledNLS);??
????????if?(!isEnabledNLS)?{??
????????//如果沒有開啟則顯示確認對話框??
????????????showConfirmDialog();??
????????}??
????}??
??
????public?void?buttonOnClicked(View?view)?{??
????????mTextView.setTextColor(Color.BLACK);??
????????switch?(view.getId())?{??
????????????case?R.id.btnCreateNotify:??
????????????????logNLS("Create?notifications...");??
????????//創建可清除的Notification??
????????????????createNotification(this);??
????????//顯示當前狀態欄中所有Notification數量及其包名??
????????????????mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_SHOW_CREATE_NOS),?50);??
????????????????break;??
????????????case?R.id.btnClearLastNotify:??
????????????????logNLS("Clear?Last?notification...");??
????????//清除最后一個Notification??
????????????????clearLastNotification();??
????????//顯示當前狀態欄中所有Notification數量及其包名??
????????????????mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_LIST_CURRENT_NOS),?50);??
????????????????break;??
????????????case?R.id.btnClearAllNotify:??
????????????????logNLS("Clear?All?notifications...");??
????????//清除所有"可被清除"的Notification??
????????????????clearAllNotifications();??
????????????????mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_LIST_CURRENT_NOS),?50);??
????????????????break;??
????????????case?R.id.btnListNotify:??
????????????????logNLS("List?notifications...");??
????????????????listCurrentNotification();??
????????????????break;??
????????????case?R.id.btnEnableUnEnableNotify:??
????????????????logNLS("Enable/UnEnable?notification...");??
????????//打開Notification?access啟動/取消界面??
????????????????openNotificationAccess();??
????????????????break;??
????????????default:??
????????????????break;??
????????}??
????}??
??
????//......省略??
}??
4. NotificationListenerService使用過程中有哪些注意事項?
? ? ? ??如果細心察看代碼的童鞋,一定發現代碼中有使用Handler,以及一些奇怪但又被注釋掉的代碼,比如"a.equals("b")"。從使用上來說,沒有必要使用handler,那干嘛要多次一舉?這里就給大家分享一下在寫NotificationListenerDemo時遇到的一些坑。
①. NotificationMonitor的onCreate方法中使用handler來調用getActiveNotifications()方法
? ? ? ??若直接在onCreate或者onBind方法中調用getActiveNotifications()方法是無法獲取當前系統通知。主要是因為NotificationMonitor還未完成初始化,而根本原因則是INotificationListenerWrapper對象mWrapper還未初始化,此時使用getActiveNotifications()方法又會調用到mWrapper,因此無法返回正常數據。在NotificationListenerService中可以看到getActiveNotifications()的源碼:
[java]?view plaincopy
public?StatusBarNotification[]?getActiveNotifications()?{??
????try?{??
????????return?getNotificationInterface().getActiveNotificationsFromListener(mWrapper);??
????}?catch?(android.os.RemoteException?ex)?{??
????????Log.v(TAG,?"Unable?to?contact?notification?manager",?ex);??
????}?????
????return?null;??
}??
也就是說只要在onBind方法完成之后,再調用getActiveNotifications()方法就可以正常獲取數據了,因此這里使用了handler多線程的方式。當然,為了保險可以使用sendEmptyMessgeDelay加上延時。
②. 如果NotificationMonitor在onCreate或onBind方法中crash,則該service已經失效,需重啟手機才能進行后續開發驗證
? ? ? ??如果在onCreate或者onBind方法中,出現異常導致NotificationMonitor發生crash,就算找到問題并將其改正,之后的驗證還是無法繼續進行的,也就是無法收到通知的新增和刪除消息,onNotificationPosted和onNotificationRemoved方法不會被調用。
? ? ? ? 這也是我在onBind方法中故意注釋導致空指針異常的代碼,有興趣的童鞋可以把注釋去掉后嘗試,去掉注釋會導致NotificationListenerDemo異常停止,此時你再加上注釋再次運行NotificationListenerDemo,雖然程序可以正常啟動,但無法正常執行NotificationMonitor中的onNotificationPosted和onNotificationRemoved方法。這個涉及NotificationListenerService的原理,后面會另行分析。
③. MainActivity中onClick方法里使用handler操作
? ? ? ??當點擊刪除通知時,系統通知相關狀態還未更新,此時還沒有回調到NotificationMonitor中,所以獲取的數據就還是上一次的數據。為了能夠獲取到正確的Notification數據,可以使用handler并加上延時,這樣再去獲取Notification信息時,系統已經觸發了NotificationMonitor回調,數據也有正常了。另外,50ms的延時幾乎是感知不到的。
④. 為什么要使用ArrayList來保存StatusBarNotification數組對象
? ? ? ??當新增或者刪除通知時,會觸發onNotificationPosted或onNotificationRemoved回調,在該方法中調用getActiveNotifications()方法用以獲取當前系統通知信息。而getActiveNotifications()返回的是StatusBarNotification[]數組,因為這個數組是可變長的,也就是長度會隨時變化,因此無法直接存儲。使用ArrayList可以很好的解決這個問題,在ArrayList對象中添加一個StatusBarNotification[]對象,之后使用ArrayList.set(0,statusbar[])方法對數據進行更新即可。
總結
? ? ? ??NotificationListenerService是Android 4.3 之后新增的接口服務,用于獲取系統Notification信息,這在之前的Android版本是無法直接辦到的。在Android 4.4中,增加了Notification.extra變量,使得獲取Notification相關信息更加豐富,這些接口的開放更加利于三方應用的使用,但同時也會帶來一些隱私問題。
? ? ? ??本文針對NotificationListenerService的使用進行了詳細分析,當然其中不乏有失偏頗的地方,本著互聯網知識共享精神也將自己的一些記錄發布出來,一來可做筆記,二來希望能夠給苦苦尋覓的童鞋一些幫助。
? ? ? ??后續會對NotificationListenerService的原理進行分析,敬請期待。
? ? ? ??NotificationMonitor代碼免積分下載:下載Demo
? ? ? ??為了后續能夠更新,已經代碼傳到github上,有興趣的童鞋可以在github上查看,連接戳這里。
轉載于:https://my.oschina.net/tingzi/blog/413666
總結
以上是生活随笔為你收集整理的NotificationManagerService使用详解与原理分析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 移动web开发规范
- 下一篇: 一键导出所有微信联系人的小工具,搞私域、