IT TIP

회전을 통해 DialogFragment를 올바르게 유지하는 방법은 무엇입니까?

itqueen 2020. 10. 28. 21:24
반응형

회전을 통해 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.

참고URL : https://stackoverflow.com/questions/14657490/how-to-properly-retain-a-dialogfragment-through-rotation

반응형