當我們從Home點擊ShortCut圖標啟動一個應用程序後,這個應用程序打開了很多個Activity,假設順序為A,B,C,然後我們按Home鍵,再次從桌面用圖標啟動這個應用程序,我們會發現顯示的是剛才的C,而不是A。這裡我們普遍的想法是按Home鍵是讓程序退到後台,然後讓桌面顯示出來。那麼我們就來看看Home鍵到底是怎麼回事。
在Framework中我們找到源碼,我們首先在interceptKeyBeforeDispatching這個方法中找到Home按鍵代碼如下
[java]
- // If the HOME button is currently being held, then we do special
- // chording with it.
- if (mHomePressed) {
-
- // If we have released the home key, and didn't do anything else
- // while it was pressed, then it is time to go home!
- if (keyCode == KeyEvent.KEYCODE_HOME) {
- if (!down) {
- mHomePressed = false;
-
- if (!canceled) {
- // If an incoming call is ringing, HOME is totally disabled.
- // (The user is already on the InCallScreen at this point,
- // and his ONLY options are to answer or reject the call.)
- boolean incomingRinging = false;
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- incomingRinging = phoneServ.isRinging();
- } else {
- Log.w(TAG, "Unable to find ITelephony interface");
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
- }
-
- if (incomingRinging) {
- Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
- } else {
- launchHomeFromHotKey();
- }
- } else {
- Log.i(TAG, "Ignoring HOME; event canceled.");
- }
- }
- }
-
- return true;
- }
這裡就是按Home鍵時執行的方法我們找到
[java]
- launchHomeFromHotKey();
- /**
- * A home key -> launch home action was detected. Take the appropriate action
- * given the situation with the keyguard.
- */
- void launchHomeFromHotKey() {
- if (mKeyguardMediator.isShowingAndNotHidden()) {
- // don't launch home if keyguard showing
- } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
- // when in keyguard restricted mode, must first verify unlock
- // before launching home
- mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
- public void onKeyguardExitResult(boolean success) {
- if (success) {
- try {
- ActivityManagerNative.getDefault().stopAppSwitches();
- } catch (RemoteException e) {
- }
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
- startDockOrHome();
- }
- }
- });
- } else {
- // no keyguard stuff to worry about, just launch home!
- try {
- ActivityManagerNative.getDefault().stopAppSwitches();
- } catch (RemoteException e) {
- }
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
- startDockOrHome();
- }
- }
再進入startDockOrHome();
[java]
- void startDockOrHome() {
- Intent dock = createHomeDockIntent();
- if (dock != null) {
- try {
- mContext.startActivity(dock);
- return;
- } catch (ActivityNotFoundException e) {
- }
- }
- mContext.startActivity(mHomeIntent);
- }
這裡我們發現,源碼中做了車載模式和普通模式Home的區別,在Android2.3原生系統中有車載模式這個應用程式,打開後按Home鍵我們返回的是車載模式的桌面,而普通情況下按Home返回正常桌面,再來看看mContext.startActivity(mHomeIntent)這個方法,我們發現,Home鍵也是打開一個activity,不同的是下面的代碼
[java]
- mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
- mHomeIntent.addCategory(Intent.CATEGORY_HOME);
- mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
這段代碼是在init()方法中,對mHomeIntent的初始化,這個Intent就是跳轉到Launcher程序中的配置了 <category android:name="android.intent.category.HOME" />這個屬性的Launcher Activity,另外我們還看到兩個flag
[java]
- FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
newTask保證了我們回到之前Launcher所在的棧,reset task if need是設置清理棧標志,保證清除掉該棧除Launcher以外其他activity(在Launcher清單文件中我們還看到android:clearTaskOnLaunch="true"這個屬性,後面會描述),這樣我們的Launcher當然會在自己單獨的Task中,而且android:launchMode="singleTask"這個屬性保證不會啟動一個新的Launcher。
通過Launcher啟動的其他Activity不會跑到Launcher所在的Task中(後面的文章會提到Launcher啟動activity的過程)。所以按Home鍵是打開了Launcher這個activity並且保證他在自己單獨的Task中,其他的activity進入stop狀態。
另外Launcher中打開一個activity直接進入之前打開的Task 而不是新打開一個activity.