Android中EditText屏幕旋转后保留内容,TextView却不保留的原因?
屏幕旋转时TextView与EditText状态保存差异的原因及实现机制
现象本质
屏幕旋转属于Android的配置变更场景,此时系统会销毁当前Activity实例,再重建一个新实例。系统会自动帮部分View完成状态的保存与恢复,但不是所有View都默认支持这个能力,这就是你看到TextView和EditText表现不同的核心原因。
EditText能自动保存状态的实现逻辑
EditText虽然继承自TextView,但系统为它做了特殊处理:
- 首先,EditText默认开启了
android:saveEnabled="true"(这个属性所有View都有,默认值为true),更关键的是它重写了View的onSaveInstanceState()和onRestoreInstanceState()方法 - 在
onSaveInstanceState()里,EditText会把输入文本、光标位置等状态打包成SavedState(内部Parcelable类)对象 - 系统在Activity销毁前,会遍历所有带id的View,调用它们的
onSaveInstanceState()收集状态;重建时再通过id匹配,调用对应View的onRestoreInstanceState()恢复状态 - 这里必须注意:EditText必须设置
android:id,否则系统无法识别该View,也就不会保存它的状态
TextView默认不保存状态的原因
TextView默认没有重写onSaveInstanceState()来处理文本内容的保存:
- 它的父类View的默认
onSaveInstanceState()只会保存一些基础状态(比如可见性、焦点状态),不会处理文本数据 - 就算你给TextView设置了id,系统也只会保存那些基础状态,不会主动帮你保存文本
让TextView也能保留状态的两种方案
方案1:自定义TextView重写状态保存方法
自己写一个继承TextView的类,手动实现状态的保存与恢复:
public class StatefulTextView extends AppCompatTextView { private static final String SAVED_TEXT = "saved_text"; public StatefulTextView(Context context) { super(context); } public StatefulTextView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected Parcelable onSaveInstanceState() { // 先保存父类的基础状态 Parcelable superState = super.onSaveInstanceState(); Bundle bundle = new Bundle(); // 把当前文本存入Bundle bundle.putString(SAVED_TEXT, getText().toString()); bundle.putParcelable("super_state", superState); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; // 恢复文本内容 setText(bundle.getString(SAVED_TEXT)); // 恢复父类的基础状态 state = bundle.getParcelable("super_state"); } super.onRestoreInstanceState(state); } }
之后在布局里使用这个自定义TextView,记得给它设置id。
方案2:在Activity中手动保存恢复
在Activity的生命周期方法里手动处理TextView的状态:
private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.my_text_view); // 重建时恢复状态 if (savedInstanceState != null) { String savedText = savedInstanceState.getString("tv_content"); textView.setText(savedText); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 销毁前保存TextView的文本 outState.putString("tv_content", textView.getText().toString()); }
同样需要给TextView设置id,确保能在Activity中获取到实例。
内容的提问来源于stack exchange,提问作者Arihant Jain
相关产品推荐
相关产品推荐

