ユーザー名とパスワードの2つのEditTextで構成されるログイン画面があります。 私の要件は、方向の変更時に、EditTextの入力データ(ある場合)をそのまま残し、新しいレイアウトも描画することです。 2つのレイアウトxmlファイルがあります-レイアウトフォルダーとその他に1つありますレイアウトランドフォルダー内。次の2つのアプローチを実装しようとしていますが、いずれも完璧ではありません。
(1)configChanges:keyboardHidden-このアプローチでは、マニフェストファイルのconfigChangesに「向き」を指定しません。そのため、onCreate()メソッドとonConfigurationChanged()メソッドの両方でsetContentView()メソッドを呼び出します。それは私の両方の要件を満たします。レイアウトが変更され、EditTextsの入力データもそのまま残ります。しかし、これには大きな問題があります。
ユーザーが[ログイン]ボタンをクリックすると、サーバー応答が受信されるまでProgressDialogが表示されます。 ProgressDialogの実行中にユーザーがデバイスを回転させると、アプリがクラッシュします。 「ビューをウィンドウにアタッチできません」という例外が表示されます。 onSaveInstanceState(向きの変更時に呼び出される)を使用して処理しようとしましたが、アプリはまだクラッシュします。
(2)configChanges:orientation | keyboardHidden-このアプローチでは、マニフェストに「向き」を指定します。だから今、私は2つのシナリオがあります:
(a) onCreate()とonConfigurationChanged()の両方でsetContentView()メソッドを呼び出すと、それに応じてレイアウトが変更されますが、EditTextデータは失われます。
(b) onCreate()でsetContentView()メソッドを呼び出すが、onConfigurationChanged()では呼び出さない場合、EditTextデータは失われませんが、レイアウトもそれに応じて変更されません。
そして、このアプローチでは、onSaveInstanceState()は呼び出されません。
だから私は本当に恐ろしい状況にあります。この問題の解決策はありますか?助けてください。事前に感謝します。
onConfigurationChangedメソッドでは、まずグローバル変数の両方の編集テキストのデータを取得してから、setContentViewメソッドを呼び出します。保存したデータを編集テキストに再度設定します。
デフォルトでは、Edittextは向きを変更するときに独自のインスタンスを保存します。
2つのEdittextが一意のIDを持ち、両方のレイアウトで同じIDを持っていることを確認してください。
そうすれば、状態を保存して、Android向きの変更を処理できます。
フラグメントを使用している場合は、フラグメントにも一意のIDが含まれていることを確認し、アクティビティを再作成するときにフラグメントを再作成しないでください。
より良いアプローチは、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(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);
}
_
EditTextに属性を追加する
Android:id="@id/anything"
私に働いた。
インスタンスを復元して値を復元すると、私にとってはうまくいきます:)
@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");
}
}
向きの変更中にフラグメントの状態を保存することになると、私は通常このようにします。
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 [〜#〜]
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();
}
Menifestファイルから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();
}
}