這兩天不知道爲啥忽然想到了這個問題,正常思惟,可能理所應當的以爲,ActivityA startActivityForResult啓動了ActivityB, 那麼activityB finish的時候,就會把結果傳回ActivityA。
因此開篇的問題,我想都沒想就以爲,ActivityA的onActivityResult會響應,過了兩天,又想到了這個問題,好吧,仍是 用代碼來實踐一下,結果ActivityA並無響應~~
好吧那咱們就看一下源碼,爲何沒有響應~
ActivityTaskManager.getService().finishActivity(mToken, resultCode, resultData, finishTask)
activity調用finish後,會交給ActivityTaskManager的finishActivity方法,而且參數中帶有resultCode, resultData 而後瀏覽了ActivityTaskManager裏面帶result的相關方法、參數,跟着finishActivity方法,一個一個找過去,不少方法中又代碼不少, 可能看着看着就斷了,而後回頭找參數,哪裏作了保存,再全局收索看哪裏作了調用,而後看着收索框裏一堆的結果,腦子裏就閃過了 我是誰、我在哪、我要幹嗎來的。若是看岔了,也是越看越迷,越看越偏,最後腦子裏又蕩起了,我是誰、我在哪、我要幹嗎來的, 不知道大家有沒有這種感覺,反正我常常有。android
下載系統 源碼 mac視角 ,首先準備好至少100g空間
git
確保主目錄下有一個 bin/ 目錄,而且該目錄包含在路徑中:
mkdir ~/bin
PATH=~/bin:$PATH
ps: 源碼不支持在大小寫敏感的文件系統中比編譯,參考第8步,這個也能夠放在第一步,隨後全部命令在/Volumes/android下執行,可是速度很慢api
下載 Repo 工具,並確保它可執行:
curl storage.googleapis.com/git-repo-do… > ~/bin/repo
chmod a+x ~/bin/repobash
建立一個空目錄來存放您的工做文件。若是您使用的是 MacOS,必須在區分大小寫的文件系統中建立該目錄。爲其指定一個您喜歡的任意名稱:
mkdir WORKING_DIRECTORY
cd WORKING_DIRECTORYapp
使用您的真實姓名和電子郵件地址配置 Git。要使用 Gerrit 代碼審覈工具,您須要一個與已註冊的 Google 賬號關聯的電子郵件地址。 確保這是您能夠接收郵件的有效地址。您在此處提供的姓名將顯示在您提交的代碼的提供方信息中。
git config --global user.name "Your Name"
git config --global user.email "you@example.com"curl
運行 repo init 以獲取最新版本的 Repo 及其最近的全部錯誤更正內容。您必須爲清單指定一個網址,該網址用於指定 Android 源代碼中包含的各個代碼庫將位於工做目錄中的什麼位置。
repo init -u android.googlesource.com/platform/ma…ide
要對「master」之外的分支進行校驗,請使用 -b 來指定相應分支。要查看分支列表,請參閱源代碼標記和版本。
repo init -u android.googlesource.com/platform/ma… -b android-10.0.0_r1函數
要將 Android 源代碼樹從默認清單中指定的代碼庫下載到工做目錄,請運行如下命令:
repo sync工具
ps: repo sync 耗了我,七、8個小時~~ 同步完了內存吃緊,能夠把.repo文件夾刪除ui
source.android.com/setup/build… 在默認安裝過程當中,macOS 會在一個保留大小寫但不區分大小寫的文件系統中運行。 Git 不支持這種類型的文件系統,並且此類文件系統會致使某些 Git 命令(如 git status)的行爲出現異常。所以,咱們建議您始終在區分大小寫的文件系統中處理 AOSP 源文件。使用下文中介紹的磁盤映像能夠很是輕鬆地作到這一點。有了適當的文件系統,在新型 macOS 環境中編譯 master 分支就會變得很是簡單。要編譯較早版本的分支,則須要一些額外的工具和 SDK。
hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 80g ~/android.dmg
hdiutil attach ~/android.dmg -mountpoint /Volumes/android;
移動源碼到上一步建立的磁盤映像
mv ~/bin/WORKING_DIRECTORY /Volumes/android
編譯idegen模塊: cd 到/Volumes/android/WORKING_DIRECTORY
source build/ensetup.sh
make idegen
執行./development/tools/idegen/idegen.sh 在源碼根目錄會生成android.iml 和 android.ipr 兩個文件
用AndroidStudio找到打開android.ipr 下載好對應版本的Android源碼,打開對應版本的虛擬機,就能夠選擇system_process執行debug了
先簡單的瞭解一下ActivityRecord,其對應一個Activity,保存了一個Activity的全部信息,其中的變量resultTo,指向啓動它的ActivityRecord
Activity執行startActivityForResult,調用到mInstrumentation.execStartActivity傳入token參數, 這個token也就是Activity對應服務端的ActivityRecord.Token,能夠拿到ActivityRecord
mInstrumentation.execStartActivity內執行ActivityTaskManager.getService().startActivity(... ActivityRecord resultTo ,int requestCode ...), 參數中resultTo也就是從上一步中的token獲取來的,而後一路走
TaskRecord、ActivityStack建立關聯等邏輯後,ActivityStackSupervisor執行realStartActivityLocked與activityThread交互,執行應用進程後續流程
private void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
ActivityRecord resultTo = r.resultTo;
...
resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode, resultData);
...
}
複製代碼
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
// 棧頂的 ActivityRecord
ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
final boolean hasRunningActivity = next != null;
// mResumedActivity 當前處在Resume的ActivityRecord,
// 棧頂的ActivityRecord是否已是RESUMED狀態
// 若是系統當前正在中斷一個Activity,須要先等待那個Activity pause完畢,以後系統會從新調用resumeTopActivityInnerLocked函數,找到下一個要啓動的Activity
if (mResumedActivity == next && next.isState(RESUMED)
&& display.allResumedActivitiesComplete()) {
executeAppTransition(options);
return false;
}
// transaction 能夠與對應進程的activityThread通信
final ClientTransaction transaction = ClientTransaction.obtain(next.app.getThread(), next.appToken);
ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
// ActivityResultItem被傳到activityThread後,經過其execute方法,
// 最終調用到deliverResults
transaction.addCallback(ActivityResultItem.obtain(a));
}
}
}
/**
* r 經過ActivityClientRecord r = mActivities.get(token)獲得,經過它能夠獲得對應的activity對象
*/
private void deliverResults(ActivityClientRecord r, List<ResultInfo> results, String reason) {
final int N = results.size();
for (int i=0; i<N; i++) {
ResultInfo ri = results.get(i);
// 如下,也就執行到了activity內部,dispatchActivityResult會調到onActivityResult
r.activity.dispatchActivityResult(ri.mResultWho,
ri.mRequestCode, ri.mResultCode, ri.mData, reason);
}
}
複製代碼
簡單總結,由startActivityForResult啓動的activity,finish時,resultData會傳入resultTo也就是啓動它的 activity對應activityRecord,而後在這個在activity將要從新顯示在屏幕上時,若是存在results,將其分發到activityThread 最終吊起onActivityResult
若是哪裏有不對的地方