編輯:Android開發教程
現在給出第二步分的分析
下面就來看看發送廣播的流程
Context中的sendBroadCast函數的 實現是在ContextImpl中,和發送廣播相關的有如下六個函數
void android.app.ContextImpl.sendBroadcast(Intent intent)
void android.app.ContextImpl.sendBroadcast(Intent intent, String receiverPermission)
void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission)
void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
void android.app.ContextImpl.sendStickyBroadcast(Intent intent)
void android.app.ContextImpl.sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
可以分為3組:1普通廣播;2Ordered廣播;3Sticky廣播
不論哪種,最後都會 由ActivityManagerService處理
private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean ordered, boolean sticky, int callingPid, int callingUid)
以第一種情況為 例,流程圖大概是這個樣子的
ordered和sticky用來區分上面3組廣播
下面我們仔細看看這個方 法都干了些什麼
刪減了一些代碼
private final int broadcastIntentLocked (ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean ordered, boolean sticky, int callingPid, int callingUid) { ...//處理特殊intent // Add to the sticky list if requested. ...//處理sticky廣播 // Figure out who all will receive this broadcast. List receivers = null; List<BroadcastFilter> registeredReceivers = null; try { if (intent.getComponent() != null) { // Broadcast is going to one specific receiver class... ActivityInfo ai = AppGlobals.getPackageManager(). getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS); if (ai != null) { receivers = new ArrayList(); ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; receivers.add(ri); } } else { // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = AppGlobals.getPackageManager().queryIntentReceivers( intent, resolvedType, STOCK_PM_FLAGS); } registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); } } catch (RemoteException ex) { // pm is in same process, this will never happen. } final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; ... int NR = registeredReceivers != null ? registeredReceivers.size() : 0; ...//如果廣播是非ordered,先處理動態注冊的接收器 if (!ordered && NR > 0) { // If we are not serializing this broadcast, then send the // registered receivers separately so they don't wait for the // components to be launched. BroadcastRecord r = new BroadcastRecord(intent, callerApp, callerPackage, callingPid, callingUid, requiredPermission, registeredReceivers, resultTo, resultCode, resultData, map, ordered, sticky, false); ... //mParallelBroadcasts只含有動態注冊的receiver boolean replaced = false; if (replacePending) { for (int i=mParallelBroadcasts.size()-1; i>=0; i--) { if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) { if (DEBUG_BROADCAST) Slog.v(TAG, "***** DROPPING PARALLEL: " + intent); mParallelBroadcasts.set(i, r); replaced = true; break; } } } if (!replaced) { mParallelBroadcasts.add(r); scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; } // Merge into one list. //如果廣播是ordered,合並靜態、動態接收器 //否則之前處理過動態接收器,這裡registeredReceivers為null int ir = 0; if (receivers != null) { ... //合並的過程,注意順序 int NT = receivers != null ? receivers.size() : 0; int it = 0; ResolveInfo curt = null; BroadcastFilter curr = null; while (it < NT && ir < NR) { if (curt == null) { curt = (ResolveInfo)receivers.get(it); } if (curr == null) { curr = registeredReceivers.get(ir); } //如果動態接收器優先級高,那麼就插到前面 //否則進入else,然後進行下一輪比較,拿下一個靜態接收器與之前的動態接收器比較,直到找到自己的位置才插入進列表中 //在這裡,調整好接收器的順序,同等優先級的,顯然動態的要在靜態的前面 if (curr.getPriority() >= curt.priority) { // Insert this broadcast record into the final list. receivers.add(it, curr); ir++; curr = null; it++; NT++; } else { // Skip to the next ResolveInfo in the final list. it++; curt = null; } } } while (ir < NR) { if (receivers == null) { receivers = new ArrayList(); } receivers.add(registeredReceivers.get(ir)); ir++; } if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastRecord r = new BroadcastRecord(intent, callerApp, callerPackage, callingPid, callingUid, requiredPermission, receivers, resultTo, resultCode, resultData, map, ordered, sticky, false); ... if (!replaced) { mOrderedBroadcasts.add(r); scheduleBroadcastsLocked(); } } return BROADCAST_SUCCESS; }
android.Content包定義了一些類,這些類主要用於在設備上訪問或是發布數據,主要有三個包構成。Content 共享 (android.content) 主要用於
這個例子需要Android系統中安裝了支持RecognizerIntent.ACTION_RECOGNIZE_SPEECH的應用,比如Google的 Voice Sear
一、為何寫作此文你是不是經常看到很多書籍中說:不能在子線程中操作ui,不然會報錯。你是不是也遇到了如下的疑惑(見下面的代碼): (Bundle savedI
這裡歸納寫一個android網絡框架的一般性原理:Http網絡請求原理學過《計算機網絡》的應該都知道http是一種應用層協議,它通過tcp實現了可靠的數據傳輸,能夠保證數