標籤:

從最近任務列表和Launcher重新進入App時,有什麼區別,開發的時候應該注意什麼?

問題描述:入口Activity AsingleTask, 另一個Activity B,App 啟動後由A進入B,按home鍵退出,分別從最近任務和Launcher重新進入App

任務列表上是可以正常恢復到B

Launcher上恢復的時候進入到了A,並且 B destory了

說明從任務列表和Launcher恢復任務棧的操作是不太一樣的,為什麼會這樣我只找到了文檔,但沒理解,Tasks and Back Stack

This second ability is important: Users must be able to leave a task and then come back to it later using this activity launcher. For this reason, the two launch modes that mark activities as always initiating a task,"singleTask" and "singleInstance", should be used only when the activity has an ACTION_MAIN and aCATEGORY_LAUNCHER filter. Imagine, for example, what could happen if the filter is missing: An intent launches a "singleTask" activity, initiating a new task, and the user spends some time working in that task. The user then presses the Home button. The task is now sent to the background and is not visible. Now the user has no way to return to the task, because it is not represented in the application launcher.

For this reason 後面是什麼意思?

省略… If the user later resumes the task by selecting the launcher icon that began the task, the task comes to the foreground and resumes the activity at the top of the stack.

正常情況下最近任務列表和Launcher都是恢復任務棧的狀態,操作應當是一致的,但由於本例默認的入口activity是sinageTask的,從Launcher重新進入後似乎執行了類似startActivity(this,A.class)的操作,由於是啟動模式是singleTask,才導致清空了B,為不是單純的恢復任務棧?那麼最近任務列表是如何恢復任務棧的呢?

希望能結合文檔解答一下,順便一問,這種從最近任務列表和Launcher恢復APP不一致的情況,有沒有什麼應用場景?


先Mark一下,試了題主的方法,沒有重現這個問題。一會扒源碼看去

@王琦 給的鏈接講的很詳細了。然而我還是沒有重現題主的問題。

扒源碼,覺得也不應該啊。不論怎麼打開app,只要startActivity,最終都會調用的ActivityStack的startActivityUncheckedLocked方法。

切出app後,再從home點擊進入app,應該會執行下面的代碼

if ((startFlagsActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {

// We don"t need to start a new activity, and

// the client said not to do anything if that

// is the case, so this is it! And for paranoia, make

// sure we have correctly resumed the top activity.

if (doResume) {

resumeTopActivityLocked(null, options);

} else {

ActivityOptions.abort(options);

}

return ActivityManager.START_RETURN_INTENT_TO_CALLER;

}

看到這個方法調用resumeTopActivityLocked,按照題主的場景,必然是B被resume過來啊。


同 @hi大頭鬼hi,我也並沒能重現這個問題。

我的理解是,在題主目前所給出的條件下,Back Press後應該會保留一個以B為root的stack供resume。就算在MainActivity是SingleTask的情況下,如果沒有進行過其他task的操作的話,應該還是會回到B為root的stack吧,是不是這個stack被kill了?

以上只是猜測,我也要再看看


1.點擊Launcher裡面的圖標,本質上就是調用的startActivity,action是android.intent.action.MAIN,category是android.intent.category.LAUNCHER,flag是FLAG_ACTIVITY_RESET_TASK_IF_NEEDED FLAG_ACTIVITY_NEW_TASK,component是你的A。

你需要看ActivityManager的源碼去了解FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 配合singleTask做了什麼。

(隨手找了個講相關源碼的帖子:android Application Component研究之Activity(一),裡面講了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED )

2.從RecentActivity進入,源碼裡面對flag做了這種處理:

intent.setFlags((intent.getFlags()~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) | Intent.FLAG_ACTIVITY_NEW_TASK);

去掉了flag裡面FLAG_ACTIVITY_RESET_TASK_IF_NEEDED那一位標誌。

3.文檔裡面描述的大部分都是「the default behavior for activities and tasks」,你截取的「For this reason」,前面一句話才是這一段的重點,後面舉的例子只是為前面一句展開的。


從桌面啟動,intent是針對的launcherActivity,你的launcherActivity是SingleTask,那麼它收到onNewIntent(),而且它上面的Activity就會被自動出棧——這個是SingleTask的特點。launcherActivity一般不要寫成SingleTask和SingleInstance。

若你的launcherActivity打開其它Activity之後自己finish了,那麼從桌面啟動時就不存在上面的情況了,只是把進程目前的任務棧棧頂Activity切換到前台。

最近列表打開應用:如果已啟動就把棧頂Activity切到前台,如果沒就啟動launcherActivity。

參考:

http://stackoverflow.com/questions/29321261/what-are-the-differences-between-flag-activity-reset-task-if-needed-and-flag-act


Activity A 加上android:clearTaskOnLaunch="true"屬性能復現該情況


推薦閱讀:

如何系統的學習安卓逆向分析?
為什麼在手機攝影方面常常提及的是 iPhone 而非安卓機?
2016年發布的安卓手機,你最喜歡哪一款?
既然微軟能讓小米4用上wp10為什麼不讓所有的安卓手機都能用上wp10?
所謂的iOS「偽多任務」和Android的多任務處理的區別在哪?

TAG:Android | Activity |