屏幕旋转后Fragment无法保留EditText值的问题求助
解决Fragment屏幕旋转后EditText数据丢失的问题
我完全懂你现在的困扰——屏幕切换方向(还用到了不同横竖屏布局)时,Fragment里的EditText输入内容总是丢失,而且你已经试了onSaveInstanceState和setRetainInstance(true)这些常规方法却没起效,这确实挺闹心的。咱们来拆解问题,一步步搞定:
问题根源分析
你当前的代码里有两个关键的小问题:
setRetainInstance(true)确实能保留Fragment实例,但视图层(比如EditText)还是会被销毁重建,你原来的etxt_firstname引用会指向旧布局的控件,新布局的控件没被正确赋值。- 当开启
setRetainInstance(true)时,onCreate的savedInstanceState会是null,导致你在onActivityCreated里的恢复代码根本没执行。
方案一:基于setRetainInstance的修正版
既然你已经用了setRetainInstance(true),咱们调整代码让它真正生效:
- 先在Fragment里定义成员变量存储输入值:
private String mFirstName; private String mLastName; private EditText etxt_firstname; private EditText etxt_lastname;
- 修正
onCreateView,每次加载新布局后重新获取控件引用并恢复数据:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = null; if(!isTablet(myContext)) { if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { view = inflater.inflate(R.layout.fragment_home_landscape, container, false); } else { view = inflater.inflate(R.layout.fragment_home, container, false); } } else { view = inflater.inflate(R.layout.fragment_home, container, false); } // 关键:每次布局重建后,重新获取EditText引用 etxt_firstname = view.findViewById(R.id.etxt_firstname); etxt_lastname = view.findViewById(R.id.etxt_lastname); // 恢复之前保存的输入值 if (mFirstName != null) { etxt_firstname.setText(mFirstName); } if (mLastName != null) { etxt_lastname.setText(mLastName); } return view; }
- 在文本变化或页面暂停时,把输入值保存到成员变量:
// 方法一:监听EditText文本变化实时保存 @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); etxt_firstname.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mFirstName = s.toString(); } @Override public void afterTextChanged(Editable s) {} }); etxt_lastname.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mLastName = s.toString(); } @Override public void afterTextChanged(Editable s) {} }); } // 方法二:在页面暂停时保存(作为补充) @Override public void onPause() { super.onPause(); if (etxt_firstname != null) { mFirstName = etxt_firstname.getText().toString(); } if (etxt_lastname != null) { mLastName = etxt_lastname.getText().toString(); } }
方案二:Jetpack ViewModel(推荐的现代写法)
如果想彻底摆脱配置变化的困扰,ViewModel是Android官方推荐的方案,它的生命周期独立于Activity/Fragment的配置变化,更可靠:
- 创建ViewModel类:
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; public class HomeViewModel extends ViewModel { private final MutableLiveData<String> mFirstName = new MutableLiveData<>(); private final MutableLiveData<String> mLastName = new MutableLiveData<>(); public void updateFirstName(String name) { mFirstName.setValue(name); } public MutableLiveData<String> getFirstName() { return mFirstName; } public void updateLastName(String name) { mLastName.setValue(name); } public MutableLiveData<String> getLastName() { return mLastName; } }
- 在Fragment里使用ViewModel:
import androidx.lifecycle.ViewModelProvider; public class HomeFragment extends Fragment { private HomeViewModel mViewModel; private EditText etxt_firstname; private EditText etxt_lastname; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 获取ViewModel实例,配置变化时不会销毁 mViewModel = new ViewModelProvider(this).get(HomeViewModel.class); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 你的布局加载代码不变 View view = ...; // 获取控件引用 etxt_firstname = view.findViewById(R.id.etxt_firstname); etxt_lastname = view.findViewById(R.id.etxt_lastname); // 观察ViewModel的数据,自动同步到EditText mViewModel.getFirstName().observe(getViewLifecycleOwner(), name -> { if (name != null) { etxt_firstname.setText(name); } }); mViewModel.getLastName().observe(getViewLifecycleOwner(), name -> { if (name != null) { etxt_lastname.setText(name); } }); // 监听EditText变化,更新ViewModel数据 etxt_firstname.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mViewModel.updateFirstName(s.toString()); } @Override public void afterTextChanged(Editable s) {} }); etxt_lastname.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mViewModel.updateLastName(s.toString()); } @Override public void afterTextChanged(Editable s) {} }); return view; } }
这种方法不需要setRetainInstance(true),也不用手动处理Bundle,ViewModel会自动帮你保留数据,是目前最稳定的解决方案。
内容的提问来源于stack exchange,提问作者Animesh Jena
相关产品推荐
相关产品推荐

