如果想在Android手機要想擴展一個實體鍵,就我知道而言有兩種方法,基於Android4.0的源碼來分析的和2.3的源碼有點區別,區別不大,下面分享給大家:
轉載請標明出處:
(一)可以在frameworks層的KeyEvent.java這個類中定義一個值,在PhoneWindowManager.java這個類中做處理就可以了。(Home鍵就是這麼實現的)。效果圖如下:
(二)可以利用廣播的形式,frameworks層PhoneWindow.java這個類的onKeyDown( )對這個實體鍵發廣播,上層接受這個廣播來處理也可以達到這個效果。耳機鍵就是利用廣播來接受的。無論在哪個界面長按耳機鍵,都會進入到音樂的界面。(長按耳機鍵的)效果圖如下:
下面我詳細展開來說明一下:
一、先說Home鍵的實現的大致流程,即---->爲什麼點擊Home鍵,都進入到launcher的待機界面;
(1)Home鍵的定義在
step1: frameworks/base/core/java/android/view/KeyEvent.java這個類中,在KeyEvent.java這個類中有個static的靜態塊:
- static {
- populateKeycodeSymbolicNames();
- }
step2: 這個populateKeycodeSymbolicNames()方法其實就是加載了許多鍵的定義,把這些鍵對應的值都放到Array數組中。
- <span style="FONT-SIZE: 16px">private static void populateKeycodeSymbolicNames() {
- SparseArray<String> names = KEYCODE_SYMBOLIC_NAMES;
- names.append(KEYCODE_UNKNOWN, "KEYCODE_UNKNOWN");
- names.append(KEYCODE_SOFT_LEFT, "KEYCODE_SOFT_LEFT");
- names.append(KEYCODE_SOFT_RIGHT, "KEYCODE_SOFT_RIGHT");
- names.append(KEYCODE_HOME, "KEYCODE_HOME");
- names.append(KEYCODE_BACK, "KEYCODE_BACK");
- names.append(KEYCODE_CALL, "KEYCODE_CALL");
- names.append(KEYCODE_ENDCALL, "KEYCODE_ENDCALL");
- names.append(KEYCODE_0, "KEYCODE_0");
- names.append(KEYCODE_1, "KEYCODE_1");
- names.append(KEYCODE_2, "KEYCODE_2");
- names.append(KEYCODE_3, "KEYCODE_3");
- names.append(KEYCODE_4, "KEYCODE_4");
- names.append(KEYCODE_5, "KEYCODE_5");
- names.append(KEYCODE_6, "KEYCODE_6");
- names.append(KEYCODE_7, "KEYCODE_7");
- names.append(KEYCODE_8, "KEYCODE_8");
- names.append(KEYCODE_9, "KEYCODE_9");</span>
step3: 而Home鍵對應的值如下:
- <span style="FONT-SIZE: 16px">/** Key code constant: Home key.
- * This key is handled by the framework and is never delivered to applications. */
- public static final int KEYCODE_HOME = 3;</span>
(2)Home鍵的處理如下:在
step1: frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java這個類中:
在這個方法interceptKeyBeforeDispatching(... ... ...)中處理有對Home,Search,menu,音量大小鍵等等:
- <span style="FONT-SIZE: 16px"> /** {@inheritDoc} */
- @Override
- public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
- final boolean keyguardOn = keyguardOn();
- final int keyCode = event.getKeyCode();
- final int repeatCount = event.getRepeatCount();
- final int metaState = event.getMetaState();
- final int flags = event.getFlags();
- final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
- final boolean canceled = event.isCanceled();
- if (false) {
- Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
- + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
- }
- // If we think we might have a volume down & power key chord on the way
- // but we're not sure, then tell the dispatcher to wait a little while and
- // try again later before dispatching.
- if ((flags & KeyEvent.FLAG_FALLBACK) == 0) {
- if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) {
- final long now = SystemClock.uptimeMillis();
- final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
- if (now < timeoutTime) {
- return timeoutTime - now;
- }
- }
- if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
- && mVolumeDownKeyConsumedByScreenshotChord) {
- if (!down) {
- mVolumeDownKeyConsumedByScreenshotChord = false;
- }
- return -1;
- }
- }
- // First we always handle the home key here, so applications
- // can never break it, although if keyguard is on, we do let
- // it handle it, because that gives us the correct 5 second
- // timeout.
- if (keyCode == KeyEvent.KEYCODE_HOME) {
- // 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 (mHomePressed && !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 telephonyService = getTelephonyService();
- if (telephonyService != null) {
- incomingRinging = telephonyService.isRinging();
- }
- } 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 -1;
- }
- // If a system window has focus, then it doesn't make sense
- // right now to interact with applications.
- WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
- if (attrs != null) {
- final int type = attrs.type;
- if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
- || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
- // the "app" is keyguard, so give it the key
- return 0;
- }
- final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
- for (int i=0; i<typeCount; i++) {
- if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
- // don't do anything, but also don't pass it to the app
- return -1;
- }
- }
- }
- if (down) {
- if (repeatCount == 0) {
- mHomePressed = true;
- } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
- if (!keyguardOn) {
- handleLongPressOnHome();
- }
- }
- }
- return -1;
- } else if (keyCode == KeyEvent.KEYCODE_MENU) {
- ........</span>
- <span style="FONT-SIZE: 16px"></span>
- <span style="font-size:24px;"> </span><span style="font-size:18px;">Step2: <span style="color:#990000;"><strong>插曲</strong></span>《<span style="color:#006600;"><strong>網上有例子說怎麼在自己的應用中屏蔽Home鍵</strong></span>》--->原理:是在你的應用的Activity中加入了鎖屏的type,因爲系統對鎖屏界面,點擊Home鍵失效!網摘代碼如下:</span>
- public class DMActivity extends Activity {
- private boolean flag = true;//true位屏蔽,false位不屏蔽
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
- @Override
- public void onAttachedToWindow() {
- if(flag) {
- this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
- }
- super.onAttachedToWindow();
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if(keyCode == KeyEvent.KEYCODE_HOME){
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
- }
Step3: 真正的原因如下,對鎖屏模式的處理:
- <span style="FONT-SIZE: 16px"> // If a system window has focus, then it doesn't make sense
- // right now to interact with applications.
- WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
- if (attrs != null) {
- final int type = attrs.type;
- if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
- || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
- // the "app" is keyguard, so give it the key
- return 0;
- }
- final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
- for (int i=0; i<typeCount; i++) {
- if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
- // don't do anything, but also don't pass it to the app
- return -1;
- }
- }
- }</span>
Step4: 我們來看點擊home鍵,爲什麼進入到launcher的待機界面:
- <span style="FONT-SIZE: 16px">// 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 (mHomePressed && !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 telephonyService = getTelephonyService();
- if (telephonyService != null) {
- incomingRinging = telephonyService.isRinging();
- }
- } 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 -1;
- }</span>
Step5: 系統會判斷,當前點擊Home鍵並且沒有電話打入的情況,纔對Home鍵進行處理---->launchHomeFromHotKey();進入到----->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();
- }
- }
Step6: 也是對鎖屏模式有個判斷,如果不在鎖屏模式,就launch Home---->startDockOrHome(),進入——>
- <span style="FONT-SIZE: 16px"> void startDockOrHome() {
- Intent dock = createHomeDockIntent();
- if (dock != null) {
- try {
- mContext.startActivity(dock);
- return;
- } catch (ActivityNotFoundException e) {
- }
- }
- mContext.startActivity(mHomeIntent);
- }</span>
Step 7: 其實這個createHomeDockIntent()方法就是對android手機的幾種模式進行判斷,
The device is not in either car mode or desk mode
The device is in car mode but ENABLE_CAR_DOCK_HOME_CAPTURE is false
The device is in desk mode but ENABLE_DESK_DOCK_HOME_CAPTURE is false
The device is in car mode but there's no CAR_DOCK app with METADATA_DOCK_HOME
The device is in desk mode but there's no DESK_DOCK app with METADATA_DOCK_HOME
如果是以上模式,車載模式或者桌面模式,就返回dock不爲空,否則爲空。啓動這個mHomeIntent。----->mHomeIntent定義如下:
- <span style="FONT-SIZE: 16px"> 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);</span>
Step 8: 這個mHomeIntent就是啓動activity中配置Category屬性的值爲CATEGORY_HOME,啓動的時候新啓動一個任務,不是在當前的這個任務中啓動launcherHome,而是新建一個task。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標記進入前臺時(典型的操作是用戶在主畫面重啓它),這個Activity和它之上的都將關閉,以至於用戶不能再返回到它們,但是可以回到之前的Activity。
到這爲止,Home鍵的流程已經分析完了。
二 、下面看看長按耳機鍵接受的廣播的處理方式:
(1)這個長按耳機鍵捕獲是在PhoneWindow.java類的onKeyDown()中,然後發送有序的廣播---->如下:
- <span xmlns="http://www.w3.org/1999/xhtml"><span xmlns="http://www.w3.org/1999/xhtml"><span xmlns="http://www.w3.org/1999/xhtml"> case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }</span></span></span>
接受這個長按耳機鍵的廣播是在Music的app中的----->
public class MediaButtonIntentReceiver extends BroadcastReceiver{ ... ... }
, 需要在Manifest.xml中註冊這個廣播<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>。---->註冊MediaButtonReceiver這個廣播,
這個類中onReceive()方法定義的:代碼如下--->
- <span style="FONT-SIZE: 16px"> @Override
- public void onReceive(Context context, Intent intent) {
- String intentAction = intent.getAction();
- if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) {
- Intent i = new Intent(MediaPlaybackService.SERVICECMD);
- i.putExtra(MediaPlaybackService.CMDNAME, MediaPlaybackService.CMDPAUSE);
- context.sendBroadcast(i);
- } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
- KeyEvent event = (KeyEvent)
- intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
- if (event == null) {
- return;
- }
- int keycode = event.getKeyCode();
- int action = event.getAction();
- long eventtime = event.getEventTime();
- // single quick press: pause/resume.
- // double press: next track
- // long press: start auto-shuffle mode.
- String command = null;
- switch (keycode) {
- case KeyEvent.KEYCODE_MEDIA_STOP:
- command = MediaPlaybackService.CMDSTOP;
- break;
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- command = MediaPlaybackService.CMDTOGGLEPAUSE;
- break;
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- command = MediaPlaybackService.CMDNEXT;
- break;
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- command = MediaPlaybackService.CMDPREVIOUS;
- break;
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- command = MediaPlaybackService.CMDPAUSE;
- break;
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- command = MediaPlaybackService.CMDPLAY;
- break;
- }
- if (command != null) {
- if (action == KeyEvent.ACTION_DOWN) {
- if (mDown) {
- if ((MediaPlaybackService.CMDTOGGLEPAUSE.equals(command) ||
- MediaPlaybackService.CMDPLAY.equals(command))
- && mLastClickTime != 0
- && eventtime - mLastClickTime > LONG_PRESS_DELAY) {
- mHandler.sendMessage(
- mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context));
- }
- } else if (event.getRepeatCount() == 0) {
- // only consider the first event in a sequence, not the repeat events,
- // so that we don't trigger in cases where the first event went to
- // a different app (e.g. when the user ends a phone call by
- // long pressing the headset button)
- // The service may or may not be running, but we need to send it
- // a command.
- Intent i = new Intent(context, MediaPlaybackService.class);
- i.setAction(MediaPlaybackService.SERVICECMD);
- if (keycode == KeyEvent.KEYCODE_HEADSETHOOK &&
- eventtime - mLastClickTime < 300) {
- i.putExtra(MediaPlaybackService.CMDNAME, MediaPlaybackService.CMDNEXT);
- context.startService(i);
- mLastClickTime = 0;
- } else {
- i.putExtra(MediaPlaybackService.CMDNAME, command);
- context.startService(i);
- mLastClickTime = eventtime;
- }
- mLaunched = false;
- mDown = true;
- }
- } else {
- mHandler.removeMessages(MSG_LONGPRESS_TIMEOUT);
- mDown = false;
- }
- if (isOrderedBroadcast()) {
- abortBroadcast();
- }
- }
- }
- }</span>
step1: 在方法if (action == KeyEvent.ACTION_DOWN) { ... ... }做的處理,event.getRepeatCount() == 0這個判斷的意思是“是否長按耳機鍵?”,如果長按耳機鍵event.getRepeatCount() 的值就一直增加。
step 2:短按耳機鍵:播放/暫停 --->音樂;短按啓動MediaPlaybackService.java這個類,並且傳入參數---->在這個服務類中有個接受廣播的內部類:如下-->
- <span style="FONT-SIZE: 16px">private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- String cmd = intent.getStringExtra("command");
- MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);
- if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
- next(true);
- } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
- prev();
- } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
- if (isPlaying()) {
- pause();
- mInternalPause = false;
- } else {
- play();
- }
- } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
- pause();
- mInternalPause = false;
- } else if (CMDPLAY.equals(cmd)) {
- play();
- } else if (CMDSTOP.equals(cmd)) {
- pause();
- mInternalPause = false;
- seek(0);
- } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) {
- // Someone asked us to refresh a set of specific widgets, probably
- // because they were just added.
- int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
- mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds);
- }
- }
- span>
通過:如下方法來控制點擊播放音樂,再次點擊暫停,如此循環。
else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
if (isPlaying()) {
pause();
mInternalPause = false;
} else {
play();
}
}
內部類的廣播是在啓動MediaPlaybackService.java中註冊的,解除註冊在onDestroy()的方法中。
- <span style="font-size:18px;"> </span><span style="FONT-SIZE: 16px">IntentFilter commandFilter = new IntentFilter();
- commandFilter.addAction(SERVICECMD);
- commandFilter.addAction(TOGGLEPAUSE_ACTION);
- commandFilter.addAction(PAUSE_ACTION);
- commandFilter.addAction(NEXT_ACTION);
- commandFilter.addAction(PREVIOUS_ACTION);
- commandFilter.addAction(PLAYSTATUS_REQUEST);
- registerReceiver(mIntentReceiver, commandFilter);</span>
Step 3: 長按耳機鍵--->發消息給mHandler,
- <strong><span style="font-size:18px;"> mHandler.removeMessages(MSG_LONGPRESS_TIMEOUT);</span></strong>
在MediaButtonIntentReceiver.java中有個內部類Handler()如下——>
- <span style="color:#000000;FONT-SIZE: 16px"> private static Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_LONGPRESS_TIMEOUT:
- if (!mLaunched) {
- Context context = (Context)msg.obj;
- Intent i = new Intent();
- i.putExtra("autoshuffle", "true");
- i.setClass(context, MusicBrowserActivity.class);
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- context.startActivity(i);
- mLaunched = true;
- }
- break;
- }
- }
- };</span>
長按耳機後就啓動MusicBrowserActivity.java這個音樂播放類。並且傳入參數“autoshuffle==true”,這個啓動和launcher的啓動相似,也是啓動一個新的任務task,但是這個後面的標誌有不同的地方Intent.FLAG_ACTIVITY_CLEAR_TOP。
到這爲止就是實現了在任何界面長按耳機鍵都能進入到music的主界面。
總結如下:
其實啓動的時候,要注意當前activity的launcherMode是什麼,如果是SingleTask,就要小心一下。比如說:想要長按耳機鍵,進入到launcher的Mainmenu界面,這時候如果單純的用以上方法套,返回鍵點擊的時候不會回到上個activity中,會有問題。因爲launcher是一直啓動的運行於每個task之中的,你再次啓動Launcher的時候,無論是否設置屬性“i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)”,都會把前一個activity給finish掉,launcher會在棧頂也是棧底。因爲launcher的launcherMode=singleTask。我們可以做個實驗;
三、例子寫兩個app,一個屬性爲singletask,一個爲standard。應singletask的啓動standard的activity,然後在再次基礎上啓動singletask的activity,看standard的activity是否會destory掉。
step1:先看截圖:
launchMode="singleTask" launchMode="standard"
Step 2:先啓動launchMode="singleTask"的activity---->點擊調用第二個App2的launchMode="standard"---->
點擊按鈕調用第一個App1的launchMode="singleTask"---->點擊返回鍵。看log分析:
(1)點擊啓動launchMode="singleTask"的activity的log如下:
(2)點擊調用第二個App2的launchMode="standard"的activity的log如下圖:
(3)點擊調用第一個App1launchMode="singleTask"的activity的log如下:
分析如下:看到這時候App2Activity--22已經執行了onStop()和onDestroy()方法了。驗證了我以上的說法。
(4)點擊返回鍵---->直接回到了launcher界面。log如下:
備註:要想解決以上問題也是可以的。就是在以上第(2)步:點擊調用第二個App2的launchMode="standard"的activity的時候設置flag。Intent.FLAG_ACTIVITY_NEW_TASK。就可以解決以上問題了,每次啓動一個新的任務,這樣就能返回到App2Activity了。
(1)點擊啓動launchMode="singleTask"的activity的log如下:
(2)點擊調用第二個App2的launchMode="standard"的activity的log如下圖:
(3)點擊調用第一個App1launchMode="singleTask"的activity的log如下:
看到如上圖:App2Activity--22--->只是onStop()了,沒有onDestroy掉。
(4)點擊返回鍵---->直接回到了launcher界面---->log如下:
(5)通過log,我們可以看出返回到App2Activity了,我們再次點擊返回鍵,--->返回到Launcher界面的log如下:
通過以上驗證說明我的結論是正確的。launcherMode一直是android的核心技術,通過這次我會更加注意到activity的LauncherMode的。
歡迎各界人士留言,討論,拍磚!轉載請標明出處!
轉載自:http://blog.csdn.net/wdaming1986/article/details/7539600