如何在方向更改时保留EditText数据?

时间:2012-09-14 08:03:37

标签: android android-layout android-edittext orientation

我有一个登录屏幕,其中包含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()。

所以我处在一个非常令人生畏的境地。有没有解决这个问题的方法?请帮忙。提前完成。

12 个答案:

答案 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)

在onConfigurationChanged方法中,首先获取全局变量中两个编辑文本的数据,然后调用setContentView方法。现在将已保存的数据再次设置为编辑文本。

答案 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)

向属性

添加EditText
android: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)

enter image description here

保存状态=正在保存(片段状态+活动状态)

在方向更改期间保存片段状态时,我通常采用这种方式。

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)

以下代码对我有用。需要注意两件事。

  1. 每个输入字段(“编辑文本”或“ TextInputEditText”)分配唯一的ID。
  2. 清单活动声明应具有以下值的配置更改属性。

    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">
相关问题