提问人:Falling Into Infinity 提问时间:9/2/2016 最后编辑:Falling Into Infinity 更新时间:7/9/2022 访问量:31832
Fragment 必须是公共静态类,才能从实例状态正确重新创建
Fragment must be a public static class to be properly recreated from instance state
问:
更新到最新的支持存储库后,
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:相同的代码适用于较旧的支持存储库。
答:
这个错误并不是特别奇怪。如果您以前没有收到此错误,那就太奇怪了。
Android 会在配置更改(例如屏幕旋转)过程中销毁并重新创建片段,并在需要时作为重新构建任务的一部分(例如,用户切换到另一个应用,应用的进程在后台终止,然后用户尝试返回您的应用,所有这些都在 30 分钟左右)。Android 无法重新创建 的匿名子类。DialogNew
因此,创建一个常规的 Java 类(或嵌套类)来扩展并具有您的业务逻辑,替换您当前使用的匿名子类。public
public
static
DialogNew
DialogNew
评论
DialogFragment
public
public
编辑:你可能不想这样做......请参阅评论。
代码示例看起来与我在这里建议的相似,而且我最近还发现我在那里的解决方案不再有效。我已经更新了 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);
}
}
评论
mSuccess
mCancel
我从头开始重新创建了我的片段,它为我解决了问题。
新建 -> Fragment -> Fragment (Blank),然后在确认之前取消选中第二个框。
从新的 >Fragment> 空白片段创建片段
它对我♥♥♥有用
此错误的原因在 Android 开发人员指南中得到了很好的解释。
当系统发出配置更改时,它需要能够创建 Fragment 的新实例。为此,它依赖于片段的默认构造函数,该构造函数不带任何参数,因此不能有任何依赖关系。如果 Fragment 类不是静态公共类,则系统无法以反射方式找到此默认构造函数,并且错误仅指示这一点。
要解决此问题,您必须覆盖 FragmentManager 实例的 FragmentFactory 的默认实现,该实现将处理 fragment 的创建。这由我提供的链接中的代码解释。
发生此错误的原因是在创建 fragment 实例时使用了虚拟方法。
必须从声明中删除虚拟方法,并且应使用处理程序类来侦听 DialogNew 类事件。
public class MainActivity extends BaseActivity {
@SuppressLint("ValidFragment")
public void showNewDialog(int type, String title, String message) {
final DialogNew dialog = new DialogNew(
// use DialogHandler for manage success or cancel click
new DialogHandler() {
@Override
public void success(boolean isLandscape) {
}
@Override
public void cancel() {
}
}
);
dialog.setArgs(title, message);
super.showDialogFragment(dialog);
}
}
评论
DialogNew