onActivityResult에서 DialogFragment 표시
내 조각에 대한 onActivityResult에 다음 코드가 있습니다.
onActivityResult(int requestCode, int resultCode, Intent data){
//other code
ProgressFragment progFragment = new ProgressFragment();
progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG);
// other code
}
그러나 다음과 같은 오류가 발생합니다.
Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
무슨 일이 일어나고 있는지 아는 사람이 있거나 어떻게 해결할 수 있습니까? Android 지원 패키지를 사용하고 있습니다.
Android 지원 라이브러리를 사용하는 경우 onResume 메서드가 조각을 재생할 올바른 위치가 아닙니다. onResumeFragments 메소드에서 수행해야합니다. onResume 메소드 설명을 참조하십시오. http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html#onResume%28%29
따라서 내 관점에서 올바른 코드는 다음과 같아야합니다.
private boolean mShowDialog = false;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
// remember that dialog should be shown
mShowDialog = true;
}
@Override
protected void onResumeFragments() {
super.onResumeFragments();
// play with fragments here
if (mShowDialog) {
mShowDialog = false;
// Show only if is necessary, otherwise FragmentManager will take care
if (getSupportFragmentManager().findFragmentByTag(PROG_DIALOG_TAG) == null) {
new ProgressFragment().show(getSupportFragmentManager(), PROG_DIALOG_TAG);
}
}
}
편집 : 버그는 아니지만 조각 프레임 워크의 결함이 더 많습니다. 이 질문에 대한 더 나은 대답은 위의 @Arcao가 제공 한 것입니다.
---- 원본 게시물 ----
실제로 지원 패키지 의 알려진 버그 입니다 (편집 : 실제로 버그가 아닙니다. @ alex-lockwood의 의견 참조). 버그 보고서의 주석에 게시 된 해결 방법은 다음과 같이 DialogFragment의 소스를 수정하는 것입니다.
public int show(FragmentTransaction transaction, String tag) {
return show(transaction, tag, false);
}
public int show(FragmentTransaction transaction, String tag, boolean allowStateLoss) {
transaction.add(this, tag);
mRemoved = false;
mBackStackId = allowStateLoss ? transaction.commitAllowingStateLoss() : transaction.commit();
return mBackStackId;
}
이것은 거대한 해킹입니다. 제가 실제로 한 방법은 원래 조각에서 등록 할 수있는 대화 조각을 만드는 것뿐이었습니다. 다른 대화 조각이 작업을 수행 할 때 (예 : 해제 됨) 모든 청취자에게 사라질 것이라고 말했습니다. 나는 이렇게했다 :
public static class PlayerPasswordFragment extends DialogFragment{
Player toJoin;
EditText passwordEdit;
Button okButton;
PlayerListFragment playerListFragment = null;
public void onCreate(Bundle icicle){
super.onCreate(icicle);
toJoin = Player.unbundle(getArguments());
Log.d(TAG, "Player id in PasswordFragment: " + toJoin.getId());
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle){
View v = inflater.inflate(R.layout.player_password, container, false);
passwordEdit = (EditText)v.findViewById(R.id.player_password_edit);
okButton = (Button)v.findViewById(R.id.ok_button);
okButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
passwordEntered();
}
});
getDialog().setTitle(R.string.password_required);
return v;
}
public void passwordEntered(){
//TODO handle if they didn't type anything in
playerListFragment.joinPlayer(toJoin, passwordEdit.getText().toString());
dismiss();
}
public void registerPasswordEnteredListener(PlayerListFragment playerListFragment){
this.playerListFragment = playerListFragment;
}
public void unregisterPasswordEnteredListener(){
this.playerListFragment = null;
}
}
이제 일이 발생하면 PlayerListFragment에 알리는 방법이 있습니다. unregisterPasswordEnteredListener를 적절하게 호출하는 것이 매우 중요합니다 (위의 경우 PlayerListFragment가 "종료"되는 경우). 그렇지 않으면이 대화 상자 조각은 해당 리스너가 더 이상 존재하지 않을 때 등록 된 리스너에서 함수를 호출하려고 할 수 있습니다.
@Natix 가 남긴 댓글 은 일부 사람들이 삭제했을 수있는 빠른 한 줄입니다.
이 문제에 대한 가장 간단한 해결책은 코드를 실행하기 전에 super.onActivityResult () 를 호출 하는 것입니다. 이것은 지원 라이브러리를 사용하는지 여부에 관계없이 작동하며 활동에서 행동 일관성을 유지합니다.
다음이 있습니다.
- 스레드, 핸들러 또는 휴면을 사용하여 가짜 지연 을 추가 할 필요가 없습니다 .
- 상태 손실 또는 하위 클래스가 show ()를 재정의 하도록 커밋 할 필요가 없습니다 . 버그가 아니라 경고입니다. 상태 데이터를 버리지 마십시오. ( 또 하나 , 보너스 예 )
- 활동에서 대화 조각을 추적 할 필요가 없습니다 (안녕하세요 메모리 누수!).
- 그리고 하나님에 의해 onStart ()를 수동으로 호출하여 활동 수명주기를 망칠 필요가 없습니다 .
내가 이것에 대해 더 많이 읽을수록 내가 본 더 미친 해킹.
여전히 문제가 발생하는 경우 Alex Lockwood 가 확인해야합니다.
- 그럴 필요합니다 onSaveInstanceState ()에 대한 코드를 쓸 ( 또 다른 하나를 )
Android 버그라고 생각합니다. 기본적으로 Android는 활동 / 조각 수명주기의 잘못된 지점 (onStart () 이전)에서 onActivityResult를 호출합니다.
버그는 https://issuetracker.google.com/issues/36929762 에서보고됩니다.
기본적으로 Intent를 나중에 onResume ()에서 처리 한 매개 변수로 저장하여 해결했습니다.
[편집] 요즘에는 2012 년에 사용할 수 없었던이 문제에 대한 더 나은 솔루션이 있습니다. 다른 답변을 참조하십시오.
편집 : 또 다른 옵션, 그리고 아마도 최고 (또는 적어도 지원 라이브러리가 기대하는 것 ...)
Android 지원 라이브러리와 함께 DialogFragments를 사용하는 경우 FragmentActivity의 하위 클래스를 사용해야합니다. 다음을 시도하십시오.
onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, intent);
//other code
ProgressFragment progFragment = new ProgressFragment();
progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG);
// other code
}
FragmentActivity 의 소스 를 살펴본 결과 상태를 잃지 않고 조각을 재개하기 위해 내부 조각 관리자를 호출하는 것처럼 보입니다.
여기에 나열되지 않은 솔루션을 찾았습니다. Handler를 만들고 Handler에서 대화 조각을 시작합니다. 따라서 코드를 약간 편집하십시오.
onActivityResult(int requestCode, int resultCode, Intent data) {
//other code
final FragmentManager manager = getActivity().getSupportFragmentManager();
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
ProgressFragment progFragment = new ProgressFragment();
progFragment.show(manager, PROG_DIALOG_TAG);
}
});
// other code
}
이것은 나에게 더 깨끗하고 덜 해커 보인다.
두 가지 DialogFragment 쇼 () 방법은 - show(FragmentManager manager, String tag)와 show(FragmentTransaction transaction, String tag).
메서드의 FragmentManager 버전을 사용하려는 경우 (원래 질문에서와 같이) 쉬운 해결책은이 메서드를 재정의하고 commitAllowingStateLoss를 사용하는 것입니다.
public class MyDialogFragment extends DialogFragment {
@Override
public void show(FragmentManager manager, String tag) {
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
}
show(FragmentTransaction, String)이 방법을 재정의 하는 것은 원래 DialogFragment 코드 내의 일부 내부 변수도 수정해야하기 때문에 쉽지 않으므로 권장하지 않습니다. 해당 메서드를 사용하려면 허용 된 답변 (또는 Jeffrey Blattman).
commitAllowingStateLoss를 사용하면 약간의 위험이 있습니다. 문서에는 "Commit ()과 유사하지만 활동 상태가 저장된 후 커밋이 실행되도록 허용합니다. 활동이 나중에 해당 상태에서 복원되어야하는 경우 커밋이 손실 될 수 있으므로 위험합니다. 이므로 UI 상태가 사용자에게 예기치 않게 변경 되어도 괜찮은 경우에만 사용해야합니다. "
onSaveInstanceState () 메서드를 호출 한 연결된 활동 후에는 대화 상자를 표시 할 수 없습니다. 분명히 onSaveInstanceState ()는 onActivityResult () 전에 호출됩니다. 따라서이 콜백 메서드 OnResumeFragment ()에서 대화 상자를 표시해야합니다. DialogFragment의 show () 메서드를 재정의 할 필요가 없습니다. 이것이 당신을 도울 것입니다.
나는 hmt의 솔루션에서 부분적으로 기반을 둔 세 번째 솔루션을 생각해 냈습니다. 기본적으로 onResume ()에 표시 될 DialogFragments의 ArrayList를 생성합니다.
ArrayList<DialogFragment> dialogList=new ArrayList<DialogFragment>();
//Some function, like onActivityResults
{
DialogFragment dialog=new DialogFragment();
dialogList.add(dialog);
}
protected void onResume()
{
super.onResume();
while (!dialogList.isEmpty())
dialogList.remove(0).show(getSupportFragmentManager(),"someDialog");
}
onActivityResult ()는 onResume () 전에 실행됩니다. onResume () 이상에서 UI를 수행해야합니다.
부울 또는이 두 메서드간에 결과가 반환되었음을 알리는 데 필요한 모든 것을 사용하십시오.
... 그게 다야. 단순한.
I know this was answered quite a while ago.. but there is a much easier way to do this than some of the other answers I saw on here... In my specific case I needed to show a DialogFragment from a fragments onActivityResult() method.
This is my code for handling that, and it works beautifully:
DialogFragment myFrag; //Don't forget to instantiate this
FragmentTransaction trans = getActivity().getSupportFragmentManager().beginTransaction();
trans.add(myFrag, "MyDialogFragmentTag");
trans.commitAllowingStateLoss();
As was mentioned in some of the other posts, committing with state loss can cause problems if you aren't careful... in my case I was simply displaying an error message to the user with a button to close the dialog, so if the state of that is lost it isn't a big deal.
Hope this helps...
It's an old question but I've solved by the simplest way, I think:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
MsgUtils.toast(getString(R.string.msg_img_saved),
getActivity().getApplicationContext());
}
});
It happens because when #onActivityResult() is called, the parent activity has already call #onSaveInstanceState()
I would use a Runnable to "save" the action (show dialog) on #onActivityResult() to use it later when activity has been ready.
With this approach we make sure the action we want to will always work
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == YOUR_REQUEST_CODE) {
mRunnable = new Runnable() {
@Override
public void run() {
showDialog();
}
};
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onStart() {
super.onStart();
if (mRunnable != null) {
mRunnable.run();
mRunnable = null;
}
}
The cleanest solution I found is this:
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
new Handler().post(new Runnable() {
@Override
public void run() {
onActivityResultDelayed(requestCode, resultCode, data);
}
});
}
public void onActivityResultDelayed(int requestCode, int resultCode, Intent data) {
// Move your onActivityResult() code here.
}
I got this error while doing .show(getSupportFragmentManager(), "MyDialog"); in activity.
Try .show(getSupportFragmentManager().beginTransaction(), "MyDialog"); first.
If still not working, this post (Show DialogFragment from onActivityResult) helps me to solve the issue.
Another way:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Activity.RESULT_OK:
new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message m) {
showErrorDialog(msg);
return false;
}
}).sendEmptyMessage(0);
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
private void showErrorDialog(String msg) {
// build and show dialog here
}
just call super.onActivityResult(requestCode, resultCode, data); before handling the fragment
As you all know this problem is because of on onActivityResult() is calling before onstart(),so just call onstart() at start in onActivityResult() like i have done in this code
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
onStart();
//write you code here
}
참고URL : https://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
'Program Club' 카테고리의 다른 글
| django 관리자는 obj를 수정할 때 필드를 읽기 전용으로 만들지 만 새 obj를 추가 할 때 필요합니다. (0) | 2020.10.11 |
|---|---|
| Git의 대소 문자 구분 (0) | 2020.10.11 |
| Android Gradle에서 versionCode를 자동 증가시키는 방법 (0) | 2020.10.11 |
| 인터페이스 속성의 XML 직렬화 (0) | 2020.10.11 |
| JavaScript-HTML 양식 값 가져 오기 (0) | 2020.10.11 |