Как сохранить данные EditText при изменении ориентации?

У меня есть экран входа в систему, который состоит из 2 EditTexts для имени пользователя и пароля. Мое требование состоит в том, что при изменении ориентации входные данные (если есть) в EditText должны оставаться такими, как есть, и должен быть также нарисован новый макет. У меня есть 2 макета xml файлов - один в папке макета и другой в папке макета-земли. Я пытаюсь реализовать следующие два подхода, но ни один из них не идеален:

(1) configChanges: keyboardHidden -. В этом подходе я не предоставляю "ориентацию" в configChanges в файле манифеста. Поэтому я вызываю метод setContentView() как в методах onCreate(), так и onConfigurationChanged(). Он выполняет оба моих требования. Макет изменен, а входные данные в EditTexts также остаются такими, какие есть. Но это имеет большую проблему:

Когда пользователь нажимает кнопку "Вход", ProgressDialog показывает, что сервер-ответ получен. Теперь, если пользователь поворачивает устройство во время работы ProgressDialog, приложение отключается. Он показывает сообщение об исключении: "Вид не может быть прикреплен к окну". Я попытался обработать его, используя onSaveInstanceState (который вызывается при изменении ориентации), но приложение все еще сбой.

(2) configChanges: orientation | keyboardHidden - В этом подходе я предоставляю "ориентацию" в манифесте. Итак, теперь у меня есть 2 сценария:

(a) Если я вызываю метод setContentView() как в onCreate(), так и onConfigurationChanged(), макет изменяется соответствующим образом, но данные EditText теряются.

(b) Если я вызываю метод setContentView() в onCreate(), но не в onConfigurationChanged(), то данные EditText не теряются, но макет также не изменяется соответствующим образом.

И в этом подходе, onSaveInstanceState() даже не вызывается.

Таким образом, я нахожусь в очень запугивающей ситуации. Есть ли решение этой проблемы? Пожалуйста помоги. Thanx заранее.

Ответ 1

в методе onConfigurationChanged сначала получите данные обоих текстов редактирования в глобальных переменных, а затем вызовите метод setContentView. Теперь снова установите сохраненные данные в тексты редактирования.

Ответ 2

По умолчанию Edittext сохраняет свой экземпляр при изменении ориентации.

Убедитесь, что 2 Edittexts имеют уникальные идентификаторы и имеют одинаковые идентификаторы в обоих макетах.

Таким образом, их состояние должно быть сохранено, и вы можете позволить Android обрабатывать изменение ориентации.

Если вы используете фрагмент, убедитесь, что он имеет уникальный идентификатор, и вы не воссоздаете его при воссоздании Activity.

Ответ 3

Лучший подход - позволить андроиду обрабатывать изменение ориентации. 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());
    }

Ответ 4

Есть много способов сделать это. Самый простой - 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);
}

Ответ 5

Im восстанавливая экземпляр для восстановления значений, и он отлично работает для меня:)

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

}

Ответ 6

Следующее должно работать и является стандартным для действий и фрагментов

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

Ответ 7

Добавление в EditText атрибута

android:id="@id/anything"

работал со мной.

Ответ 8

Измените атрибут android: configChanges из файла манифеста и позвольте андроиду обрабатывать изменение ориентации, ваши данные в 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();
        }

    }

Ответ 9

Как отмечает Ялла Т, важно не воссоздавать фрагмент. 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();

}

Ответ 10

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

}

Вы можете увидеть полный рабочий код ЗДЕСЬ

Ответ 11

это может помочь вам

если ваш андроид: targetSdkVersion = "12" или меньше

android:configChanges="orientation|keyboardHidden">

если ваш андроид: targetSdkVersion = "13" или более

android:configChanges="orientation|keyboardHidden|screenSize">