startActivityForResult가FragmentActivity와Fragment에서의 공통점과 차이점을 철저히 이해하다
25840 단어 android
startActivityForResult가FragmentActivity와Fragment에서의 공통점과 차이점을 철저히 이해하다
1. 앞말
Activity,FragmentActivity,Fragment에는 모두
startActivityForResult()
방법이 있고, 결과를 받아들이는 onActivityResult()
방법도 있다. 그러면 그들은 어떤 차이가 있습니까?용법이 뭐가 달라요?이 문제를 주목한 것은 최근 Fragment에서 getActivity () 를 사용했기 때문이다.startActivityForResult () 에서 그림 선택기를 호출한 결과 Fragment의 onActivityResult에서 되돌아오는 결과를 받을 수 없습니다.
원인을 자세히 연구해 보니 예전에 눈치채지 못했던 문제점을 발견하고 써서 여러분께 나눠드렸습니다.
2. 표현
FragmentActivity에 Fragment가 끼워져 있다고 가정하면 각각 startActivityForResult를 사용하여 데이터 요청을 합니다.대상이 반환한 결과 데이터가 각각의 onActivity Result 메소드에 의해 수신될 수 있는지 여부는 다음과 같습니다.

Fragment와 FragmentActivity 모두 자신이 발기한 요청이 되돌아오는 결과를 받을 수 있다FragmentActivity에서 요청한 경우 Fragment에서 결과를 전혀 받지 못함Fragment에서 발동한 요청은 FragmentActivity에서 결과를 얻을 수 있지만 RequestCode가 완전히 대응하지 않습니다왜 이런 표현이 나왔을까요?내려다보다
3. 이유 찾기: Show me your code!
문서를 자세히 보면 이전에 눈치채지 못했던 점이 하나 있습니다. FragmentActivity는 부모Activity에 비해 startActivityForResult에 대한 설명이 약간 바뀌었습니다.
FragmentActivity.startActivityForResult 문서는 다음과 같습니다.
결과를 Fragment에 전달할 수 있도록 표준 동작을 수정했습니다.제한 사항이 추가되었습니다. requestCode는 <=0xffff여야 합니다.
여기
는 자연히 정상적인 Activity를 가리킨다.startActivityForResult 기능새로 추가된 Request Code에 대한 크기 제한은 이상해 보이는데, 아마도 어떤 고양이가 그 안에 묻은 것 같다.OK, 뜸 안 들이고 바로 원본을 봐!
3.1
Fragment.startActivityForResult
Fragment의 startActivityForResult에서 시작:
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode, options);
}
Fragment.startActivityForResult 자체의 코드는 매우 간단하다. 바로 mHost를 호출한 것이다.onStartActivityFromFragment 방법- Fragment가 FragmentActivity에 추가된 후에 이곳의 mHost는 현재 FragmentActivity의 내부 클래스인 FragmentActivity입니다.FragmentActivity에 대한 인용을 가진 HostCallbacksonStartActivityFromFragment는 현재 FragmentActivity의 startActivityFromFragment() 방법으로 간단하게 전달됩니다.
Fragment.startActivityForResult ↓ FragmentActivitymHost.HostCallbacks.onStartActivityFromFragment ↓ FragmentActivity.startActivityFromFragment
다음은 Fragment Activity입니다.startActivityFromFragment:
3.2
FragmentActivity.startActivityFromFragment
public void startActivityFromFragment(Fragment fragment, Intent intent,
int requestCode, @Nullable Bundle options) {
mStartedActivityFromFragment = true;
try {
if (requestCode == -1) {
ActivityCompat.startActivityForResult(this, intent, -1, options);
return;
}
if ((requestCode&0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
int requestIndex = allocateRequestIndex(fragment);
ActivityCompat.startActivityForResult(
this, intent, ((requestIndex+1)<<16) + (requestCode&0xffff), options);
} finally {
mStartedActivityFromFragment = false;
}
}
이 코드를 분석해 봅시다. 1,
mStartedActivityFromFragment = true
우선 요청이 Fragment에서 온 것임을 표시하세요.2, if(requestCode == 1)
의 내용은 상관하지 마십시오. 이것은 startActivity(ForResult가 없는 경우)에서 나온 것입니다.3, 그리고 코드는 Request Code가 0xfff보다 작아야 한다는 제한을 추가했습니다. if((requestCode&0xffff0000) != 0){/* */}
우리는 Fragment에서 왔습니다.startActivityForResult가 이곳을 추적했기 때문에 문서에 명확한 설명이 없지만 여기서 알 수 있듯이 Fragment.startActivityForResult의 RequestCode도 <=0xffff가 필요합니다.그리고 다음은 관건이다.
ActivityCompat.startActivityForResult(
this, intent, ((requestIndex+1)<<16) + (requestCode&0xffff), options);
-ActivityCompat은 도움말 클래스입니다.ActivityCompat.startActivityForResult는 최종적으로 호출된Activity입니다.startActivityForResult, 이것은 표시하지 않습니다.여기서 관건은
requestCode
=>((requestIndex+1)<<16)+(requestCode&0xffff)
의 매핑을 통해Fragment.startActivityForResult에서 최종적으로Activity를 호출했습니다.startActivityForResult. Activity가 호출되었습니다.startActivityForResult는 사실 예상했던 일입니다.
requestCode
부터 ((requestIndex+1)<<16)+(requestCode&0xffff)
까지 무엇을 했을까요?분석을 통해 RequestIndex는 요청의 번호로 0에서 증가하는 정수 값임을 알 수 있습니다.또 앞에서 알 수 있듯이 Request Code 자체의 값은 0xfff보다 작기 때문에 ((request Index+1)<<16)+(request Code & 0xfff)를 간소화하면
(requestIndex+1)*65536+requestCode
이다.그래서 이 값은 반드시 0xfff보다 크다.Fragment Activity를 다시 한 번 봅시다.startActivityForResult 코드:
3.3
FragmentActivity.startActivityForResult
@Override
public void startActivityForResult(Intent intent, int requestCode) {
// If this was started from a Fragment we've already checked the upper 16 bits were not in
// use, and then repurposed them for the Fragment's index.
if (!mStartedActivityFromFragment) {
if (requestCode != -1 && (requestCode&0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
}
super.startActivityForResult(intent, requestCode);
}
보시다시피 요청이 Fragment, 즉 FragmentActivity 자체에서 온 것이 아니라면 RequestCode가 0xfff보다 크면 안 된다고 판단했습니다.
게다가 앞에서 말한 Fragment.startActivityForResult에서 최종적으로 비치는 RequestCode 값은 0xfff보다 크기 때문에 현재 초보적인 결과를 얻을 수 있다. SDK는 Fragment와FragmentActivity의 ruquestCode를 0xffff 이내로 제한한 다음에 Fragment에서 요청한 것은 모두 하나의 비추기를 통해 최종 RequestCode를 0xfff보다 큰 값으로 만들었다.
- 지금까지 추측할 수 있듯이 결과를 얻을 때도 0xfff라는 수치와 비교하여 결과를 FragmentActivity에 맡길지 Fragment에 맡길지 구분할 수 있다.
한 번 확인해 보십시오.
3.4
FragmentActivity.onActivityResult
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mFragments.noteStateNotSaved();
int requestIndex = requestCode>>16;
if (requestIndex != 0) {
requestIndex--;
String who = mPendingFragmentActivityResults.get(requestIndex);
mPendingFragmentActivityResults.remove(requestIndex);
if (who == null) {
Log.w(TAG, "Activity result delivered for unknown Fragment.");
return;
}
Fragment targetFragment = mFragments.findFragmentByWho(who);
if (targetFragment == null) {
Log.w(TAG, "Activity result no fragment exists for who: " + who);
} else {
targetFragment.onActivityResult(requestCode&0xffff, resultCode, data);
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
OK, 일목요연하게 우리 위의 추론을 증명했다.Fragment Activity에서Activity Result에서 Request Code > 0xfff만 얻을 수 있는 Request Index는
requestIndex != 0
를 충족시키고 다음 논리로 들어갑니다. Request Code를 이전의 반사 관계를 통해 최초의 Fragment에서 지정한 Request Code로 복원하여 Fragment에 전달합니다.onActivityResult에서 처리합니다.4. 최초의 문제를 설명한다
그래서 앞에서 말한 이 몇 가지 표현이 왜 있는지 이제는 알 수 있다.
Fragment와 FragmentActivity 모두 자신이 발기한 요청이 되돌아오는 결과를 받을 수 있습니다
당연하지, 바로 이렇게 설계한 거야.
Fragment Activity에서 요청한 내용이 전혀 전달되지 않습니다.
Fragment Activity에 의해 차단되어 Fragment로 전달되지 않았습니다.
Fragment 요청은 Fragment Activity에서 결과를 얻을 수 있지만 Request Code가 전혀 대응하지 않습니다
Fragment에서 요청한 경우 FragmentActivity에서Activity Result에서 얻은 Request Code는 0xfff보다 큰 값입니다. 처음 Fragment에서 요청을 했을 때의 Request Code가 아닙니다.
5. 생각
RequestCode를 매핑하는 방법으로 요청이 Fragment에서 왔는지 아닌지를 구분하는 이유는 무엇입니까?이렇게 한 바퀴 돌고 변수를 직접 사용해서 표시하면 안 됩니까?
직접 변수를 사용하여 표시하면 정말 안 된다. * 왜냐하면 우리가 최종적으로 업무 코드를 쓰는 MyFragmentActivity는 FragmentActivity에서 계승된 것이고 MyFragmentActivity이기 때문이다.onActivityResult 호출은 FragmentActivity보다 먼저 실행됩니다.onActivityResult. * 그래서 Fragment이든MyFragmentActivity가 발기한 startActivityForResult 요청이든 최종적으로 결과를 얻을 때 반드시 MyFragmentActivity를 통과해야 한다.onActivityResult의.*만약 여기서 변수로 요청의 출처를 표시한다면 실질적으로는 개발자 스스로 판단하는 것이다. 이것은 번거롭고 통제할 수 없는 것이다. *비교해 보면 간단한 매핑 규칙을 사용하면 Fragment로부터의 요청과 FragmentActivity로부터의 요청을 구분할 수 있다. 매우 간단하고 믿을 만하다.
6. 요약
startActivityForResult를 사용할 때 RequestCode는 0xfff(65535)보다 크지 않아야 합니다.
Fragment의 onActivity Result에서 데이터를 수신하려면 Fragment을 호출해야 합니다.Fragment 대신 startActivityForResult.getActivity().startActivityForResult.
역시 원본을 보면 공부하기 좋은 방법~ Google의 엔지니어는 과연 대단합니다.
작성자 정보:http://www.barryzhang.com https://github.com/barryhappy
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.