在我的项目环境中,我在活动b
中的片段f(1)
中有一个按钮a
。
片段f(x)
是F
的一个实例,其内容取决于参数x
我需要在f(1)
点击事件上用实例f(2)
替换当前实例b
:
来自活动a
:
private void setFragment(int x) {
Bundle args = new Bundle();
args.putInt("x", x);
F f = new F();
f.setArguments(args);
f.setListener(new F.Listener() {
public void onButtonClick(int x) {
setFragment(x);
}
});
getSupportFragmentManager()
.beginTransaction()
.replace(ID, f)
.commit();
}
来自片段f
:
b.setOnClickListener(new View.onClickListener() {
public void onClick(View view) {
listener.onButtonClick(x + 1);
}
});
我的问题是:
只有在配置状态发生变化时,b
点击事件才会出现异常:
java.lang.IllegalStateException:onSaveInstanceState之后无法执行此操作
请问,我的错误是什么?我阅读了很多关于此例外的帖子,但我找不到任何解决方案
编辑:我只是在没有AsyncTask的情况下进行测试,请参阅代码:
尝试旋转屏幕并按下按钮
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.activity_main);
if (state == null) {
setFragment(1);
}
}
private void setFragment(int id) {
Bundle args = new Bundle();
args.putInt("id", id);
MyFragment myFragment = new MyFragment();
myFragment.setArguments(args);
myFragment.setListener(new MyFragment.Listener() {
@Override
public void onClick(int id) {
setFragment(id);
}
});
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment, myFragment)
.commit();
}
public static class MyFragment extends Fragment{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup view, Bundle state) {
return new Button(getActivity()) {
{
setText(String.valueOf(getArguments().getInt("id")));
setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.onClick(getArguments().getInt("id") + 1);
}
});
}
};
}
private static interface Listener {
public void onClick(int id);
}
private Listener listener;
public void setListener(Listener listener) {
this.listener = listener;
}
}
}
答案 0 :(得分:2)
问题在于您设置侦听器的方式。 您正在设置监听器,然后将设备从横向旋转到纵向。轮换后会发生什么:
MainActivity
。FragmentManager
在内部创建MyFragment
的新实例,并在方向更改之前将其自动重新添加到活动中。因此,不仅存在内存泄漏(旧活动不能被垃圾收集,因为它是从这里引用的),但您也会收到此错误。
如何正确地做到:
好吧,问题不仅是setRetainInstanceState()
您还没有正确理解Android Fragments生命周期。如上所述,Fragments由FragmentManager(FragmentTransaction)控制。所以,是的,每次旋转屏幕时都会创建一个新的Fragment实例,但FragmentManager会自动为它们附加它们(它有点奇怪,但这就是Fragment的工作原理)
我建议使用EventBus
。片段将触发事件onClick()
,活动将在订阅后接收此事件。我推荐GreenDao EventBus。
否则你可以查看official docs,但从我的观点来看,他们教的不是一个好的解决方案,因为你的片段和活动很难连接(不是模块化的)。他们说您应该使用onAttach()
,就像您在文档中的示例中看到的那样:http://developer.android.com/guide/components/fragments.html#EventCallbacks
顺便说一下。如果你没有使用Fragment参数来传递"传递"会出现类似的问题。数据。有关详细信息,请阅读此博客:http://hannesdorfmann.com/android/fragmentargs/