30

ユーザー名とパスワードの2つのEditTextで構成されるログイン画面があります。私の要件は、向きを変更するときに、EditTextの入力データ(存在する場合)をそのままにして、新しいレイアウトも描画することです。2つのレイアウトxmlファイルがあります。1つはlayoutフォルダーに、もう1つはlayout-landフォルダーにあります。私は次の2つのアプローチを実装しようとしていますが、どれも完璧ではありません。

(1)configChanges:keyboardHidden-このアプローチでは、マニフェストファイルのconfigChangesに「方向」を指定しません。そのため、onCreate()メソッドとonConfigurationChanged()メソッドの両方でsetContentView()メソッドを呼び出します。それは私の両方の要件を満たしています。レイアウトが変更され、EditTextsの入力データもそのまま残ります。しかし、それは大きな問題を抱えています:

ユーザーが[ログイン]ボタンをクリックすると、サーバー応答が受信されるまでProgressDialogが表示されます。これで、ProgressDialogの実行中にユーザーがデバイスを回転させると、アプリがクラッシュします。「ビューをウィンドウにアタッチできません」という例外が表示されます。onSaveInstanceState(向きの変更時に呼び出されます)を使用して処理しようとしましたが、アプリがクラッシュします。

(2)configChanges:orientation |keyboardHidden-このアプローチでは、マニフェストに「orientation」を提供します。だから今私は2つのシナリオがあります:

(a) onCreate()とonConfigurationChanged()の両方でsetContentView()メソッドを呼び出すと、それに応じてレイアウトが変更されますが、EditTextデータは失われます。

(b) onCreate()でsetContentView()メソッドを呼び出したが、onConfigurationChanged()では呼び出さなかった場合、EditTextデータは失われませんが、それに応じてレイアウトも変更されません。

そして、このアプローチでは、onSaveInstanceState()は呼び出されません。

ですから、私は本当に恐ろしい状況にあります。この問題の解決策はありますか?助けてください。よろしくお願いします。

4

12 に答える 12

88

デフォルトでは、Edittextは、向きを変更するときに独自のインスタンスを保存します。

2つのエディットテキストが一意のIDを持ち、両方のレイアウトで同じIDを持っていることを確認してください。

そうすれば、それらの状態を保存する必要があり、Androidに向きの変更を処理させることができます。

フラグメントを使用している場合は、フラグメントにも一意のIDがあることを確認し、アクティビティを再作成するときにフラグメントを再作成しないでください。

于 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

これを行うには多くの方法があります。最も単純なのはあなたの質問の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);
}
于 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 に答える
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 に答える
1

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

    }
于 2012-09-20T08:49:08.213 に答える
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

ここに画像の説明を入力してください

保存状態=保存(フラグメント状態+アクティビティ状態)

向きの変更中にフラグメントの状態を保存する場合、通常はこの方法で行います。

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

以下のコードは私のために働いています。2つのことを気にする必要があります。

  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>
于 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 に答える