51

我正在疯狂地找出处理屏幕旋转的最佳方法。我在这里阅读了数百个问题/答案,但我真的很困惑。

如何在重新创建活动之前保存 myClass 数据,以便我可以保留重绘活动的所有内容,而无需进行其他无用的初始化?

有没有比 parcelable 更干净更好的方法?

我需要处理旋转,因为我想在横向模式下更改布局。

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.
    }
4

8 回答 8

49

在清单的活动标签中,您应该提到

<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">

它应该工作。

It will work only with activity tag and not with application tag

于 2013-11-29T06:22:56.890 回答
28

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


}
于 2012-04-12T15:37:29.200 回答
18

May be this is solved already but just for a small update for new members who stuck on it, just have a look at Google Developer Site, From API level 13, you just need to add this code to Manifest:

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

when one of these configurations change, SplashScreensActivity does not restart. Instead, the SplashScreensActivity receives a call to onConfigurationChanged(). This method is passed a Configuration object that specifies the new device configuration. By reading fields in the Configuration, you can determine the new configuration and make appropriate changes by updating the resources used in your interface. At the time this method is called, your activity's Resources object is updated to return resources based on the new configuration, so you can easily reset elements of your UI without the system restarting your activity.

于 2015-01-14T07:37:52.143 回答
18

The problem here is that you are losing the "state" of the App. In OOPs, What is a State? The Variables! Exactly! Hence when you are losing the data of your variables.

Now here is what you can do, Find Out the variables which are losing their states.

enter image description here

When you rotate your device, your present activity gets completely destroyed, ie goes through onSaveInstanceState() onPause() onStop() onDestroy() and a new activity is created completely which goes through onCreate() onStart() onRestoreInstanceState.

The Two Methods in the bold, onSaveInstanceState() saves the instance of the present activity which is going to be destroyed. onRestoreInstanceState This method restores the saved state of the previous activity. This way you don't lose your previous state of the app.

Here is how you use these methods.

 @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
    }

EDIT : A Better Approach: The above approach toward maintaining your data isn't the best way to maintain data in production code/apps. Google IO 2017 introduced ViewModel to protect your data against configurational changes (like Screen Rotation). Keeping all data inside the activity using variables isn't a good software design and violates the Single Responsibility Principle hence separate your data storage using ViewModel from the activities.

  • ViewModel will be responsible for the data to be displayed.
  • Activity will be responsible for how to display the data.
  • Use additional repository class if you have an increasing complexity of storing the data.

That's just one of the way to separate classes and their responsibility, which will go a long way while making well-architectured apps.

于 2017-07-25T05:07:02.713 回答
5

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

    android:configChanges="keyboard|keyboardHidden|orientation"

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

于 2012-04-12T15:37:04.387 回答
4

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

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

于 2012-04-12T15:37:38.723 回答
2

Its solve my problem.

<activity android:name=".MyActivity"
      android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
      android:label="@string/app_name">
于 2021-03-14T05:53:22.937 回答
0

from the documentation:

Note: If your application targets Android 3.2 (API level 13) or higher, then you should also declare the "screenSize" and "screenLayout" configurations, because they might also change when a device switches between portrait and landscape orientations.

so what you shpuld write will be :

<android:configChanges="keyboardHidden|orientation|screenSize|screenLayout">
于 2019-12-09T17:32:18.187 回答