Android筆記之Fragment的startActivityForResult(與requestPermissions)

1、fragment使用...的注意事項

首先是你們熟悉的,在fragment中使用startActivityForResult和requestPermissions的時候,要注意:bash

  • 使用fragment本身的方法,即Fragment.startActivityForResult和...,而不是fragment.getActivity(=FragmentActivity)的方法
  • 在Activity中的對應方法(onActivityResult和onRequestPermissionsResult)中不要去掉super.

原本我只是知其然但不知其因此然,可是一次debug讓我瞭解了其中緣由。函數

2、 debug什麼

這樣的,我在fragment中發出startActivityForResult請求,在fragment所在的Activity中的onActivityResult打了個斷點看一下,這一看就發現了有個問題:fragment中啓動的requestCode是0,然而到了activity中的onResult的requestCode變成了65536。this

若是是別的數字的話可能會忽略掉,反正最後是能正常調用fragment的回調的,可是65536?2^16??0xffff+1?這個數字但是很特殊。在看了源碼以後終於有了具體的解釋,因此來看看發出請求到onResult的過程吧。spa

聲明: 如下源碼爲API 27.1.1debug

3、(support)Fragment的請求

能夠看到Fragment的startActivityForResult調用一個mHost的方法,這個mHost最後就是調用了FragmentActivity的startActivityFromFragment,那FragmentActivity作了什麼呢?
code

requestCode = -1 這是沒有result的startActivity用的,暫且不表,下邊是重要的部分了,check的函數我也放到一塊兒了:

static void checkForValidRequestCode(int requestCode) {
    if ((requestCode & 0xffff0000) != 0) {
        throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
    }
}
...
    checkForValidRequestCode(requestCode);
    int requestIndex = allocateRequestIndex(fragment);
    ActivityCompat.startActivityForResult(
        this, intent, 
        ((requestIndex + 1) << 16) + (requestCode & 0xffff), options);
複製代碼

首先是檢查requestCode,高16位不能有1,即requestcode不能大於0xffff,requestIndex能夠理解成fragment的一個標識編號,fragmentActivity來管理的。
重點在這裏: 在實際用ActivityCompact啓動請求的時候,傳入的requestCode並非咱們設置的requestCode了,作了一個轉換,((requestIndex + 1) << 16) + (requestCode & 0xffff)
這個轉換的意思就是requestIndex+1放在高16位,requestCode的低16位放在新的低16位,這樣組成了新的requestCode,寫成數學表達式就是:
requestCode = (requestIndex+1)*0xffff+requeseCode 這樣新的requestCode就是大於0xffff的了。cdn

Fragment的startActivityForResult總結

  • 傳入的requestCode要不大於0xffff
  • 實際請求的requestCode作了轉換,變成大於0xffff的數了,可是低8位仍然是原來的requestCode,高8位是requestIndex+1

4、 FragmentActivity的請求

首先仍是看源碼:blog

嗯..那個check的函數就是上邊那個,因此結果很清楚了。

FragmentActivity的startActivityForResult總結

  • 沒幹啥,就要求requestCode不大於0xffff,實際請求的requestCode沒變

FragmentActivity的onActivityResult

首先咱們要明白,Fragment的請求也是先有FragmentActivity來處理的。而後通過上邊的分析,咱們大概能夠猜想,經過轉換requestCode,Fragment和FragmentActivity的請求就被分開了,那onResult的時候也是分開處理的。來看code:開發

分開來看:get

int requestIndex = requestCode>>16;
if (requestIndex != 0) {
    requestIndex--;
    ...
}
複製代碼

首先是除以(右移)16,這樣剩下的就是高16位,若是不爲0的話,就說明requestCode是大於0xffff的,就是咱們Fragment發出的請求,不爲0的高16位就是requestIndex。下邊就是根據requestIndex找到對應的Fragment了

targetFragment.onActivityResult(
requestCode & 0xffff, resultCode, data);
複製代碼

這是真正調用找到的Fragment的onResult的地方,因爲請求的時候requestCode通過了轉換,因此這裏要轉換回來,取出低16位就是原來的requestCode。

5、one more thing

以上是分析了startActivityForResult的流程,requestPermissions是相似的能夠本身去看一遍。源碼真的是好東西,Google的工程師也真的厲害,這個邏輯不難可是讓我這種新手是很差想出來的。

//做爲Android開發的初學者,若是我有錯誤的地方或者不足的話歡迎你們指正。但願與你們一同進步。

相關文章
相關標籤/搜索