日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NotificationManagerService使用详解与原理分析(一)

發布時間:2023/12/9 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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使用详解与原理分析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。