Fragment must be a public static class to be properly recreated from instance state

ぐ巨炮叔叔 提交于 2019-11-26 17:48:59

问题


After updating to the latest support repository,

compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:design:24.2.0'
compile 'com.android.support:percent:24.2.0'
compile 'com.android.support:recyclerview-v7:24.2.0'

I'm getting the weird exception.

java.lang.IllegalStateException: Fragment null must be a public static class to be  properly recreated from instance state.
at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:435)
at android.support.v4.app.BackStackRecord.add(BackStackRecord.java:414)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:154)
at com.androidapp.base.BaseActivity.showDialogFragment(BaseActivity.java:78)
at com.androidapp.MainActivity.showNewDialog(MainActivity.java:304)
at com.androidapp.MainActivity$6.onClick(MainActivity.java:228)

In my BaseActivity class, I've created a re-usable fragment which can be used in activity class that extends the BaseActivty

public void showDialogFragment(DialogFragment newFragment) {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
        if (prev != null) {
            ft.remove(prev);
        }
        ft.addToBackStack("dialog");
        newFragment.show(ft, "dialog");
    }

Back to the MainActivty I've used the fragment like this,

public class MainActivity extends BaseActivity {

    @SuppressLint("ValidFragment")
        public void showNewDialog(int type, String title, String message) {
            final DialogNew dialog = new DialogNew() {
                @Override
                public void success(boolean isLandscape) {
                    .......
                }

                @Override
                public void cancel() {

                }
            };
            dialog.setArgs(title, message);
            super.showDialogFragment(dialog);
        }
}

The DialogNew class is below,

public abstract class DialogNew extends DialogFragment {

    private View rootView;

    private String title;
    private String message;

    public void setArgs(String title, String message) {
        Bundle args = new Bundle();
        args.putString("title", title);
        args.putString("message", message);
        setArguments(args);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(STYLE_NO_TITLE, 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        rootView = inflater.inflate(R.layout.fragment_new_dialog, container, false);

        init();
        setListeners();

        return rootView;
    }

    public abstract void success(boolean isLandscape);

    public abstract void cancel();
}

PS: The same code works with older support repository.


回答1:


The error is not especially weird. If you were not getting this error before, that was weird.

Android destroys and recreates fragments as part of a configuration change (e.g., screen rotation) and as part of rebuilding a task if needed (e.g., user switches to another app, your app's process is terminated while it is in the background, then the user tries to return to your app, all within 30 minutes or so). Android has no means of recreating an anonymous subclass of DialogNew.

So, make a regular public Java class (or a public static nested class) that extends DialogNew and has your business logic, replacing the anonymous subclass of DialogNew that you are using presently.




回答2:


Edit: You probably don't want to do this... See the comments.

The code sample looks similar to what I had suggested over here, and I also recently discovered that the solution I had there was not working anymore. I've updated my answer there for Java7, but if you have Java8 the solution is super easy:

(I haven't tested this yet)

public class DialogNew extends DialogFragment {
    private View rootView;
    private String title;
    private String message;

    // Do nothing by default
    private Consumer mSuccess = (boolean b) -> {};
    private Runnable mCancel = () -> {};

    public void setArgs(String title, String message) {
        Bundle args = new Bundle();
        args.putString("title", title);
        args.putString("message", message);
        setArguments(args);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(STYLE_NO_TITLE, 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_new_dialog, container, false);
        // use mSuccess.accept(boolean) when needed
        init();
        setListeners();
        return rootView;
    }

    public void setSuccess(Consumer success) {
        mSuccess = success;
    }

    public void setCancel(Runnable cancel) {
        mCancel = cancel;
    }
}

Then in the Main activity:

public class MainActivity extends BaseActivity {
        public void showNewDialog(int type, String title, String message) {
            final DialogNew dialog = new DialogNew();
            dialog.setArgs(title, message);
            dialog.setSuccess((boolean isLandscape) -> {
                //....
            });
            super.showDialogFragment(dialog);
        }
}


来源:https://stackoverflow.com/questions/39295458/fragment-must-be-a-public-static-class-to-be-properly-recreated-from-instance-st

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!