Android 응용 프로그램 에서 Fragment 구성 요 소 를 사용 하 는 문제 및 해결 방안 요약
Fragment 는 Activity 의 보기 단계 에 View 를 추가 하지 않 아 도 됩 니 다.특정한 모듈 이 Activity 의 생명주기 리 셋 을 받 아야 할 때 Fragment 를 통 해 이 루어 지 는 것 을 고려 할 수 있 습 니 다.
예 를 들 어 DialogFragment 는 show 방법 으로 Dialog(이 키 Window 는 Activity 의 보기 등급 에 있 지 않 습 니 다)를 표시 합 니 다.화면 을 돌 릴 때 DialogFragment 는 onDestroy View 를 이용 하여 dismiss Dialog 를 리 셋 한 다음 Activity 를 재 구축 한 후에 DialogFragment 는 onStart 리 셋 을 이용 하여 Dialog 를 표시 합 니 다.
물론,우 리 는 UI 가 전혀 없 는 Fragment 를 만 들 수 있 습 니 다.예 를 들 어 BackgroundWorker Fragment 는 onResume 에서 Task 를 실행 하고 onPause 에서 Task 를 일시 정지 할 수 있 습 니 다.
프 래 그 먼 트 수명 주기
먼저 기초 지식 을 돌 이 켜 보면 Fragment 의 생명 주기 도 는 다음 과 같다.
설명:전체적으로 말 하면 Fragment 와 Activity 의 생명주기 가 유사 하 다.주의해 야 할 것 은 Activity 에 비해 onAttach(),onDetch(),onCreateView()와 onDestroy View()라 는 몇 가지 반전 함수 가 많 습 니 다.하지만 온 레 스타 트()가 빠 졌 다.
Fragment 의 생명 주 기 는 매우 복잡 하 며 다음 과 같은 몇 가지 상황 으로 나 뉜 다.
Fragment 를 사용 하 는 과정 에서 Activity 의 onSave InstanceState 방법 이 호출 된 후에 commt 나 popBackStack 을 조작 하여 발생 하 는 crash 를 자주 만 날 수 있 습 니 다.
onSave InstanceState 방법 이후 의 작업 상 태 를 잃 어 버 릴 수 있 기 때문에 Android framework 는 기본적으로 이상 을 던 집 니 다.
commt 방법 에 있어 서 이 이상 을 피 하 는 것 은 간단 합 니 다.commt Allowing StateLoss 방법 을 사용 하면 됩 니 다.그러나 popBackStack 과 popBackStack Immediate 도 state(checkStateLoss)를 검사 합 니 다.특히 주의해 야 할 것 은 Activity 의 onBackPressed 방법 입 니 다.
public void onBackPressed() {
if (!mFragments.popBackStackImmediate()) {//
supportFinishAfterTransition();
}
}
onBackPressed 가 onSaved InstanceState 이후 에 호출 되면 crash 입 니 다.onBackPressed 호출 시기:
*targetSdkVersion<=5,onKeyDown 에서 호출
*targetSdkVersion>5,onKeyUp 에서 호출
onSaved InstanceState 호출 시기(호출 되면):
*반드시 온 스 톱 전에
*onPause 이전 일 수도 있 고,onPause 와 onStop 사이 일 수도 있 습 니 다.
주의해 야 할 것 은:onSaved InstanceState 방법 이 반드시 호출 되 는 것 은 아 닙 니 다.Activity 가 특정한 이유 로 Framework 에 의 해 소각 되 고 그 후에 다시 만들어 야 하 는 경우 에 만 호출 이 필요 합 니 다.(예 를 들 어 회전 화면 이나 메모리 가 부족 해서 스 택 에 있 는 일부 Activity 를 회수 합 니 다)
예:
*Activity A 가 프론트 에 있 을 때 화면 이 잠 길 때 까지 어 두 워 집 니 다.그러면 A 의 onSaved InstanceState 가 호출 됩 니 다.
*Activity A start Activity B,Activity A 의 onSaved InstanceState 가 호출 됨
*Activity A 는 리 턴 키 나 finish 호출 로 이전 화면 으로 되 돌아 갑 니 다.그러면 A 의 onSaved InstanceState 는 호출 되 지 않 습 니 다.
따라서 onBackPressed 가 onSaved InstanceState 방법 이후 에 호출 되면 반드시 crash 가 발생 합 니 다.해결 방법 은 주로 두 가지 가 있 습 니 다.
Activity 의 onSaved InstanceState()방법 을 다시 쓰 고 슈퍼 호출 을 설명 합 니 다.
이러한 방법 은 crash 를 피 할 수 있 지만 전체 Activity 의 상 태 를 잃 어 버 릴 수 있 습 니 다.DialogFragment 의 경우 정상 적 인 상황 에서 표 시 된 DialogFragment 는 회전 화면 Activity 를 다시 만 든 후에 우리 가 처리 할 필요 가 없습니다.Dialog 는 자동 으로 표 시 됩 니 다(DialogFragment.onStart(참조).그러나 Activity 의 onSaved InstanceState()방법 을 설명 한 후에 Fragment 상 태 를 잃 어 버 립 니 다.Activity 가 다시 만 들 면 Dialog 도 다시 표시 되 지 않 습 니 다.
더 좋 고 일반적인 방법:commt,popBackStack,onBackPressed 방법 을 호출 하기 전에 onSaved InstanceState()방법 이 실행 되 었 는 지 판단 하고 onResume 방법 이 실행 되 지 않 았 습 니 다.그렇지 않 으 면 직접 조작 합 니 다.그렇지 않 으 면 pending 대기 열 에 가입 하여 onResume Fragments 나 onPost Resume 을 기다 린 후에 실행 합 니 다.
메모:onResume 에서 동작 하지 마 십시오.이 때 Fragment Manager 의 mStateSaved 는 여전히 true 일 수 있 기 때 문 입 니 다.(실행 순서 가 onSaved InstanceState()->onPause()->onResume()또는 onPause()->onSaved InstanceState()->onResume())))
예 를 들 면:
public void onDataReceived() {
if(isStateSaved()) {//isStateSaved() BaseActivity
addPendingFragmentOperation(new Runnable() {
@Override
public void run() {
getSupportFragmentManager().popBackStackImmediate();
}
});
} else {
getSupportFragmentManager().popBackStackImmediate();
}
}
@Override
protected void onPostResume() {
super.onPostResume();
if(pendingFragmentOperation != null && !pendingFragmentOperation.isEmpty()) {
for(Runnable operation : pendingFragmentOperation) {
operation.run();
}
pendingFragmentOperation.clear();
}
}
startActivityForResultrequestCode 의 사용 가능 한 구간:
1.Activity: [Integer.MIN_VALUE, Integer.MAX_VALUE]
(1)requestCode 의 값 이[Integer.MIN 에 있 을 때VALUE,-1]구간 에서 효 과 는 startActivity()와 마찬가지 로 onActivity Result()리 셋 을 받 지 않 습 니 다.
(2)내 장 된 Fragment 는 requestCode 를 사용 할 수 있 는 구간 과 Activity 가 같 습 니 다.
2.support 라 이브 러 리:Fragment,그리고 Fragment Activity:[-1,65535]
(1)requestCode==-1,효 과 는 startActivity()와 마찬가지 로 onActivity Result()리 셋 을 받 지 못 합 니 다.
(2)requestCode 재[Integer.MINVALUE,-2]또는[65536,Integer.MAXVALUE]사이 에 이상 이 발생 합 니 다(requestCode 는 16 비트 이하 만 사용 가능)
권장:requestCode 의 수 치 는[-1,65535]사이 로 통일 적 으로 제한 합 니 다.
모자이크 프 래 그 먼 트
우선 내장 Fragment 를 사용 하지 말 라 는 것 이다.
포 함 된 Fragment 에서 startActivity ForResult()를 사용 할 때 발생 하 는 문제:
모든 Fragment 에서 onActivity Result()를 받 을 수 없습니다.
어떤 level 1 의 Fragment 가 onActivity Result()를 받 았 습 니 다.
아무튼 startActivity ForResult()를 시작 하 는 내장 Fragment 는 onActivity Result()의 리 셋 을 받 지 않 을 것 입 니 다.
이 유 는 다음 과 같다.(위 에서 말 한 requestCode 참조)
Fragment Activity.startActivity FromFragment()는 requestCode 를 변경 하여 Fragment Manager 에 있 는 index 를 높 은 16 비트 로 저장 하고,낮은 16 비트 는 Fragment 에서 사용 할 수 있 는 requstCode 로 저장 합 니 다.Fragment Activity.onActivity Result()에 서 는 높 은 16 비트 에 따라 Fragment Manager 에서 해당 하 는 Fragment 를 찾 은 다음 낮은 16 비트 의 값 을 requstCode 로 합 니 다.Fragment.onActivity Result()를 호출 합 니 다.
그러면 requestCode 에 하나의 index,즉 root Fragment Manager 의 Fragment index 만 저장 할 수 있 습 니 다.따라서 위 에 열거 한 상황 이 나타 납 니 다.
해결 방안:
Tips
개발 시 Fragment 관련 디 버 깅 정 보 를 열 수 있 습 니 다.
FragmentManager.enableDebugLogging(BuildConfig.DEBUG);
Activity onResume ,Fragment onResume .
protected void onPostResume() {
super.onPostResume();
mHandler.removeMessages(MSG_RESUME_PENDING);
onResumeFragments();
mFragments.execPendingActions();
}
protected void onResumeFragments() {
mFragments.dispatchResume();
}
Fragment 의 onResume 이 모두 실 행 된 후에 어떤 작업 을 수행 해 야 한다 면 onPostResume()방법 을 다시 쓸 수 있 습 니 다.슈퍼.onPostResume()을 호출 해 야 합 니 다.1.IllegalStateException(Fragment not attached to Activity)의 질문
이 이상 한 상황 은 Fragment 에서 비동기 작업 을 시작 한 다음 리 소스 와 관련 된 작업(getString(...)이나 startActivity(...)와 같은 작업 을 수행 하 는 것 입 니 다.그러나 이 때 Fragment 는 detach 에 의 해 실행 되 었 을 수 있 습 니 다.따라서 이 작업 을 수행 하기 전에 isAdded()를 판단 해 야 합 니 다.
메모:여 기 는 isDetached()를 사용 하여 판단 하지 마 십시오.Fragment 가 detach 에 당 한 후에 도 isDetached()방법 은 false 로 돌아 갈 수 있 기 때 문 입 니 다.
2.Fragment A 가 replace 되 어 detach 가 되 었 다 면,isDetached()는 false 로 되 돌아 갑 니 다.
3.Fragment A 에 대응 하 는 Fragment Transaction 이 스 택 에서 나 와 detach 가 되면 isDetached()는 true 로 돌아 갑 니 다.
final public Resources getResources() {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
return mHost.getContext().getResources();
}
public void startActivity(Intent intent, @Nullable Bundle options) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mHost.onStartActivityFromFragment(this /*fragment*/, intent, -1, options);
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.