Ответ 1
в методе onConfigurationChanged сначала получите данные обоих текстов редактирования в глобальных переменных, а затем вызовите метод setContentView. Теперь снова установите сохраненные данные в тексты редактирования.
У меня есть экран входа в систему, который состоит из 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 заранее.
в методе onConfigurationChanged сначала получите данные обоих текстов редактирования в глобальных переменных, а затем вызовите метод setContentView. Теперь снова установите сохраненные данные в тексты редактирования.
По умолчанию Edittext сохраняет свой экземпляр при изменении ориентации.
Убедитесь, что 2 Edittexts имеют уникальные идентификаторы и имеют одинаковые идентификаторы в обоих макетах.
Таким образом, их состояние должно быть сохранено, и вы можете позволить Android обрабатывать изменение ориентации.
Если вы используете фрагмент, убедитесь, что он имеет уникальный идентификатор, и вы не воссоздаете его при воссоздании Activity.
Лучший подход - позволить андроиду обрабатывать изменение ориентации. 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 (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);
}
Im восстанавливая экземпляр для восстановления значений, и он отлично работает для меня:)
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask2);
if(savedInstanceState!=null)
onRestoreInstanceState(savedInstanceState);
}
Следующее должно работать и является стандартным для действий и фрагментов
@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");
}
}
Добавление в EditText атрибута
android:id="@id/anything"
работал со мной.
Измените атрибут 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();
}
}
Как отмечает Ялла Т, важно не воссоздавать фрагмент. 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();
}
Когда дело доходит до сохранения состояния фрагмента во время изменения ориентации, я обычно так и делаю.
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");
}
}
Вы можете увидеть полный рабочий код ЗДЕСЬ
это может помочь вам
если ваш андроид: targetSdkVersion = "12" или меньше
android:configChanges="orientation|keyboardHidden">
если ваш андроид: targetSdkVersion = "13" или более
android:configChanges="orientation|keyboardHidden|screenSize">