我有一个登录屏幕,其中包含2个用于用户名和密码的EditTexts。 我的要求是,在方向更改时,EditText中的输入数据(如果有)应保持原样,并且还应绘制新布局。我有2个布局xml文件 - 布局文件夹中有一个,其他在layout-land文件夹中。我正在尝试实施以下两种方法,但它们都不是完美的:
(1)configChanges:keyboardHidden - 在这种方法中,我没有在清单文件中的configChanges中提供“orientation”。所以我在onCreate()和onConfigurationChanged()方法中都调用了setContentView()方法。它符合我的要求。布局已更改,EditTexts中的输入数据也保持不变。但它有一个很大的问题:
当用户点击“登录”按钮时, ProgressDialog会显示,直到收到服务器响应为止。现在,如果用户在ProgressDialog运行时旋转设备,则应用程序崩溃。它显示一个异常,说“视图无法附加到窗口”。我试图使用onSaveInstanceState处理它(它会在方向更改时调用)但应用程序仍然崩溃。
(2)configChanges:orientation | keyboardHidden - 在这种方法中,我在清单中提供“方向”。所以现在我有两个场景:
(a)如果我在onCreate()和onConfigurationChanged()中调用setContentView()方法,则会相应地更改Layout,但会丢失EditText数据。
(b)如果我在onCreate()中调用setContentView()方法,而不是onConfigurationChanged(),则EditText数据不会丢失,但布局也不会相应更改。
在这种方法中,甚至不调用onSaveInstanceState()。
所以我处在一个非常令人生畏的境地。有没有解决这个问题的方法?请帮忙。提前完成。
答案 0 :(得分:78)
默认情况下,Edittext在更改方向时保存自己的实例。
确保2个Edittexts具有唯一ID,并且在两个布局中具有相同的ID。
这样,他们的状态应该被保存,你可以让Android处理方向改变。
如果您正在使用片段,请确保它还具有唯一ID,并且在重新创建活动时不会重新创建它。
答案 1 :(得分:33)
更好的方法是让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());
}
答案 2 :(得分:9)
答案 3 :(得分:3)
有很多方法可以做到这一点。最简单的是你的问题中的2(b)。在清单中提及android:configChanges="orientation|keyboardHidden|screenSize"
,以便在方向更改时不会销毁活动。
在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);
}
答案 4 :(得分:3)
向属性
添加EditTextandroid:id="@id/anything"
对我有用。
答案 5 :(得分:2)
以下内容应该有效,并且是活动和片段的标准
@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");
}
}
答案 6 :(得分:2)
我正在恢复实例以恢复值,它适用于我:)
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask2);
if(savedInstanceState!=null)
onRestoreInstanceState(savedInstanceState);
}
答案 7 :(得分:1)
从menifest文件中删除android:configChanges属性,让android处理方向更改edittext中的数据会自动保留。
现在您提到的问题是进度对话框强制关闭这是因为当方向更改时,在backgroud中运行的线程正在尝试更新可见的旧对话框组件。您可以通过关闭savedinstancestate方法上的对话框并调用要在onRestoreInstanceState方法上执行的过程来处理它。
以下示例希望它有助于解决您的问题: -
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();
}
}
答案 8 :(得分:1)
正如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();
}
答案 9 :(得分:1)
在方向更改期间保存片段状态时,我通常采用这种方式。
1)片段状态:
保存和还原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)活动状态::
活动首次启动时创建一个新实例 否则使用 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");
}
}
您可以看到完整的工作代码HERE
答案 10 :(得分:0)
以下代码对我有用。需要注意两件事。
清单活动声明应具有以下值的配置更改属性。
android:configChanges =“ orientation | keyboardHidden | screenSize”
清单中的活动示例声明。
<activity
android:name=".screens.register.RegisterActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:label="Registration"
android:theme="@style/AppTheme.NoActionBar" />
的示例声明
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/inputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:boxCornerRadiusBottomEnd="@dimen/boxCornerRadiusDP"
app:boxCornerRadiusBottomStart="@dimen/boxCornerRadiusDP"
app:boxCornerRadiusTopEnd="@dimen/boxCornerRadiusDP"
app:boxCornerRadiusTopStart="@dimen/boxCornerRadiusDP">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/inputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:fontFamily="@font/proxima_nova_semi_bold"
android:inputType="textCapWords"
android:lines="1"
android:textColor="@color/colorInputText"
android:textColorHint="@color/colorInputText" />
</com.google.android.material.textfield.TextInputLayout>
答案 11 :(得分:-1)
这可能会对你有所帮助
如果 android:targetSdkVersion =“12”或更少
android:configChanges="orientation|keyboardHidden">
如果 android:targetSdkVersion =“13”或更多
android:configChanges="orientation|keyboardHidden|screenSize">