開發(fā)中經常使用的 Notification 以及 桌面小部件都是講應用進程的 view 現實在系統(tǒng)進程中动壤,這么神奇的事情是如何實現的颖对,這篇文章會說明白荣月,主要是對 PendingIntent 和 RemoteViews 的使用。
一兴垦、PendingIntent
首先肤视,在使用 Notification 時如果我們要為 View 添加點擊事件档痪,都會使用到 PendingIntent 類,那么 PendingIntent 是什么邢滑,PendingIntent 是一種在遠程進程中響應的 Intent腐螟,關于 PendingIntent 的 flag 參數有幾點需要注意,下面細看
PendingIntent 的 flag
1. PendingIntent.FLAG_ONE_SHOT 這個標記的表現為困后,如果兩個 RemoteViews 使用了同一個 PendingIntent乐纸,如果一個 RemoteViews 的點擊事件被激活,則 PendingIntent 則會失效摇予,其他的 Remoteviews 的響應事件將會消失汽绢,表現為點擊沒有反應。
2. PendingIntent.FLAG_CANCEL_CURRENT 這個標記表現為侧戴,如果兩個 RemoteViews 使用的 PendingIntent 是相同的(相同的定義為 Intent 相同宁昭,并且 requestCode 相同,并不是同一個)酗宋,那么之前使用這個 PendingIntent 的會 cancel积仗,第二個的 PendingIntent 為重新創(chuàng)建的,可以正常工作本缠,舊的 RemoteViews 設置的 PendingIntent 會失效
3. PendingIntent.FLAG_UPDATE_CURRENT 這個標記位斥扛,只要有相同的 PendingInten 其都會更新
PendingIntent 的主要方法
1. get 系列方法 在 NMS 中注冊 PendingIntent入问,注冊之后丹锹,PendingIntent 的 send 方法被調用時會執(zhí)行 PendingIntent 初始化時設定的操作
2. send 方法,激活已注冊的 PendingIntent芬失,在遠程進程中注冊的事件被激活時楣黍,則會通過 IPC 調用 PendingIntent 中指定的操作
3. cancel 取消注冊的 PendingIntent ,取消之后 send 方法將失效
二棱烂、RemoteViews
RemoteViews 繼承了 Parcelable 接口租漂,是可以跨進程傳遞的
創(chuàng)建時需要需要指明 View 的布局 id,以及該布局所在的進程的包名,創(chuàng)建 RemoteViews
調用 RemoteViews.setOnClickPendingIntent 方法哩治,為 RemoteViews 添加點擊事件
RemoteViews 使用
本地進程創(chuàng)建 RemoteViews 對象秃踩,并在 set 系列方法時創(chuàng)建 Action 對象,并加入 RemoteViews 內部的集合中
通過 NMS 將 RemoteViews 傳遞到系統(tǒng)進程
系統(tǒng)進程得到 RemoteViews 业筏,根據包名和 layoutId 得到 View憔杨,調用 performApply 方法,其中遍歷 Action 集合中的 Action 對象并調用其 applay/reApply蒜胖,為 View 中的子 View 初始化顯示消别,最后再系統(tǒng)進程將 view 顯示
1. Action 原理
Action 在構造方法中保存了待操作的 View 的 id,要操作方法名台谢,以及要設置的屬性值寻狂,需要顯示時調用 Action 對象的 applay/reApply 方法通過反射調用相應 id 的控件的對應方法,并將要設置的值傳入朋沮,實現在遠程進程中的設置蛇券。
注意,在布局文件中應該指定控件的顏色等信息朽们,如果跨進程怀读,這些如果是默認狀態(tài)可能效果不同預期,所以需要確定這些信息時要對 RemoteViews 顯式設置
2. RemoteViews 單擊事件
RemoteViews 中只支持 PendingIntent骑脱,不支持 OnClickListener菜枷,所以需要為 RemoteViews 設置單機事件時需要通過 setPendingIntent 方法設置添加
如果要給 ListView 添加 item 的點擊事件,必須將 setPendingIntentTemplate 和 setOnClickFillIntent 組合使用
三叁丧、RemoteViews 的使用及意義
1啤誊、Notification 頂部通知
Nofication 在創(chuàng)建時其實就是通過 RemoteViews 來設置要顯示的布局,再調用 NotificationManager 的 notify 方法拥娄,notify 方法中會通過 IPC 將 RemoteViews 傳遞到 NotificationManagerService 系統(tǒng)服務中蚊锹,NMS 中根據 id 和包名得到 layout 布局,在調用 RemoteViews 的 applay/reApplay 方法初始化布局顯示稚瘾,最后將布局顯示到屏幕上
2牡昆、AppWidget 桌面小部件點擊時顯示修改
AppWidget 同樣使用 RemoteViews 來實現,AppWidgetProvider 是一個廣播接收者摊欠,運行在應用進程丢烘,通過特定的注冊方式系統(tǒng)可以將其關聯的小部件顯示到桌面上并添加單擊響應事件。在收到響應時系統(tǒng)會通過廣播的形式將對應事件發(fā)送到AppWidgetProvider 中些椒,相對于 AppWidgetProvider 桌面小部件所在的系統(tǒng)進程是遠程進程播瞳,所以要修改桌面小部件的顯示時需要通過 RemoteViews 來將需要顯示的布局傳遞到系統(tǒng)進程中
在 AppWidgetProvider 中收到單擊事件時,首先構建 RemoteViews 免糕,并通過 set 系列方法設置布局顯示以及添加點擊響應 PendingIntent赢乓,然后調用 AppWidgetManager 的 updateAppWidget 方法忧侧。updateAppWidget 該方法中會通過 IPC 調用 AppWidgetManagerService 的 updateAppWidgetProvider 方法將 RemoteViews 傳遞到系統(tǒng)進程,AppWidgetManagerService 中會根據 RemoteViews 的布局來更新舊的桌面小部件實現單擊時桌面小部件顯示的變化牌芋。