在我的项目上下文中,我在活动a
的片段f(1)
中有一个按钮b
。
片段f(x)
是F
的一个实例,其中内容取决于参数x
我需要将当前实例f(1)
替换为b
单击事件时f(2)
实例:
-
从活动
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;
}
}
}
问题在于您设置侦听器的方式。您正在设置听众,然后将设备从横向旋转到纵向。轮换后发生的情况是:
- 安卓创建了一个全新的
MainActivity
实例。 -
FragmentManager
内部创建一个新的MyFragment
实例,并将其自动重新添加到活动中,就像方向更改之前一样。 - 如果单击该按钮,将调用侦听器。但是,侦听器是已被销毁的上一个活动(在轮换之前)的侦听器。
因此,您不仅有内存泄漏(旧活动不能被垃圾回收,因为它是从这里引用的),而且您还会收到此错误。
如何正确操作:好吧,问题不仅在于您没有正确理解Android片段生命周期setRetainInstanceState()
。如上所述,片段由FragmentManager(FragmentTransaction)控制。所以,是的,每次你旋转屏幕时都会创建一个新的片段实例,但FragmentManager会自动为你附加它们(这有点奇怪,但这就是片段的工作方式)
我建议使用EventBus
。片段将触发事件onClick()
活动将收到此事件,因为它已订阅。我重新评论绿色道事件巴士。否则,您可以查看官方文档,但从我的角度来看,它们教授的不是一个好的解决方案,因为您的片段和活动几乎没有连接(不是模块化的)。他们说你应该使用onAttach()
就像你在文档中的示例中看到的那样:http://developer.android.com/guide/components/fragments.html#EventCallbacks
顺便说一句,如果您不使用片段参数来"传递"数据,则可能会出现类似的问题。有关更多详细信息,请阅读此博客:http://hannesdorfmann.com/android/fragmentargs/