關(guān)于startActivityForResult

startActivityForResult使用場景是什么?requestCode、resultCode含義是什么?

使用場景

用戶開始新的活動(dòng),并且希望得到新活動(dòng)的某些信息。比如選擇照片、選擇聯(lián)系人、選擇收貨地址、進(jìn)行某塊數(shù)據(jù)編輯工作等。

requestCode

解決的是「區(qū)分多個(gè)異步任務(wù)」的問題。與其他異步 API 的設(shè)計(jì)類似,如果沒有這個(gè)信息,那么 Activity 在收到響應(yīng)時(shí)會(huì)進(jìn)入混亂的狀態(tài)。比如他不知道自己得到的是選擇照片還是選擇聯(lián)系人的結(jié)果。
該信息會(huì)發(fā)送到 AMS 那邊的ActivityRecord.requestCode變量進(jìn)行記錄,Client 端新 Activity 并不知道這個(gè)信息。

  • 為什么requestCode < 0時(shí)收不到結(jié)果?
    ActivityStarter 收到startActivityLocked時(shí),寫入ActivityRecord.resultTo變量為空。
if (requestCode >= 0 && !sourceRecord.finishing) {
    // 只有非負(fù)數(shù)時(shí)新的 ActivityRecord 對象的 resultTo 變量才指向發(fā)起者 ActivityRecord 對象
    resultRecord = sourceRecord;
}

????在 ActivityStack 收到finishActivityResultsLocked時(shí),讀取ActivityRecord.resultTo變量為空,結(jié)果數(shù)據(jù)不會(huì)添加到源ActivityRecord.results變量。
????在 ActivityStack 收到resumeTopActivityInnerLocked時(shí),讀取ActivityRecord.results數(shù)組為空,不會(huì)分發(fā)結(jié)果數(shù)據(jù),這樣源Activity也就沒有結(jié)果回調(diào)了。

resultCode

異步調(diào)用結(jié)果碼,告訴調(diào)用者成功/失敗/其它信息。
該信息由被調(diào)用 Activity/Framework 寫入,并經(jīng)過 AMS 傳遞給源 Activity。

Activity A啟動(dòng)B的時(shí)候,在B中何時(shí)執(zhí)行setResult?setResult是否可以位于Activity的finish方法之后嗎?

setResultfinish之前執(zhí)行,只是把數(shù)據(jù)記錄在Activity.mResultCodeActivity.mResultData變量中。

  • 最早 Activity 構(gòu)造器階段
  • 最晚 Activity.finalize 內(nèi)存回收階段
// Home 鍵 + 不保留后臺 Activity 可觸發(fā) onDestroy
protected void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy() called");
    new ReqGC().start();
}

@Override
protected void finalize() throws Throwable {
    Log.d(TAG, "finalize() called");
    finish();
    super.finalize();
}

@Override
public void finish() {
    Log.d(TAG, "finish() called");
    setResult(RESULT_OK, new Intent().putExtra("key", "resultData"));
    super.finish();
}

// 不泄漏 Activity 對象
static class ReqGC {
    public void start() {
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
            System.gc();
            handler.postDelayed(this, 10);
            }
        }, 10);
    }
}

如果位于finish之后執(zhí)行,那信息無法傳遞給源 Activity。
從代碼可以看出setResultfinish類似生產(chǎn)者/消費(fèi)者模型,setResult負(fù)責(zé)寫入數(shù)據(jù),finish負(fù)責(zé)讀取數(shù)據(jù)。

線程安全問題

Activity.mResultCodeActivity.mResultData變量由Activity對象的鎖進(jìn)行保護(hù),支持后臺線程和 UI 線程分別進(jìn)行setResultfinish。

API設(shè)計(jì)/數(shù)據(jù)組裝問題

底層 AMS 提供的接口的參數(shù)是setResultfinish的參數(shù)的組合形式,但是 Activity 為什么把一個(gè)接口拆分成兩個(gè)接口給開發(fā)者使用?
使用方便。很多情況下調(diào)用者只關(guān)心finish,不需要理解太多的信息。

API內(nèi)部原理/數(shù)據(jù)處理流程

關(guān)鍵節(jié)點(diǎn):

  • Client 端通過 AMP 把數(shù)據(jù)發(fā)送給 Server 端 AMS Binder 實(shí)體
  • AMS 把數(shù)據(jù)包裝成 ActivityResult 并保存在源 ActivityRecord 的 results 變量中
  • AMS 通過 ApplicationThreadProxy 向 Client 端發(fā)送 pause 信息讓棧頂 Activity 進(jìn)入 paused 狀態(tài),并等待 Client 端回復(fù)或超時(shí)
  • AMS 接收 Client 端已 paused 信息,恢復(fù)下一個(gè)獲取焦點(diǎn)的 Activity ,讀取之前保存在ActivityRecord.results變量的數(shù)據(jù)派發(fā)給 Client 端對應(yīng)的 Activity
  • Client 端數(shù)據(jù)經(jīng)過 ApplicationThread 對象、ActivityThread 對象的分發(fā)最后到達(dá) Activity
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容