我的片段被创建了两次,即使该活动仅将片段添加到内容中一次。旋转屏幕时会发生这种情况。此外,每次调用片段onCreateView时,它都会丢失所有可变状态。
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) { // Checking for recreation
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new AppPanelFragment())
.commit();
}
}
}
onCreate in活动检查null savedInstanceState,并且只有null将添加片段,这样我才能看出为什么片段应该被创建两次?在if条件中设置断点告诉我它只被调用一次,因此活动不应该多次添加片段。但是,每次方向更改时,片段的onCreateView仍会被调用。
public class AppPanelFragment extends Fragment {
private TextView appNameText;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// This method called several times
View rootView = inflater.inflate(R.layout.fragment_app_panel, container, false);
// 2nd call on this method, appNameText is null, why?
appNameText = (TextView) rootView.findViewById(R.id.app_name);
appNameText.text = "My new App";
return view;
}
我设法使用setRetainInstance(true)保持变量状态,但这是真正的解决方案吗?我希望片段不会仅仅在方向改变时创建。
答案 0 :(得分:4)
在Android中,当手机的方向改变时,活动将被销毁并重新创建。现在,我相信要修复你的问题,你可以使用片段管理器来检查片段是否已经存在于后台堆栈中,如果它不存在则创建它。
public void onCreated(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
mFragmentManager = getSupportFragmentManager();
AppPanelFragment fragment = (AppPanelFragment)mFragmentManager.findFragmentById(R.id.fagment_id);
if(fragment == null) {
//do your fragment creation
}
}
}
P.S。我没有测试过这个,但是一旦你在findFragmentById方法中提供正确的片段id,它就应该可以工作。
答案 1 :(得分:3)
Fragment
生命周期与Activity
非常相似。默认情况下,是的,它们将在配置更改期间重新创建,就像Activity
一样。这是预期的行为。即使使用setRetainInstance(true)
(我会说,如果它包含用户界面,我会非常谨慎地使用),您的View
将被销毁并重新创建,但在这种情况下,您的Fragment
实例将不会被摧毁 - 只是View
。
答案 2 :(得分:0)
如上所述,在方向更改时,活动将被销毁并重新创建。此外,系统会重新创建片段(任何)。
为了确保您的应用程序恢复到以前的状态,在销毁活动之前调用onSaveInstanceState()。
因此,您可以在活动的onSaveInstanceState()方法中存储一些信息,然后在方向更改时将应用程序恢复到相同的状态。
注意:您不需要在方向更改时创建片段,因为会重新创建片段。
来自http://www.mynewsfeed.x10.mx/articles/index.php?id=15的示例:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ( savedInstanceState == null ){
//Initialize fragments
Fragment example_fragment = new ExampleFragment();
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.container, example_fragment, "Example");
} else{
//control comes to this block only on orientation change.
int postion = savedInstanceState.getInt("position"); //You can retrieve any piece of data you've saved through onSaveInstanceState()
//finding fragments on orientation change
Fragment example_fragment = manager.findFragmentByTag("Example");
//update the fragment so that the application retains its state
example_fragment.setPosition(position); //This method is just an example
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("position", position); //add any information you'd like to save and restore on orientation change.
}
}
答案 3 :(得分:0)
我知道回答有点迟,但使用The Code Pimp回答你可以做下一件事:
如果片段存在于backstack中,我们会弹出并删除它以将其添加回来(如果在不删除它的情况下将其添加回来,则会抛出异常,说它已经存在)。
fragment变量是一个类成员变量。
此方法将在Activity的onCreate方法中调用:
private TextView dummyTV;
private static int counter = 0;
@Override
protected int getFragmentLayoutId() {
return R.layout.fragment_alerts_view;
}
@Override
protected void saveReferences(View view) {
dummyTV = (TextView) view.findViewById(R.id.fragment_alerts_view_dummy_tv);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
if (savedInstanceState != null) {
dummyTV.setText(savedInstanceState.getString("dummy_string"));
} else {
dummyTV.setText("flip me!");
}
dummyTV.append(" | " + String.valueOf(counter));
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("dummy_string", counter++ % 2 == 0 ? "landscape" : "portrait");
}
下一个代码将在片段本身中调用。
这是您可以在片段中实现的代码的一个小示例,以了解它的工作原理。 dummyTV是片段中心的简单文本视图,它根据方向接收文本(为此我们需要一个计数器)。
<p>compu lack, Your styling is based on URL string</p>