我已经写了很长时间的Android应用程序,但现在我遇到了一个我从未想过的问题。它是关于配置更改的Activitys
和Fragments
的android生命周期。为此,我用这个必要的代码创建了一个小应用程序:
public class MainActivity extends FragmentActivity {
private final String TAG = "TestFragment";
private TestFragment fragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
fragment = (TestFragment) fm.findFragmentByTag(TAG);
if (fragment == null) {
fragment = new TestFragment();
fm.beginTransaction().add(R.id.fragment_container, fragment, TAG).commit();
}
}
}
这是我TestFragment
的代码。请注意,我在setRetainInstance(true);
方法中调用了onCreate
,因此在配置更改后不会对片段进行重新调整。
public class TestFragment extends Fragment implements View.OnClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater li, ViewGroup parent, Bundle bundle) {
View rootView = li.inflate(R.layout.fragment_test, parent, false);
Button button = (Button) rootView.findViewById(R.id.toggleButton);
button.setOnClickListener(this);
return rootView;
}
@Override
public void onClick(View v) {
Button button = (Button) v;
String enable = getString(R.string.enable);
if(button.getText().toString().equals(enable)) {
button.setText(getString(R.string.disable));
} else {
button.setText(enable);
}
}
}
这是我的片段正在使用的布局:
<LinearLayout
...>
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/toggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/enable"/>
</LinearLayout>
我的问题是,如果我旋转设备,Button
的文本会更改回默认值。当然View
的{{1}}是新建的并且已经膨胀,但是应该恢复已保存的视图实例。我的布局中也有Fragment
,旋转后文本和其他属性仍然存在。那么为什么Button默认情况下不会从EditText
恢复?我已阅读developer site:
默认情况下,系统使用Bundle实例状态来保存活动布局中每个View对象的信息(例如输入EditText对象的文本值)。因此,如果您的活动实例被销毁并重新创建,则布局的状态将恢复到之前的状态,而您无需代码。
我在最后几天也读了很多答案,但我不知道他们的实际情况如何。请不要在Bundle
这是非常糟糕练习时发表评论或回答。我希望有人可以为我缺乏理解带来光明。
答案 0 :(得分:5)
您应该在NO 256
DATETIME 1 8:8:41.0
中保存片段的状态,并使用onSaveInstanceState(Bundle outState)
方法将其恢复。这样,您最终将获得UI,就像配置更改之前一样。
答案 1 :(得分:4)
TextView
子类默认不保存文本。您需要在布局中启用freezesText="true"
,或在运行时启用setFreezesText(true)
以保存其状态。
答案 2 :(得分:4)
根据文档,视图应保持其状态而不使用setRetainInstance(true)
。尝试将其从onCreate
中删除,这应该强制在屏幕旋转时重新创建片段,因此所有视图都应该在旋转之前保存并在之后恢复。
答案 3 :(得分:4)
这个堆栈溢出应该回答你的问题: setRetainInstance not retaining the instance
setRetainInstance
确实告诉片段保存其所有数据,对于用户操作状态的UI元素(EditText,ScrollView,ListView等),状态将恢复。话虽如此,正常的只读UI组件会在onCreateView
中从头开始重新填充,并且必须再次设置 - 我的猜测是他们的属性不被考虑&#34;数据&#34;需要保留和恢复 - 谷歌可能出于性能原因这样做。因此,如果它与XML中的初始状态不同,那么像普通Button,ImageView或TextView这样的内容在重新填充时需要手动设置它们的内容。 (TextView&#39; s android:freezesText
基本上将TextView置于一种使用实现来保存状态并恢复它的模式。
PS:根据此堆栈溢出Save and restore a ButtonText when screen orientation is switched,您可以在按钮上设置android:freezesText
以保留您设置的文本 - 我还没有尝试过,但它有道理。
答案 4 :(得分:2)
选择反馈后编辑
虽然没有回答这个问题,但在与OP协商后,我决定将其留在这里作为有关该主题的人的信息的参考点。希望你觉得它有用。
尝试将setRetainInstance
放入onCreateView
。见here
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater li, ViewGroup parent, Bundle bundle) {
setRetainInstance(true);
View rootView = li.inflate(R.layout.fragment_test, parent, false);
Button button = (Button) rootView.findViewById(R.id.toggleButton);
button.setOnClickListener(this);
return rootView;
}
在创建片段活动时调用此方法 片段的视图层次结构实例化。它可以用来做最后的 这些部分就位后进行初始化,例如检索 观点或恢复状态。它对使用的片段也很有用 setRetainInstance(boolean)保留它们的实例,就像这样 回调告诉片段何时与新片段完全关联 活动实例。这是在onCreateView(LayoutInflater, ViewGroup,Bundle)和onViewStateRestored(Bundle)之前。
developer.android.com/reference/android/app/Fragment.html#onActivityCreated
控制是否在Activity中保留片段实例 重新创建(例如从配置更改)。这只能是 与不在后栈中的片段一起使用。如果设置,则片段 重新创建活动时,生命周期会略有不同:
onDestroy()不会被调用(但onDetach()仍然会被调用,因为 片段正在脱离其当前的活动。) 因为片段不存在,所以不会调用onCreate(Bundle) 重新创建。
onAttach(Activity)和onActivityCreated(Bundle)会 仍被称为。
developer.android.com/reference/android/app/Fragment.html#setRetainInstance
取自here:
onCreate:在片段的初始创建时调用它。你做 你的非图形初始化在这里。它甚至在之前完成 布局膨胀,片段可见。
onCreateView:调用它来膨胀片段的布局,即 图形初始化通常发生在这里。它总是被称为 有时在onCreate方法之后。
onActivityCreated:如果您的视图是静态的,那么将任何代码移动到 onActivityCreated方法不是必需的。但是当你 - 为了 例如,从适配器填充一些列表,然后你应该进行 onActivityCreated方法以及何时恢复视图状态 setRetainInstance曾经这样做过。还访问视图层次结构 父活动必须在onActivityCreated中完成,而不是更早。
如果有帮助,请告诉我。