Android 片段创建了两次方向改变
Android Fragment created twice orientation change
我的片段被创建了两次,即使 activity 只将片段添加到内容中一次。当我旋转屏幕时会发生这种情况。此外,每次调用片段的 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 在 activity 中检查 null savedInstanceState 并且只有在 null 时才会添加片段所以我不明白为什么应该创建片段两次?在 if 条件下放置一个断点告诉我它只被调用一次,所以 activity 不应该多次添加片段。然而,每次方向改变时,片段的 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) 保留了变量状态,但这是真正的解决方案吗?我希望片段不会仅在方向更改时创建。
Fragment
生命周期与 Activity
非常相似。默认情况下,是的,它们将在配置更改期间重新创建,就像 Activity
一样。这是预期的行为。即使使用 setRetainInstance(true)
(如果它包含 UI,我会说要格外小心使用)你的 View
将被销毁并重新创建,但在那种情况下你的 Fragment
实例不会被销毁——只是 View
.
在android中,当phone的方向改变时,activity会被销毁并重新创建。现在,我相信要解决您的问题,您可以使用片段管理器检查片段是否已存在于后台堆栈中,如果不存在则创建它。
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,它应该会起作用。
如前所述,在方向改变时,activity 被破坏并重新创建。此外,碎片(任何)由系统重新创建。
为确保您的应用程序恢复到之前的状态,在 activity 被销毁之前调用 onSaveInstanceState()。
因此,您可以在 activity 的 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.
}
}
我知道现在回答有点晚了,但是使用代码皮条客的回答你可以做接下来的事情:
如果片段存在于后台堆栈中,我们弹出并删除它以将其添加回来(如果添加回去而不删除它,则抛出异常,表示它已经存在)。
片段变量是一个class成员变量。
这个方法会在Activity的onCreate方法中调用:
if (savedInstanceState == null) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentManager.findFragmentById(getFragmentActivityLayoutContainerId()) == null) {
fragment = getNewFragmentInstance();
} else {
fragment = fragmentManager.findFragmentById(getFragmentActivityLayoutContainerId());
fragmentTransaction.remove(fragment);
fragmentManager.popBackStack();
fragmentTransaction.commit();
fragmentTransaction = fragmentManager.beginTransaction();
}
fragmentTransaction.add(getFragmentActivityLayoutContainerId(), fragment);
fragmentTransaction.commit();
}
下一个代码将在片段本身中调用。
这是一个代码的小示例,您可以在片段中实施代码以了解其工作原理。 dummyTV 是片段中心的一个简单文本视图,它根据方向接收文本(为此我们需要一个计数器)。
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");
}
我的片段被创建了两次,即使 activity 只将片段添加到内容中一次。当我旋转屏幕时会发生这种情况。此外,每次调用片段的 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 在 activity 中检查 null savedInstanceState 并且只有在 null 时才会添加片段所以我不明白为什么应该创建片段两次?在 if 条件下放置一个断点告诉我它只被调用一次,所以 activity 不应该多次添加片段。然而,每次方向改变时,片段的 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) 保留了变量状态,但这是真正的解决方案吗?我希望片段不会仅在方向更改时创建。
Fragment
生命周期与 Activity
非常相似。默认情况下,是的,它们将在配置更改期间重新创建,就像 Activity
一样。这是预期的行为。即使使用 setRetainInstance(true)
(如果它包含 UI,我会说要格外小心使用)你的 View
将被销毁并重新创建,但在那种情况下你的 Fragment
实例不会被销毁——只是 View
.
在android中,当phone的方向改变时,activity会被销毁并重新创建。现在,我相信要解决您的问题,您可以使用片段管理器检查片段是否已存在于后台堆栈中,如果不存在则创建它。
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,它应该会起作用。
如前所述,在方向改变时,activity 被破坏并重新创建。此外,碎片(任何)由系统重新创建。
为确保您的应用程序恢复到之前的状态,在 activity 被销毁之前调用 onSaveInstanceState()。
因此,您可以在 activity 的 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.
}
}
我知道现在回答有点晚了,但是使用代码皮条客的回答你可以做接下来的事情:
如果片段存在于后台堆栈中,我们弹出并删除它以将其添加回来(如果添加回去而不删除它,则抛出异常,表示它已经存在)。
片段变量是一个class成员变量。
这个方法会在Activity的onCreate方法中调用:
if (savedInstanceState == null) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentManager.findFragmentById(getFragmentActivityLayoutContainerId()) == null) {
fragment = getNewFragmentInstance();
} else {
fragment = fragmentManager.findFragmentById(getFragmentActivityLayoutContainerId());
fragmentTransaction.remove(fragment);
fragmentManager.popBackStack();
fragmentTransaction.commit();
fragmentTransaction = fragmentManager.beginTransaction();
}
fragmentTransaction.add(getFragmentActivityLayoutContainerId(), fragment);
fragmentTransaction.commit();
}
下一个代码将在片段本身中调用。
这是一个代码的小示例,您可以在片段中实施代码以了解其工作原理。 dummyTV 是片段中心的一个简单文本视图,它根据方向接收文本(为此我们需要一个计数器)。
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");
}