处理屏幕旋转而不会丢失数据 - Android

时间:2012-04-12 15:31:44

标签: android android-layout android-intent

我正在变得疯狂,弄清楚处理屏幕旋转的最佳方法是什么。我在这里阅读了数百个问题/答案,但我真的很困惑。

如何在重新创建活动之前保存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.
    }

8 个答案:

答案 0 :(得分:38)

在Manifest的Activity Tag中你应该提到

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

如果您使用的是Android 2.3(API级别13)及以上,请使用

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

它应该有效。

仅适用于活动标记,而不适用于应用标记

答案 1 :(得分:25)

可以使用覆盖方法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();
 }


}

答案 2 :(得分:14)

可能已经解决了这个问题,但只是对于坚持使用它的新成员进行了一次小更新,只需查看Google Developer Site,从API级别13开始,您只需要将此代码添加到Manifest:< / p>

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

当其中一个配置发生更改时,SplashScreensActivity不会重新启动。相反,SplashScreensActivity接收对onConfigurationChanged()的调用。此方法传递一个Configuration对象,该对象指定新设备配置。通过读取“配置”中的字段,您可以确定新配置并通过更新界面中使用的资源进行适当的更改。在调用此方法时,您的活动的Resources对象会更新,以根据新配置返回资源,因此您可以轻松重置UI的元素,而无需系统重新启动您的活动。

答案 3 :(得分:11)

这里的问题是你正在失去App的“状态”。在OOP中,什么是国家?变量!究竟!因此,当您丢失变量的数据时。

现在,您可以执行以下操作,找出失去状态的变量。

enter image description here

当您旋转设备时,您当前的活动会被彻底销毁,即通过 onSaveInstanceState() onPause() onStop() onDestroy()并完全创建一个新活动,该活动将通过onCreate() onStart() <强> onRestoreInstanceState 即可。

粗体中的两个方法 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将负责显示数据。
  • 活动将负责如何显示数据。
  • 如果您存储数据的复杂性日益增加,请使用其他存储库类。

这只是分离课程及其责任的一种方式,这将在制作结构良好的应用程序方面取得很大进展。

答案 4 :(得分:3)

有两种(好的)方法。让您的类实现Parcelable并将其放在onSaveInstanceState()中的包中,或者,如果它更复杂(例如AsyncTask),则将其返回onRetainNonConfigurationInstance()

然后还有一种懒惰的方式,你只是停止对配置更改做出反应。

答案 5 :(得分:2)

如果您不需要重新启动活动,只需将AndroidManifest.xml中活动的configChanges属性设置为:

    android:configChanges="keyboard|keyboardHidden|orientation"

这将告诉操作系统您将负责处理轮换并且不会重新启动您的活动。使用此方法将无需您保存任何类型的状态。

答案 6 :(得分:0)

来自文档:

  

注意:如果您的应用程序针对Android 3.2(API级别13)或   更高,那么您还应该声明“ screenSize”,   “ screenLayout”配置,因为当   设备在纵向和横向之间切换。

所以您应该写的是:

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

答案 7 :(得分:0)

它解决了我的问题。

<activity android:name=".MyActivity"
      android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
      android:label="@string/app_name">