<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 101,  comments - 29,  trackbacks - 0

            前面我們介紹了Android系統(tǒng)的廣播機制,從本質來說,它是一種消息訂閱/發(fā)布機制,因此,使用這種消息驅動模型的第一步便是訂閱消息;而對Android應用程序來說,訂閱消息其實就是注冊廣播接收器,本文將探討Android應用程序是如何注冊廣播接收器以及把廣播接收器注冊到哪里去的。

            在Android的廣播機制中,ActivityManagerService扮演著廣播中心的角色,負責系統(tǒng)中所有廣播的注冊和發(fā)布操作,因此,Android應用程序注冊廣播接收器的過程就把是廣播接收器注冊到ActivityManagerService的過程。Android應用程序是通過調用ContextWrapper類的registerReceiver函數來把廣播接收器BroadcastReceiver注冊到ActivityManagerService中去的,而ContextWrapper類本身又借助ContextImpl類來注冊廣播接收器。

            在Android應用程序框架中,Activity和Service類都繼承了ContextWrapper類,因此,我們可以在Activity或者Service的子類中調用registerReceiver函數來注冊廣播接收器。Activity、Service、ContextWrapper和ContextImpl這四個類的關系可以參考前面Android系統(tǒng)在新進程中啟動自定義服務過程(startService)的原理分析一文中描述的Activity類圖。

            這篇文章還是繼續(xù)以實例來進行情景分析,所用到的例子便是上一篇文章Android系統(tǒng)中的廣播(Broadcast)機制簡要介紹和學習計劃里面介紹的應用程序了,所以希望讀者在繼續(xù)閱讀本文之前,先看看這篇文章;又由于Android應用程序是把廣播接器注冊到ActivityManagerService中去的,因此,這里又會涉入到Binder進程間通信機制,所以希望讀者對Android系統(tǒng)的Binder進程間通信機制有所了解,具體請參考Android進程間通信(IPC)機制Binder簡要介紹和學習計劃一文。

            開始進入主題了,在Android系統(tǒng)中的廣播(Broadcast)機制簡要介紹和學習計劃一文所介紹的例子中,注冊廣播接收器的操作是MainActivity發(fā)起的,我們先來看看注冊過程的序列圖:


            在分析這個序列圖之前,我們先來看一下MainActivity是如何調用registerReceiver函數來注冊廣播接收器的:

    public class MainActivity extends Activity implements OnClickListener {  
    	......
    
    	@Override   
    	public void onResume() {  
    		super.onResume();  
    
    		IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);  
    		registerReceiver(counterActionReceiver, counterActionFilter);  
    	} 
    
    	......
    
    }
            MainActivity在onResume函數里,通過其父類ContextWrapper的registerReceiver函數注冊了一個BroadcastReceiver實例counterActionReceiver,并且通過IntentFilter實例counterActionFilter告訴ActivityManagerService,它要訂閱的廣播是CounterService.BROADCAST_COUNTER_ACTION類型的,這樣,ActivityManagerService在收到CounterService.BROADCAST_COUNTER_ACTION類型的廣播時,就會分發(fā)給counterActionReceiver實例的onReceive函數。

     

            接下來,就開始分析注冊過程中的每一個步驟了。

            Step 1. ContextWrapper.registerReceiver

            這個函數實現(xiàn)在frameworks/base/core/java/android/content/ContextWrapper.java文件中:

    public class ContextWrapper extends Context {
    	Context mBase;
    	......
    
    	@Override
    	public Intent registerReceiver(
    		BroadcastReceiver receiver, IntentFilter filter) {
    		return mBase.registerReceiver(receiver, filter);
    	}
    
    	......
    
    }
            這里的成員變量mBase是一個ContextImpl實例,想知道為什么,可以回過頭去看看Android應用程序啟動過程源代碼分析這篇文章>~<。

     

            Step 2. ContextImpl.registerReceiver

            這個函數實現(xiàn)在frameworks/base/core/java/android/app/ContextImpl.java文件中:

    class ContextImpl extends Context {
    	......
    
    	@Override
    	public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    		return registerReceiver(receiver, filter, null, null);
    	}
    
    	@Override
    	public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
    			String broadcastPermission, Handler scheduler) {
    		return registerReceiverInternal(receiver, filter, broadcastPermission,
    			scheduler, getOuterContext());
    	}
    
    	private Intent registerReceiverInternal(BroadcastReceiver receiver,
    			IntentFilter filter, String broadcastPermission,
    			Handler scheduler, Context context) {
    		IIntentReceiver rd = null;
    		if (receiver != null) {
    			if (mPackageInfo != null && context != null) {
    				if (scheduler == null) {
    					scheduler = mMainThread.getHandler();
    				}
    				rd = mPackageInfo.getReceiverDispatcher(
    					receiver, context, scheduler,
    					mMainThread.getInstrumentation(), true);
    			} else {
    				......
    			}
    		}
    		try {
    			return ActivityManagerNative.getDefault().registerReceiver(
    					mMainThread.getApplicationThread(),
    					rd, filter, broadcastPermission);
    		} catch (RemoteException e) {
    				return null;
    		}
    	}
    
    	......
    
    }
            通過兩個函數的中轉,最終就進入到ContextImpl.registerReceiverInternal這個函數來了。這里的成員變量mPackageInfo是一個LoadedApk實例,它是用來負責處理廣播的接收的,在后面一篇文章講到廣播的發(fā)送時(sendBroadcast),會詳細描述。參數broadcastPermission和scheduler都為null,而參數context是上面的函數通過調用函數getOuterContext得到的,這里它就是指向MainActivity了,因為MainActivity是繼承于Context類的,因此,這里用Context類型來引用。

     

            由于條件mPackageInfo != null和context != null都成立,而且條件scheduler == null也成立,于是就調用mMainThread.getHandler來獲得一個Handler了,這個Hanlder是后面用來分發(fā)ActivityManagerService發(fā)送過的廣播用的。這里的成員變量mMainThread是一個ActivityThread實例,在前面Android應用程序啟動過程源代碼分析這篇文章也描述過了。我們先來看看ActivityThread.getHandler函數的實現(xiàn),然后再回過頭來繼續(xù)分析ContextImpl.registerReceiverInternal函數。

            Step 3. ActivityThread.getHandler

            這個函數實現(xiàn)在frameworks/base/core/java/android/app/ActivityThread.java文件中:

    public final class ActivityThread {
    	......
    
    	final H mH = new H();
    
    	private final class H extends Handler {
    		......
    
    		public void handleMessage(Message msg) {
    			......
    
    			switch (msg.what) {
    			......
    			}
    
    			......
    		}
    
    		......
    
    	}
    
    	......
    
    	final Handler getHandler() {
    		return mH;
    	}
    
    	......
    
    }
            有了這個Handler之后,就可以分發(fā)消息給應用程序處理了。

     

            再回到上一步的ContextImpl.registerReceiverInternal函數中,它通過mPackageInfo.getReceiverDispatcher函數獲得一個IIntentReceiver接口對象rd,這是一個Binder對象,接下來會把它傳給ActivityManagerService,ActivityManagerService在收到相應的廣播時,就是通過這個Binder對象來通知MainActivity來接收的。

            我們也是先來看一下mPackageInfo.getReceiverDispatcher函數的實現(xiàn),然后再回過頭來繼續(xù)分析ContextImpl.registerReceiverInternal函數。

            Step 4. LoadedApk.getReceiverDispatcher

            這個函數實現(xiàn)在frameworks/base/core/java/android/app/LoadedApk.java文件中:

    final class LoadedApk {
    	......
    
    	public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
    			Context context, Handler handler,
    			Instrumentation instrumentation, boolean registered) {
    		synchronized (mReceivers) {
    			LoadedApk.ReceiverDispatcher rd = null;
    			HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
    			if (registered) {
    				map = mReceivers.get(context);
    				if (map != null) {
    					rd = map.get(r);
    				}
    			}
    			if (rd == null) {
    				rd = new ReceiverDispatcher(r, context, handler,
    					instrumentation, registered);
    				if (registered) {
    					if (map == null) {
    						map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
    						mReceivers.put(context, map);
    					}
    					map.put(r, rd);
    				}
    			} else {
    				rd.validate(context, handler);
    			}
    			return rd.getIIntentReceiver();
    		}
    	}
    
    	......
    
    	static final class ReceiverDispatcher {
    
    		final static class InnerReceiver extends IIntentReceiver.Stub {
    			final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
    			......
    
    			InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
    				mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
    				......
    			}
    
    			......
    		}
    
    		......
    
    		final IIntentReceiver.Stub mIIntentReceiver;
    		final Handler mActivityThread;
    
    		......
    
    		ReceiverDispatcher(BroadcastReceiver receiver, Context context,
    				Handler activityThread, Instrumentation instrumentation,
    				boolean registered) {
    			......
    
    			mIIntentReceiver = new InnerReceiver(this, !registered);
    			mActivityThread = activityThread;
    			
    			......
    		}
    
    		......
    
    		IIntentReceiver getIIntentReceiver() {
    			return mIIntentReceiver;
    		}
    
    	}
    
    	......
    
    }

     

            在LoadedApk.getReceiverDispatcher函數中,首先看一下參數r是不是已經有相應的ReceiverDispatcher存在了,如果有,就直接返回了,否則就新建一個ReceiverDispatcher,并且以r為Key值保在一個HashMap中,而這個HashMap以Context,這里即為MainActivity為Key值保存在LoadedApk的成員變量mReceivers中,這樣,只要給定一個Activity和BroadcastReceiver,就可以查看LoadedApk里面是否已經存在相應的廣播接收發(fā)布器ReceiverDispatcher了。

            在新建廣播接收發(fā)布器ReceiverDispatcher時,會在構造函數里面創(chuàng)建一個InnerReceiver實例,這是一個Binder對象,實現(xiàn)了IIntentReceiver接口,可以通過ReceiverDispatcher.getIIntentReceiver函數來獲得,獲得后就會把它傳給ActivityManagerService,以便接收廣播。在ReceiverDispatcher類的構造函數中,還會把傳進來的Handle類型的參數activityThread保存下來,以便后面在分發(fā)廣播的時候使用。

            現(xiàn)在,再回到ContextImpl.registerReceiverInternal函數,在獲得了IIntentReceiver類型的Binder對象后,就開始要把它注冊到ActivityManagerService中去了。

            Step 5. ActivityManagerProxy.registerReceiver

            這個函數實現(xiàn)在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

    class ActivityManagerProxy implements IActivityManager
    {
    	......
    
    	public Intent registerReceiver(IApplicationThread caller,
    			IIntentReceiver receiver,
    			IntentFilter filter, String perm) throws RemoteException
    	{
    		Parcel data = Parcel.obtain();
    		Parcel reply = Parcel.obtain();
    		data.writeInterfaceToken(IActivityManager.descriptor);
    		data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    		data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
    		filter.writeToParcel(data, 0);
    		data.writeString(perm);
    		mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
    		reply.readException();
    		Intent intent = null;
    		int haveIntent = reply.readInt();
    		if (haveIntent != 0) {
    			intent = Intent.CREATOR.createFromParcel(reply);
    		}
    		reply.recycle();
    		data.recycle();
    		return intent;
    	}
    
    	......
    
    }
    
             這個函數通過Binder驅動程序就進入到ActivityManagerService中的registerReceiver函數中去了。

     

             Step 6. ActivityManagerService.registerReceiver

             這個函數實現(xiàn)在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

    public final class ActivityManagerService extends ActivityManagerNative
    		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    	......
    
    	public Intent registerReceiver(IApplicationThread caller,
    			IIntentReceiver receiver, IntentFilter filter, String permission) {
    		synchronized(this) {
    			ProcessRecord callerApp = null;
    			if (caller != null) {
    				callerApp = getRecordForAppLocked(caller);
    				if (callerApp == null) {
    					......
    				}
    			}
    
    			List allSticky = null;
    
    			// Look for any matching sticky broadcasts...
    			Iterator actions = filter.actionsIterator();
    			if (actions != null) {
    				while (actions.hasNext()) {
    					String action = (String)actions.next();
    					allSticky = getStickiesLocked(action, filter, allSticky);
    				}
    			} else {
    				......
    			}
    
    			// The first sticky in the list is returned directly back to
    			// the client.
    			Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
    
    			......
    
    			if (receiver == null) {
    				return sticky;
    			}
    
    			ReceiverList rl
    				= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
    			if (rl == null) {
    				rl = new ReceiverList(this, callerApp,
    					Binder.getCallingPid(),
    					Binder.getCallingUid(), receiver);
    
    				if (rl.app != null) {
    					rl.app.receivers.add(rl);
    				} else {
    					......
    				}
    				mRegisteredReceivers.put(receiver.asBinder(), rl);
    			}
    
    			BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
    			rl.add(bf);
    			......
    			mReceiverResolver.addFilter(bf);
    
    			// Enqueue broadcasts for all existing stickies that match
    			// this filter.
    			if (allSticky != null) {
    				......
    			}
    
    			return sticky;
    		}
    	}
    
    	......
    
    }
             函數首先是獲得調用registerReceiver函數的應用程序進程記錄塊:

     

        ProcessRecord callerApp = null;
        if (caller != null) {
    	callerApp = getRecordForAppLocked(caller);
    	if (callerApp == null) {
    	    ......
            }
        }
            這里得到的便是上一篇文章Android系統(tǒng)中的廣播(Broadcast)機制簡要介紹和學習計劃里面介紹的應用程序Broadcast的進程記錄塊了,MainActivity就是在里面啟動起來的。

     

            

        List allSticky = null;
    
        // Look for any matching sticky broadcasts...
        Iterator actions = filter.actionsIterator();
        if (actions != null) {
    	while (actions.hasNext()) {
    		String action = (String)actions.next();
    		allSticky = getStickiesLocked(action, filter, allSticky);
    	}
        } else {
    	......
        }
    
        // The first sticky in the list is returned directly back to
        // the client.
        Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
            這里傳進來的filter只有一個action,就是前面描述的CounterService.BROADCAST_COUNTER_ACTION了,這里先通過getStickiesLocked函數查找一下有沒有對應的sticky intent列表存在。什么是Sticky Intent呢?我們在最后一次調用sendStickyBroadcast函數來發(fā)送某個Action類型的廣播時,系統(tǒng)會把代表這個廣播的Intent保存下來,這樣,后來調用registerReceiver來注冊相同Action類型的廣播接收器,就會得到這個最后發(fā)出的廣播。這就是為什么叫做Sticky Intent了,這個最后發(fā)出的廣播雖然被處理完了,但是仍然被粘住在ActivityManagerService中,以便下一個注冊相應Action類型的廣播接收器還能繼承處理。

     

            這里,假設我們不使用sendStickyBroadcast來發(fā)送CounterService.BROADCAST_COUNTER_ACTION類型的廣播,于是,這里得到的allSticky和sticky都為null了。

            繼續(xù)往下看,這里傳進來的receiver不為null,于是,繼續(xù)往下執(zhí)行:

        ReceiverList rl
    	= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
    	rl = new ReceiverList(this, callerApp,
    		Binder.getCallingPid(),
    		Binder.getCallingUid(), receiver);
    
    	if (rl.app != null) {
    		rl.app.receivers.add(rl);
    	} else {
    		......
    	}
    	mRegisteredReceivers.put(receiver.asBinder(), rl);
        }
            這里其實就是把廣播接收器receiver保存一個ReceiverList列表中,這個列表的宿主進程是rl.app,這里就是MainActivity所在的進程了,在ActivityManagerService中,用一個進程記錄塊來表示這個應用程序進程,它里面有一個列表receivers,專門用來保存這個進程注冊的廣播接收器。接著,又把這個ReceiverList列表以receiver為Key值保存在ActivityManagerService的成員變量mRegisteredReceivers中,這些都是為了方便在收到廣播時,快速找到對應的廣播接收器的。

     

            再往下看:

        BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
        rl.add(bf);
        ......
        mReceiverResolver.addFilter(bf);
            上面只是把廣播接收器receiver保存起來了,但是還沒有把它和filter關聯(lián)起來,這里就創(chuàng)建一個BroadcastFilter來把廣播接收器列表rl和filter關聯(lián)起來,然后保存在ActivityManagerService中的成員變量mReceiverResolver中去。

     

            這樣,廣播接收器注冊的過程就介紹完了,比較簡單,但是工作又比較瑣碎,主要就是將廣播接收器receiver及其要接收的廣播類型filter保存在ActivityManagerService中,以便以后能夠接收到相應的廣播并進行處理,在下一篇文章,我們將詳細分析這個過程,敬請關注。

    作者:Luoshengyang 發(fā)表于2011-9-2 1:26:33 原文鏈接
    閱讀:7141 評論:14 查看評論
    posted on 2012-04-17 21:32 mixer-a 閱讀(760) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網站導航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 天天操夜夜操免费视频| 成人黄页网站免费观看大全| 久久久久噜噜噜亚洲熟女综合| 亚洲熟妇AV一区二区三区浪潮| 夜夜春亚洲嫩草影院| 日本一区二区三区在线视频观看免费 | 中文字幕在线免费看线人| 亚洲日韩在线观看免费视频| caoporm碰最新免费公开视频| 青青草原亚洲视频| 成全动漫视频在线观看免费高清版下载| 亚洲黄片毛片在线观看| 黄视频在线观看免费| 久久精品国产亚洲网站| 亚洲妇女熟BBW| 免费黄色小视频网站| 国产99久久亚洲综合精品| 97免费人妻在线视频| 亚洲国产亚洲片在线观看播放| 久久精品免费大片国产大片| 亚洲国产日韩在线视频| 亚洲精品在线免费观看| 色噜噜AV亚洲色一区二区| 无码av免费一区二区三区| 亚洲女人被黑人巨大进入| 日韩电影免费在线观看网站| 亚洲男人的天堂在线播放| 黄色网址免费大全| 亚洲AV一宅男色影视| 91香蕉成人免费网站| 久久久久久亚洲av无码蜜芽| 亚洲国产成人影院播放| 99视频在线精品免费| 亚洲色少妇熟女11p| 亚洲综合另类小说色区| 成年人视频免费在线观看| 看成年女人免费午夜视频| 亚洲视频2020| 亚洲精品无码av天堂| 国产成人精品久久免费动漫| 91亚洲精品视频|