회전을 통해 DialogFragment를 올바르게 유지하는 방법은 무엇입니까?
DialogFragment를 호스팅하는 FragmentActivity가 있습니다.
DialogFragment는 네트워크 요청을 수행하고 Facebook 인증을 처리하므로 회전하는 동안 유지해야합니다.
이 문제와 관련된 다른 모든 질문을 읽었지만 실제로 문제를 해결하지 못했습니다.
저는 putFragment 및 getFragment를 사용하여 Fragment 인스턴스를 저장하고 활동 재생성 중에 다시 가져옵니다.
그러나 onRestoreInstanceState에서 getFragment를 호출 할 때 항상 null 포인터 예외가 발생합니다. 또한 회전하는 동안 대화 상자가 닫히지 않도록하고 싶지만 지금까지는 그 인스턴스를 유지할 수 없습니다.
무슨 일이 일어나고 있는지 아이디어가 있습니까?
현재 내 코드는 다음과 같습니다.
public class OKLoginActivity extends FragmentActivity implements OKLoginDialogListener
{
private OKLoginFragment loginDialog;
private static final String TAG_LOGINFRAGMENT = "OKLoginFragment";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
if(savedInstanceState == null)
{
loginDialog = new OKLoginFragment();
loginDialog.show(fm, TAG_LOGINFRAGMENT);
}
}
@Override
public void onSaveInstanceState(Bundle outState)
{
getSupportFragmentManager().putFragment(outState,TAG_LOGINFRAGMENT, loginDialog);
}
@Override
public void onRestoreInstanceState(Bundle inState)
{
FragmentManager fm = getSupportFragmentManager();
loginDialog = (OKLoginFragment) fm.getFragment(inState, TAG_LOGINFRAGMENT);
}
}
다음은 예외 스택 추적입니다.
02-01 16:31:13.684: E/AndroidRuntime(9739): FATAL EXCEPTION: main
02-01 16:31:13.684: E/AndroidRuntime(9739): java.lang.RuntimeException: Unable to start activity ComponentInfo{io.openkit.example.sampleokapp/io.openkit.OKLoginActivity}: java.lang.NullPointerException
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3692)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.access$700(ActivityThread.java:141)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1240)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.os.Handler.dispatchMessage(Handler.java:99)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.os.Looper.loop(Looper.java:137)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.main(ActivityThread.java:5039)
02-01 16:31:13.684: E/AndroidRuntime(9739): at java.lang.reflect.Method.invokeNative(Native Method)
02-01 16:31:13.684: E/AndroidRuntime(9739): at java.lang.reflect.Method.invoke(Method.java:511)
02-01 16:31:13.684: E/AndroidRuntime(9739): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
02-01 16:31:13.684: E/AndroidRuntime(9739): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
02-01 16:31:13.684: E/AndroidRuntime(9739): at dalvik.system.NativeStart.main(Native Method)
02-01 16:31:13.684: E/AndroidRuntime(9739): Caused by: java.lang.NullPointerException
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:528)
02-01 16:31:13.684: E/AndroidRuntime(9739): at io.openkit.OKLoginActivity.onRestoreInstanceState(OKLoginActivity.java:62)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.Activity.performRestoreInstanceState(Activity.java:910)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1131)
02-01 16:31:13.684: E/AndroidRuntime(9739): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2158)
Inside your DialogFragment
, call Fragment.setRetainInstance(boolean)
with the value true
. You don't need to save the fragment manually, the framework already takes care of all of this. Calling this will prevent your fragment from being destroyed on rotation and your network requests will be unaffected.
You may have to add this code to stop your dialog from being dismissed on rotation, due to a bug with the compatibility library:
@Override
public void onDestroyView() {
Dialog dialog = getDialog();
// handles https://code.google.com/p/android/issues/detail?id=17423
if (dialog != null && getRetainInstance()) {
dialog.setDismissMessage(null);
}
super.onDestroyView();
}
One of the advantages of using dialogFragment
compared to just using alertDialogBuilder
is exactly because dialogfragment can automatically recreate itself upon rotation without user intervention.
However, when the dialogfragment does not recreate itself, it is possible that you overwrite onSaveInstanceState
but didn't to call super
:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); // <-- must call this if you want to retain dialogFragment upon rotation
...
}
This is a convenience method using the fix from antonyt's answer:
public class RetainableDialogFragment extends DialogFragment {
public RetainableDialogFragment() {
setRetainInstance(true);
}
@Override
public void onDestroyView() {
Dialog dialog = getDialog();
// handles https://code.google.com/p/android/issues/detail?id=17423
if (dialog != null && getRetainInstance()) {
dialog.setDismissMessage(null);
}
super.onDestroyView();
}
}
Just let your DialogFragment
extend this class and everything will be fine. This becomes especially handy, if you have multiple DialogFragments
in your project which all need this fix.
'IT TIP' 카테고리의 다른 글
C #에서 Exception 개체를 직렬화하는 방법은 무엇입니까? (0) | 2020.10.28 |
---|---|
PHP는 특정 문자열 앞의 모든 문자를 제거합니다. (0) | 2020.10.28 |
Android-Kotlin에서 setOnClickListener를 달성하는 방법은 무엇입니까? (0) | 2020.10.28 |
.NET에서 문자열을 바이트 배열로 어떻게 변환합니까? (0) | 2020.10.28 |
Subversion에서 파일 삭제를 취소하는 간단한 방법은 무엇입니까? (0) | 2020.10.28 |