30

我有一个登录屏幕,其中包含 2 个用于用户名和密码的 EditText。我的要求是,在方向更改时,EditText 中的输入数据(如果有)应保持原样,并且还应绘制新布局。我有 2 个布局 xml 文件 - 一个在布局文件夹中,另一个在 layout-land 文件夹中。我正在尝试实现以下两种方法,但它们都不是完美的:

(1) configChanges:keyboardHidden -在这种方法中,我不在清单文件的 configChanges 中提供“方向”。所以我在 onCreate() 和 onConfigurationChanged() 方法中都调用了 setContentView() 方法。它满足我的两个要求。布局已更改,EditTexts 中的输入数据也保持原样。但它有一个大问题:

当用户单击登录按钮时,会显示一个 ProgressDialog,直到收到服务器响应。现在,如果用户在 ProgressDialog 运行时旋转设备,应用程序会崩溃。它显示一个异常说“视图不能附加到窗口”。我尝试使用 onSaveInstanceState 处理它(在方向更改时会调用它),但应用程序仍然崩溃。

(2) configChanges:orientation|keyboardHidden -在这种方法中,我在清单中提供“方向”。所以现在我有两种情况:

(a)如果我在 onCreate() 和 onConfigurationChanged() 中调用 setContentView() 方法,布局会相应更改,但 EditText 数据会丢失。

(b)如果我在 onCreate() 中调用 setContentView() 方法,但在 onConfigurationChanged() 中没有调用,则 EditText 数据不会丢失,但布局也不会相应更改。

在这种方法中,甚至不调用 onSaveInstanceState() 。

所以我处于一个非常可怕的境地。这个问题有什么解决办法吗?请帮忙。提前谢谢。

4

12 回答 12

88

默认情况下,Edittext 在更改方向时会保存自己的实例。

确保 2 个 Edittexts 具有唯一的 ID,并且在两个布局中具有相同的 ID。

这样,它们的状态应该被保存,您可以让 Android 处理方向更改。

如果您使用的是片段,请确保它也具有唯一 ID,并且在重新创建 Activity 时不要重新创建它。

于 2012-09-18T13:27:56.767 回答
34

更好的方法是让 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());
    }
于 2012-09-19T20:32:34.770 回答
9

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

于 2012-11-01T14:13:17.223 回答
9

给元素一个 id,Android 会为你管理它。

android:id="@id/anything"
于 2017-10-04T11:13:40.937 回答
2

我正在恢复实例以恢复值,它对我来说很好:)

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.addtask2);
    if(savedInstanceState!=null)
     onRestoreInstanceState(savedInstanceState);

}
于 2013-05-29T18:13:18.523 回答
2

有很多方法可以做到这一点。最简单的是您的问题中的 2(b)。在您的清单中提及android:configChanges="orientation|keyboardHidden|screenSize",以便 Activity 在方向更改时不会被破坏。

来电。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);
}
于 2012-09-17T05:09:14.163 回答
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");
      }
}
于 2012-09-18T16:30:52.677 回答
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();

}
于 2014-05-10T21:56:10.630 回答
1

从清单文件中删除 android:configChanges 属性并让 android 处理方向更改,您在 edittext 中的数据将自动保留。

现在您提到的问题是进度对话框强制关闭,这是因为当方向改变时,在背景中运行的线程正在尝试更新可见的旧对话框组件。您可以通过关闭有关 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();
        }

    }
于 2012-09-20T08:49:08.213 回答
1

在此处输入图像描述

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

当涉及到在方向更改期间保存 Fragment 的状态时,我通常会这样做。

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)活动状态::

在活动第一次启动时创建一个新实例,否则使用TAGFragmentManager找到旧片段

@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");
    }

}

您可以在此处查看完整的工作代码

于 2018-12-31T14:25:32.707 回答
0

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

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

    android:configChanges="方向|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>
于 2020-02-13T11:56:29.937 回答
-2

这可能会帮助你

如果您的android:targetSdkVersion="12" 或更少

android:configChanges="orientation|keyboardHidden">

如果你的 android:targetSdkVersion="13" 或更多

android:configChanges="orientation|keyboardHidden|screenSize">
于 2012-09-14T08:05:37.370 回答