有的時候,我們不斷的發一個通知,如果次數達到定後,可能會導致通知欄消失(3.0以下的Android system),這個問題,其實是Android內部的一個Bug,下面我來分析一下造成這個問題的原因。
一,原因
當這個問題出現的時候,我們通過分析Log後得知,com.android.systemui進行中出現在ANR,原因就是處理廣播訊息時逾時,而這個ANR會導致com.android.systemui進程死掉。通常,狀態列會維護通知資訊,並會保持所有通知的remote views,如果當一個用戶端程式不斷的發送通知的話,系統就不地斷的使用記憶體來建立這些remote view,因此,就會導致記憶體回收行程(GC)開始回收記憶體,UI開始變慢(通俗一點說就是變卡),如果此時用戶端程式還不斷的發通知,那麼UI會變得越來越慢,最後,ANR錯誤出現了。我們可以寫一個DEMO來重現這個問題,起一個timer,不斷的發送通知,可能狀態列就會消失,此時的LOG如下:
D/dalvikvm(11985): GC_EXPLICIT freed 1258 objects / 84016 bytes in 1157msD/dalvikvm( 85): GC_FOR_MALLOC freed 52216 objects / 1900968 bytes in 130msD/dalvikvm( 85): GC_FOR_MALLOC freed 49465 objects / 1805248 bytes in 125msD/dalvikvm( 85): GC_FOR_MALLOC freed 53106 objects / 1909992 bytes in 134ms...12-10 15:07:11.088 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.098 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.098 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.098 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.108 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.128 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.128 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.138 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!12-10 15:07:11.158 E/JavaBinder( 2240): !!! FAILED BINDER TRANSACTION !!!
從這個LOG中可以看見,GC不斷的釋放記憶體,這會導致UI響應延遲。這種現象可以Android 2.1, 2.2, 2.3上面重現,3.0以上的我沒有試過,不知道是不是存在同樣的問題。當Notification bar中的RemoteView增長到一定數量之後,也就是說它超過了IBinder.transcat()所能處理的範圍,RemoteException異常就會拋出,有時候,如果起過了VM的限制,APP都可能會掛掉。
二,解決方案
關於這個問題,原因我們是知道了,如何解決。我們不要去每次發送通知,我們可以用相同的訊息ID去更新通知,而不是重新建立。
三,其他連結
這個問題,其實已經在Google的論壇上提出來了,可以參考:
http://code.google.com/p/android/issues/detail?id=13941
http://code.google.com/p/csipsimple/issues/detail?id=676