Android 如何在方向更改时保留 EditText 数据?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12420396/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to retain EditText data on orientation change?
提问by Yogesh Somani
I have a Login screen which consists of 2 EditTexts for Username and Password. My requirement is that on orientation change , input data(if any) in EditText should remain as it is and a new layout should also be drawn.I have 2 layout xml files- one in layout folder and other in layout-land folder. I am trying to implement following 2 approaches but none of them is perfect:
我有一个登录屏幕,其中包含 2 个用于用户名和密码的 EditText。我的要求是在方向改变时,EditText 中的输入数据(如果有)应该保持原样,并且还应该绘制新的布局。我有 2 个布局 xml 文件 - 一个在 layout 文件夹中,另一个在 layout-land 文件夹中。我正在尝试实施以下两种方法,但它们都不是完美的:
(1) configChanges:keyboardHidden -In this approach, I don't provide "orientation" in configChanges in manifest file. So I call setContentView() method in both onCreate() and onConfigurationChanged() methods. It fulfills both my requirements. Layout is changed and input data in EditTexts also remains as it is. But it has a big problem :
(1) configChanges:keyboardHidden -在这种方法中,我不在清单文件的 configChanges 中提供“方向”。所以我在 onCreate() 和 onConfigurationChanged() 方法中都调用了 setContentView() 方法。它满足我的两个要求。布局已更改,并且 EditTexts 中的输入数据也保持原样。但它有一个大问题:
When user clicks on Login button, a ProgressDialog shows until server-response is received. Now if user rotates the device while ProgressDialog is running, app crashes. It shows an Exception saying "View cannot be attached to Window." I have tried to handle it using onSaveInstanceState (which DOES get called on orientation change) but app still crashes.
当用户单击“登录”按钮时,将显示 ProgressDialog,直到收到服务器响应。现在,如果用户在 ProgressDialog 运行时旋转设备,应用程序会崩溃。它显示一个异常,说“视图不能附加到窗口”。我尝试使用 onSaveInstanceState (在方向更改时调用)来处理它,但应用程序仍然崩溃。
(2) configChanges:orientation|keyboardHidden -In this approach, I provide "orientation" in manifest. So now I have 2 scenarios:
(2) configChanges:orientation|keyboardHidden -在这种方法中,我在清单中提供“方向”。所以现在我有两个场景:
(a)If I call setContentView() method in both onCreate() and onConfigurationChanged(), Layout is changed accordingly but EditText data is lost.
(a)如果我在 onCreate() 和 onConfigurationChanged() 中调用 setContentView() 方法,布局会相应更改,但 EditText 数据丢失。
(b)If I call setContentView() method in onCreate() , but not in onConfigurationChanged(), then EditText data is not lost but layout also not changes accordingly.
(b)如果我在 onCreate() 中调用 setContentView() 方法,而不是在 onConfigurationChanged() 中,则 EditText 数据不会丢失,但布局也不会相应地更改。
And in this approach, onSaveInstanceState() is not even called.
在这种方法中,甚至没有调用 onSaveInstanceState()。
So I am in a really intimidating situation. Is there any solution to this problem? Please help. Thanx in advance.
所以我处于一个非常令人生畏的境地。这个问题有什么解决办法吗?请帮忙。提前谢谢。
采纳答案by Arpit Raniwala
in onConfigurationChanged method, first get the data of both the edit texts in global variables and then call setContentView method. Now set the saved data again into the edit texts.
在 onConfigurationChanged 方法中,首先获取全局变量中两个编辑文本的数据,然后调用 setContentView 方法。现在再次将保存的数据设置到编辑文本中。
回答by Yalla T.
By default, Edittext save their own instance when changing orientation.
默认情况下,Edittext 在更改方向时保存自己的实例。
Be sure that the 2 Edittexts have unique IDs and have the same IDs in both Layouts.
确保这 2 个 Edittext 具有唯一的 ID,并且在两个布局中具有相同的 ID。
That way, their state should be saved and you can let Android handle the orientation change.
这样,他们的状态应该被保存,你可以让 Android 处理方向变化。
If you are using a fragment, be sure it has a unique ID also and you dont recreate it when recreating the Activity.
如果您使用的是片段,请确保它也具有唯一 ID,并且在重新创建活动时不要重新创建它。
回答by karn
A better approach is to let android handle the orientation change. Android will automatically fetch the layout from the correct folder and display it on the screen. All you need to do is to save the input values of the edit texts in the onSaveInsanceState() methodand use these saved values to initialize the edit texts in the onCreate() method.
Here is how you can achieve this:
更好的方法是让 android 处理方向变化。Android 会自动从正确的文件夹中获取布局并将其显示在屏幕上。您需要做的就是在onSaveInsanceState() 方法中保存编辑文本的输入值,并使用这些保存的值在onCreate() 方法中初始化编辑文本。
以下是您如何实现这一目标:
@Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.login_screen);
...
...
String userName, password;
if(savedInstanceState!=null)
{
userName = savedInstanceState.getString("user_name");
password= savedInstanceState.getString("password");
}
if(userName != null)
userNameEdtTxt.setText(userName);
if(password != null)
passEdtTxt.setText(password);
}
>
>
@Override
protected void onSaveInstanceState (Bundle outState)
{
outState.putString("user_name", userNameEdtTxt.getText().toString());
outState.putString("password", passEdtTxt.getText().toString());
}
回答by Carlos López Marí
Give the element an id and Android will manage it for you.
给元素一个 id,Android 会为你管理它。
android:id="@id/anything"
回答by sujith
There are many ways to do this. The simplest is 2(b) in your question. Mention android:configChanges="orientation|keyboardHidden|screenSize"
in your manifest so that Activity doesn't get destroyed on Orientation changes.
有很多方法可以做到这一点。最简单的是您问题中的 2(b)。android:configChanges="orientation|keyboardHidden|screenSize"
在您的清单中提及,以便 Activity 不会因方向更改而被破坏。
Call setContentView()
in onConfigChange()
. but before calling setContentView() get the EditText data into a string and set it back after calling setContentView()
打setContentView()
进来onConfigChange()
。但在调用 setContentView() 之前将 EditText 数据转换为字符串并在调用后将其设置回来setContentView()
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mEditTextData = mEditText.getText().tostring();//mEditTextData is a String
//member variable
setContentView(R.layout.myLayout);
initializeViews();
}
private void initializeViews(){
mEditText = (EditText)findViewById(R.id.edittext1);
mEdiText.setText(mEditTextData);
}
回答by Aswin Anand
Im restoring instance to restore values and it works fine for me :)
我正在恢复实例以恢复值,它对我来说很好用:)
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask2);
if(savedInstanceState!=null)
onRestoreInstanceState(savedInstanceState);
}
回答by chris-tulip
The following should work and is standard to the activities and fragments
以下应该工作并且是活动和片段的标准
@Override
public void onSaveInstanceState (Bundle outState)
{
outState.putString("editTextData1", editText1.getText().toString());
outState.putString("editTextData2", editText2.getText().toString());
super.onSaveInstanceState(outState);
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate();
... find references to editText1, editText2
if (savedInstanceState != null)
{
editText1.setText(savedInstanceState.getString("editTextData1");
editText2.setText(savedInstanceState.getString("editTextData2");
}
}
回答by Gunnar Bernstein
As pointed out by Yalla T it is important to not recreate the fragment. The EditText will not lose its content if the existing fragment is reused.
正如 Yalla T 所指出的,重要的是不要重新创建片段。如果重复使用现有片段,则 EditText 不会丢失其内容。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_frame);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Display the fragment as the main content.
// Do not do this. It will recreate the fragment on orientation change!
// getSupportFragmentManager().beginTransaction().replace(android.R.id.content, new Fragment_Places()).commit();
// Instead do this
String fragTag = "fragUniqueName";
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = (Fragment) fm.findFragmentByTag(fragTag);
if (fragment == null)
fragment = new Fragment_XXX(); // Here your fragment
FragmentTransaction ft = fm.beginTransaction();
// ft.setCustomAnimations(R.xml.anim_slide_in_from_right, R.xml.anim_slide_out_left,
// R.xml.anim_slide_in_from_left, R.xml.anim_slide_out_right);
ft.replace(android.R.id.content, fragment, fragTag);
// ft.addToBackStack(null); // Depends on what you want to do with your back button
ft.commit();
}
回答by Chandrashekhar
Remove android:configChanges attribute from the menifest file and let android handle the orientation change your data in edittext will automatically remain.
从menifest 文件中删除android:configChanges 属性并让android 处理方向更改,您在edittext 中的数据将自动保留。
Now The problem you mentioned is with the progress dialog force close this is because when the orientation is changed the thread running in backgroud is trying to update the older dialog component whihc was visible. You can handle it by closing the dialog on savedinstancestate method and recalling the proceess you want to perform onRestoreInstanceState method.
现在您提到的问题是进度对话框强制关闭,这是因为当方向改变时,在后台运行的线程试图更新可见的旧对话框组件。您可以通过关闭savedinstancestate 方法上的对话框并调用您要在onRestoreInstanceState 方法上执行的过程来处理它。
Below is a sample hope it helps solving your problem:-
以下是一个示例,希望它有助于解决您的问题:-
public class MyActivity extends Activity {
private static final String TAG = "com.example.handledataorientationchange.MainActivity";
private static ProgressDialog progressDialog;
private static Thread thread;
private static boolean isTaskRunnig;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new EditText.OnClickListener() {
@Override
public void onClick(View v) {
perform();
isTaskRunnig = true;
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void perform() {
Log.d(TAG, "perform");
progressDialog = android.app.ProgressDialog.show(this, null,
"Working, please wait...");
progressDialog
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
//isTaskRunnig = false;
}
});
thread = new Thread() {
public void run() {
Log.d(TAG, "run");
int result = 0;
try {
// Thread.sleep(5000);
for (int i = 0; i < 20000000; i++) {
}
result = 1;
isTaskRunnig = false;
} catch (Exception e) {
e.printStackTrace();
result = 0;
}
Message msg = new Message();
msg.what = result;
handler.sendMessage(msg);
};
};
thread.start();
}
// handler to update the progress dialgo while the background task is in
// progress
private static Handler handler = new Handler() {
public void handleMessage(Message msg) {
Log.d(TAG, "handleMessage");
int result = msg.what;
if (result == 1) {// if the task is completed successfully
Log.d(TAG, "Task complete");
try {
progressDialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
isTaskRunnig = true;
}
}
}
};
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "onRestoreInstanceState" + isTaskRunnig);
if (isTaskRunnig) {
perform();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "onSaveInstanceState");
if (thread.isAlive()) {
thread.interrupt();
Log.d(TAG, thread.isAlive() + "");
progressDialog.dismiss();
}
}
回答by Rohit Singh
Saving state = Saving (Fragment State + Activity State)
保存状态 = 保存(片段状态 + 活动状态)
When it comes to saving the state of a Fragment during orientation change, I usually do this way.
在方向更改期间保存 Fragment 的状态时,我通常这样做。
1) Fragment State:
1) 片段状态:
Save and Restore EditText value
保存和恢复 EditText 值
// Saving State
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("USER_NAME", username.getText().toString());
outState.putString("PASSWORD", password.getText().toString());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.user_name_fragment, parent, false);
username = (EditText) view.findViewById(R.id.username);
password = (EditText) view.findViewById(R.id.password);
// Retriving value
if (savedInstanceState != null) {
username.setText(savedInstanceState.getString("USER_NAME"));
password.setText(savedInstanceState.getString("PASSWORD"));
}
return view;
}
2) Activity State::
2)活动状态::
Create a new Instance when the activity launches for the first time else find the old fragment using a TAGand the FragmentManager
当活动第一次启动时创建一个新实例,否则使用TAG和FragmentManager查找旧片段
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
fragmentManager = getSupportFragmentManager();
if(savedInstanceState==null) {
userFragment = UserNameFragment.newInstance();
fragmentManager.beginTransaction().add(R.id.profile, userFragment, "TAG").commit();
}
else {
userFragment = fragmentManager.findFragmentByTag("TAG");
}
}
You can see the the full working code HERE
您可以在此处查看完整的工作代码