web-dev-qa-db-ja.com

データを失うことなく画面の回転を処理する-Android

私は画面の回転を処理するための最良の方法が何であるかを考え出すことに夢中になっています。ここで何百もの質問/回答を読んでいますが、本当に混乱しています。

アクティビティを再作成する前にmyClassデータを保存して、無駄な初期化を行わずにアクティビティを再描画するためにすべてを保持するにはどうすればよいですか?

小包よりもきれいで良い方法はありますか?

横向きモードでレイアウトを変更したいので、回転を処理する必要があります。

public class MtgoLifecounterActivity extends Activity {

    MyClass myClass;

    // Called when the activity is first created
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        If ( ?? first run...myClass == null ? ) {
            myClass = new MyClass();
        } else {
            // do other stuff but I need myClass istance with all values.
        }
        // I want that this is called only first time. 
        // then in case of rotation of screen, i want to restore the other instance of myClass which
        // is full of data.
    }
38
Riccardo Neri

オーバーライドメソッドonSaveInstanceState()およびonRestoreInstanceState()を使用できます。または、画面の回転時にonCreate()の呼び出しを停止するには、マニフェストxml Android:configChanges="keyboardHidden|orientation"

注:カスタムクラスは、以下のParcelableの例を実装する必要があります。

@Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("obj", myClass);
    }

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onRestoreInstanceState(savedInstanceState);
 myClass=savedInstanceState.getParcelable("obj"));
}

public class MyParcelable implements Parcelable {
     private int mData;

 public int describeContents() {
     return 0;
 }

 /** save object in parcel */
 public void writeToParcel(Parcel out, int flags) {
     out.writeInt(mData);
 }

 public static final Parcelable.Creator<MyParcelable> CREATOR
         = new Parcelable.Creator<MyParcelable>() {
     public MyParcelable createFromParcel(Parcel in) {
         return new MyParcelable(in);
     }

     public MyParcelable[] newArray(int size) {
         return new MyParcelable[size];
     }
 };

 /** recreate object from parcel */
 private MyParcelable(Parcel in) {
     mData = in.readInt();
 }


}
26
Azhar Shaikh

マニフェストのアクティビティタグでは、言及する必要があります

<activity
        Android:name="com.example.ListActivity"
        Android:label="@string/app_name" 
        Android:configChanges="keyboardHidden|orientation">

Android 2.3(API level 13)以上を使用している場合

<activity
        Android:name="com.example.Activity"
        Android:label="@string/app_name" 
        Android:configChanges="keyboardHidden|orientation|screenSize">

動作するはずです。

activityタグでのみ動作し、applicationタグでは動作しません

42
Cool7

これは既に解決されているかもしれませんが、それに固執する新しいメンバーのための小さな更新のために、 Google Developer Site を見てください、APIレベル13から、このコードをマニフェストに追加するだけです:

<activity Android:name=".SplashScreensActivity"
          Android:configChanges="orientation|keyboardHidden|screenSize"
          Android:label="@string/app_name">

これらの構成のいずれかが変更されると、SplashScreensActivityは再起動しません。代わりに、SplashScreensActivityはonConfigurationChanged()の呼び出しを受け取ります。このメソッドには、新しいデバイス構成を指定するConfigurationオブジェクトが渡されます。構成のフィールドを読み取ることにより、新しい構成を決定し、インターフェイスで使用されるリソースを更新することにより適切な変更を加えることができます。このメソッドが呼び出されると、アクティビティのResourcesオブジェクトが更新され、新しい構成に基づいてリソースが返されるため、システムがアクティビティを再起動しなくてもUIの要素を簡単にリセットできます。

15
Zak Chapman

ここでの問題は、アプリの「状態」が失われていることです。 OOPでは、状態とは何ですか?変数!まさに!したがって、変数のデータを失っているとき。

これがあなたができることです。状態を失っている変数を見つけてください。

enter image description here

デバイスを回転させると、現在のアクティビティは完全に破棄されます。つまり、onSaveInstanceState()onPause() onStop() onDestroy()を通過し、新しいアクティビティが作成されます。完全にonCreate() onStart()onRestoreInstanceStateを通過します。

太字の2つのメソッドonSaveInstanceState()は、破棄される現在のアクティビティのインスタンスを保存します。 onRestoreInstanceStateこのメソッドは、以前のアクティビティの保存状態を復元します。これにより、アプリの以前の状態を失うことはありません。

これらのメソッドの使用方法は次のとおりです。

 @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);

        outState.putString("theWord", theWord); // Saving the Variable theWord
        outState.putStringArrayList("fiveDefns", fiveDefns); // Saving the ArrayList fiveDefns
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onRestoreInstanceState(savedInstanceState, persistentState);

        theWord = savedInstanceState.getString("theWord"); // Restoring theWord
        fiveDefns = savedInstanceState.getStringArrayList("fiveDefns"); //Restoring fiveDefns
    }

編集:より良いアプローチ:データを維持するための上記のアプローチは、本番コード/アプリでデータを維持する最良の方法ではありません。 Google IO 2017は、画面の回転などの構成変更からデータを保護するためにViewModelを導入しました。変数を使用してアクティビティ内のすべてのデータを保持することは、良いソフトウェア設計ではなく、単一責任原則したがって、ViewModelを使用してデータストレージをアクティビティから分離します。

  • ViewModelは、表示されるデータを担当します。
  • アクティビティは、データの表示方法を担当します。
  • データの格納の複雑さが増している場合は、追加のリポジトリクラスを使用します。

これは、クラスとその責任を分離する方法の1つにすぎません。これは、適切にアーキテクチャ化されたアプリを作成する際に大いに役立ちます。

13
devDeejay

これには2つの(良い)方法があります。クラスでParcelableを実装し、onSaveInstanceState()のバンドルに入れるか、より複雑な場合(AsyncTaskなど)、onRetainNonConfigurationInstance()で返します。

次に、構成の変更に反応するのをやめるだけの怠laな方法もあります。

4
dmon

アクティビティを再起動する必要がない場合は、AndroidManifest.xmlのアクティビティのconfigChanges属性を次のように設定するだけです。

    Android:configChanges="keyboard|keyboardHidden|orientation"

これにより、OSにローテーションを処理するように指示し、アクティビティを再開しません。この方法を使用すると、あらゆる種類の状態を保存する必要がなくなります。

3
Bobbake4