片段必须是要从实例状态正确重新创建的公共静态类

时间:2016-09-02 14:59:22

标签: android android-fragments android-support-library android-dialogfragment fragmentmanager

更新到最新的支持存储库后,

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'

我得到了奇怪的例外。

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)

在我的 BaseActivity 类中,我创建了一个可重复使用的片段,可以在扩展 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");
    }

返回 MainActivty 我已经使用了这样的片段,

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);
        }
}

DialogNew 类位于下方,

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:相同的代码适用于较旧的支持存储库。

5 个答案:

答案 0 :(得分:13)

错误并不特别奇怪。如果您之前没有收到此错误,很奇怪。

Android会破坏并重新创建碎片,作为配置更改的一部分(例如,屏幕旋转),并在需要时重建任务的一部分(例如,用户切换到另一个应用程序,您的应用程序的进程会终止在后台,然后用户尝试返回您的应用程序,所有都在30分钟左右)。 Android无法重新创建DialogNew的匿名子类。

因此,创建一个扩展public且具有业务逻辑的常规public Java类(或static DialogNew嵌套类),替换{的匿名子类{1}}你目前正在使用。

答案 1 :(得分:3)

我从头开始重新创建了片段,为我解决了这个问题。

新建->片段->片段(空白),您取消选中第二个框,然后确认。

答案 2 :(得分:1)

此错误的原因在 Android Developers 指南中有很好的解释。

当系统发出配置更改时,它需要能够创建片段的新实例。为此,它依赖于片段的默认构造函数,该构造函数不接受任何参数,因此不能具有任何依赖项。如果您的 Fragment 类不是静态公共类,则系统无法反射性地找到此默认构造函数,错误表明了这一点。

要解决此问题,您必须覆盖 FragmentManager 实例的 FragmentFactory 的默认实现,该实例将处理您的片段的创建。我提供的链接中的代码对此进行了解释。

答案 3 :(得分:0)

编辑: 您可能不想这样做...请参阅评论。

代码示例看起来类似于我在here上建议的内容,我最近也发现我在那里的解决方案不再适用了。我已经为Java7更新了我的答案,但如果你有Java8,解决方案非常简单:

(我还没有测试过)

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;
    }
}

然后在主要活动中:

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);
        }
}

答案 4 :(得分:0)

从新的> Fragment>空白片段创建片段

对我有用♥♥♥