標籤:android blog http io ar 使用 java on art
“Binder通訊是同步而不是非同步”,但是在實際使用時,是設計成用戶端同步而服務端非同步。
看看Framwork層的各service類java源碼便會知道,在用戶端調用服務端的各種方法時,通常會傳遞一個Binder過來,該Binder對象用於服務端做非同步回調,而服務端本身會使用handler或隊列的方式做成非同步處理。在Android中,系統service是作為"管理者"的身份存在的,像Ams(ActivityManagerService),它並不建立Activity,建立Activity的是用戶端的ActivityThread,但是每當ActivityThread想建立一個Acitivty,就必須告訴Ams,Ams會進行調度該Acitivty的建立。更簡單的一個例子,Toast和NotificationManagerService,Toast負責快顯視窗的建立顯示和隱藏,而何時顯示跟何時隱藏卻是由NotificationManagerService決定的。具體可以看看這篇文章Toast視窗的源碼分析。
我們可以發現,當隊列本來不為空白時,用戶端的同步在服務端執行完將ToastRecord放入隊列之後就可以結束了。服務端會通過連續取出隊列項並且回調用戶端的show()和hide()方法。而在服務度回調show()和hide()時,用戶端就成了”服務端“,這時它通過handler將本次真正的顯示和隱藏Toast視窗操作壓入Message隊列,再一次實現了非同步作業。
那為什麼要設計成這樣呢?以Toast為例,假如服務端不設計成非同步呼叫+使用Binder回調,那當有2個Toast請求同時過來時,為了實現序列化顯示(Toast每次只顯示一個,本次顯示完畢後才接下去顯示下一個),那麼第二個Toast進程就必須阻塞著等待第一個Toast顯示再隱藏,更糟糕的是,即使是第一個請求也必須在顯示之後阻塞著等待服務端發送隱藏指令。
(我在看源碼時對於每次IPC調用用戶端都會傳遞一個Binder對象到服務端覺得很奇怪,當時以為是為了"雙向通訊":服務端也可能需要用戶端的一些處理結果。但看了更多代碼後我覺得可能更準確的原因是為了非同步回調。以上只是個人理解,如有錯誤請指出。)
Android Binder機制中的非同步回調