Android 轮流重启 Activity

发布于 2024-09-28 10:50:41 字数 309 浏览 4 评论 0 原文

在我的 Android 应用程序中,当我旋转设备(滑出键盘)时,我的 Activity 将重新启动(onCreate 被调用)。现在,这可能是应该的样子,但我在 onCreate 方法中做了很多初始设置,所以我需要:

  1. 将所有初始设置放在另一个函数中,这样就不是全部了设备旋转时丢失或
  2. 使其不会再次调用 onCreate 并且布局仅调整或
  3. 将应用程序限制为仅纵向,以便不会调用 onCreate

In my Android application, when I rotate the device (slide out the keyboard) then my Activity is restarted (onCreate is called). Now, this is probably how it's supposed to be, but I do a lot of initial setting up in the onCreate method, so I need either:

  1. Put all the initial setting up in another function so it's not all lost on device rotation or
  2. Make it so onCreate is not called again and the layout just adjusts or
  3. Limit the app to just portrait so that onCreate is not called.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

水波映月 2024-10-05 10:50:41

使用应用程序类

根据您在初始化中所做的操作,您可以考虑创建一个扩展 Application 的新类,并将初始化代码移动到该类中重写的 onCreate 方法中班级。

Kotlin 版本

class MyApplicationClass: Application {
    @override fun onCreate() {
        super.onCreate()
        // Put your application initialization code here
    }
}

Java 版本

public class MyApplicationClass extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // Put your application initialization code here
    }
}

应用程序类中的 onCreate 仅在创建整个应用程序时调用,因此 Activity 在方向或键盘可见性更改时重新启动不会触发它。

最好将此类的实例公开为单例,并公开使用 getter 和 setter 初始化的应用程序变量。

注意:您需要在清单中指定新应用程序类的名称,以便注册和使用它:

<application
    android:name="com.you.yourapp.MyApplicationClass"

对配置更改做出反应

更新:自 API 13 起已弃用; 查看推荐的替代方案

作为进一步的替代方案,您可以让应用程序侦听会导致重新启动的事件(例如方向和键盘可见性更改),并在您的活动中处理它们。

首先将 android:configChanges 节点添加到 Activity 的清单节点:

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

或者对于 Android 3.2(API 级别 13)和更新的

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

然后在 Activity 中覆盖 onConfigurationChanged 方法并调用 setContentView 强制 GUI 布局在新方向上重新完成。

Kotlin 版本

@override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    setContentView(R.layout.myLayout)
}

Java 版本

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.myLayout);
}

Using the Application Class

Depending on what you're doing in your initialization you could consider creating a new class that extends Application and moving your initialization code into an overridden onCreate method within that class.

Kotlin version

class MyApplicationClass: Application {
    @override fun onCreate() {
        super.onCreate()
        // Put your application initialization code here
    }
}

Java version

public class MyApplicationClass extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // Put your application initialization code here
    }
}

The onCreate in the application class is only called when the entire application is created, so the Activity restarts on orientation or keyboard visibility changes won't trigger it.

It's good practice to expose the instance of this class as a singleton and exposing the application variables you're initializing using getters and setters.

NOTE: You'll need to specify the name of your new Application class in the manifest for it to be registered and used:

<application
    android:name="com.you.yourapp.MyApplicationClass"

Reacting to Configuration Changes

UPDATE: This is deprecated since API 13; see the recommended alternative

As a further alternative, you can have your application listen for events that would cause a restart – like orientation and keyboard visibility changes – and handle them within your Activity.

Start by adding the android:configChanges node to your Activity's manifest node:

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

Or for Android 3.2 (API level 13) and newer:

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

Then within the Activity override the onConfigurationChanged method and call setContentView to force the GUI layout to be re-done in the new orientation.

Kotlin version

@override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    setContentView(R.layout.myLayout)
}

Java version

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.myLayout);
}
千纸鹤带着心事 2024-10-05 10:50:41

Android 3.2 及更高版本的更新:

注意:从 Android 3.2(API 级别 13)开始,当设备在纵向和横向方向之间切换时,“屏幕尺寸”也会发生变化。因此,如果您想在针对 API 级别 13 或更高级别(如 minSdkVersion 和 targetSdkVersion 属性声明)进行开发时防止由于方向更改而导致运行时重新启动,除了“方向” 值。也就是说,您必须声明 android:configChanges="orientation|screenSize"。但是,如果您的应用程序面向 API 级别 12 或更低级别,则您的 Activity 始终会自行处理此配置更改(此配置更改不会重新启动您的 Activity,即使在 Android 3.2 或更高版本的设备上运行也是如此)。

来自 http ://web.archive.org/web/20120805085007/http://developer.android.com/guide/topics/resources/runtime-changes.html

Update for Android 3.2 and higher:

Caution: Beginning with Android 3.2 (API level 13), the "screen size" also changes when the device switches between portrait and landscape orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing for API level 13 or higher (as declared by the minSdkVersion and targetSdkVersion attributes), you must include the "screenSize" value in addition to the "orientation" value. That is, you must declare android:configChanges="orientation|screenSize". However, if your application targets API level 12 or lower, then your activity always handles this configuration change itself (this configuration change does not restart your activity, even when running on an Android 3.2 or higher device).

From http://web.archive.org/web/20120805085007/http://developer.android.com/guide/topics/resources/runtime-changes.html

农村范ル 2024-10-05 10:50:41

与其尝试完全阻止 onCreate() 被触发,不如尝试检查传递到事件中的 Bundle savedInstanceState 来查看是否它是否为空。

例如,如果我有一些逻辑应该在 Activity 真正创建时运行,而不是在每次方向更改时运行,那么我只在 onCreate() 中运行该逻辑如果 savedInstanceState 为 null。

否则,我仍然希望布局能够根据方向正确重绘。

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

不确定这是否是最终答案,但它对我有用。

Instead of trying to stop the onCreate() from being fired altogether, maybe try checking the Bundle savedInstanceState being passed into the event to see if it is null or not.

For instance, if I have some logic that should be run when the Activity is truly created, not on every orientation change, I only run that logic in the onCreate() only if the savedInstanceState is null.

Otherwise, I still want the layout to redraw properly for the orientation.

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

not sure if this is the ultimate answer, but it works for me.

预谋 2024-10-05 10:50:41

我做了什么......

在清单中的活动部分添加:

android:configChanges="keyboardHidden|orientation"

在活动的代码中,实现:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

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

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}

what I did...

in the manifest, to the activity section, added:

android:configChanges="keyboardHidden|orientation"

in the code for the activity, implemented:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

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

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}
锦爱 2024-10-05 10:50:41

您所描述的是默认行为。您必须自己检测和处理这些事件,方法是添加:

android:configChanges

到您的清单中,然后添加您想要处理的更改。因此,对于方向,您将使用:

android:configChanges="orientation"

对于打开或关闭的键盘,您将使用:

android:configChanges="keyboardHidden"

如果您想处理两者,您可以使用管道命令将它们分开,例如:

android:configChanges="keyboardHidden|orientation"

这将在您调用的任何 Activity 中触发 onConfigurationChanged 方法。如果您重写该方法,则可以传入新值。

希望这有帮助。

What you describe is the default behavior. You have to detect and handle these events yourself by adding:

android:configChanges

to your manifest and then the changes that you want to handle. So for orientation, you would use:

android:configChanges="orientation"

and for the keyboard being opened or closed you would use:

android:configChanges="keyboardHidden"

If you want to handle both you can just separate them with the pipe command like:

android:configChanges="keyboardHidden|orientation"

This will trigger the onConfigurationChanged method in whatever Activity you call. If you override the method you can pass in the new values.

Hope this helps.

琉璃梦幻 2024-10-05 10:50:41

我刚刚发现了这个知识:

为了通过方向变化保持 Activity 的活动状态,并通过 onConfigurationChanged 处理它,文档上面的代码示例在清单文件中建议了这一点:

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

它的额外好处是它始终有效。

额外的知识是,省略 keyboardHidden 可能看起来合乎逻辑,但它会导致模拟器失败(至少对于 Android 2.1):仅指定 orientation 将使模拟器调用两者有时 OnCreateonConfigurationChanged,其他时候仅 OnCreate

我还没有在设备上看到过失败,但我听说过其他设备上的模拟器失败。所以值得记录。

I just discovered this lore:

For keeping the Activity alive through an orientation change, and handling it through onConfigurationChanged, the documentation and the code sample above suggest this in the Manifest file:

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

which has the extra benefit that it always works.

The bonus lore is that omitting the keyboardHidden may seem logical, but it causes failures in the emulator (for Android 2.1 at least): specifying only orientation will make the emulator call both OnCreate and onConfigurationChanged sometimes, and only OnCreate other times.

I haven't seen the failure on a device, but I have heard about the emulator failing for others. So it's worth documenting.

人疚 2024-10-05 10:50:41

您还可以考虑使用 Android 平台在方向变化时保留数据的方式:onRetainNonConfigurationInstance()getLastNonConfigurationInstance()

这允许您在配置更改期间保留数据,例如您可能从服务器获取获取的信息或在 onCreate 或此后计算的其他内容,同时还允许 Android 重新布局您的 Activity 使用 xml 文件作为当前使用的方向。

请参阅此处此处

应该注意的是,这些方法现在已被弃用(尽管仍然比上面大多数解决方案建议的自己处理方向更改更灵活),建议每个人都切换到 Fragments 并改为使用 setRetainInstance (true) 在您想要保留的每个 Fragment 上。

You might also consider using the Android platform's way of persisting data across orientation changes: onRetainNonConfigurationInstance() and getLastNonConfigurationInstance().

This allows you to persist data across configuration changes, such as information you may have gotten from a server fetch or something else that's been computed in onCreate or since, while also allowing Android to re-layout your Activity using the xml file for the orientation now in use.

See here or here.

It should be noted that these methods are now deprecated (although still more flexible than handling orientation change yourself as most of the above solutions suggest) with the recommendation that everyone switch to Fragments and instead use setRetainInstance(true) on each Fragment you want to retain.

℉絮湮 2024-10-05 10:50:41

该方法很有用,但在使用 Fragment 时并不完整。

片段通常会在配置更改时重新创建。如果您不希望发生这种情况,请

在片段的构造函数中使用 setRetainInstance(true);

这将导致片段在配置更改期间被保留。

http://developer.android.com/reference/android /app/Fragment.html#setRetainInstance(boolean)

The approach is useful but is incomplete when using Fragments.

Fragments usually get recreated on configuration change. If you don't wish this to happen, use

setRetainInstance(true); in the Fragment's constructor(s)

This will cause fragments to be retained during configuration change.

http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)

◇流星雨 2024-10-05 10:50:41

我只是简单地在 AndroidManifest.xml 文件中添加:

android:configChanges="keyboard|keyboardHidden|orientation"

并且在我的活动中没有添加任何 onConfigurationChanged 方法。

所以每次键盘滑出或者什么反应都没有!另请查看此 关于此问题的文章

I just simply added:

android:configChanges="keyboard|keyboardHidden|orientation"

in the AndroidManifest.xml file and did not add any onConfigurationChanged method in my activity.

So every time the keyboard slides out or in nothing happens! Also checkout this article about this problem.

执手闯天涯 2024-10-05 10:50:41

即使你改变了android的orientationonCreate方法仍然会被调用。因此,将所有繁重的功能转移到此方法不会对您有帮助

The onCreate method is still called even when you change the orientation of android. So moving all the heavy functionality to this method is not going to help you

终遇你 2024-10-05 10:50:41

将以下代码放入 Manifest.xml 中的 标记内:

android:configChanges="screenLayout|screenSize|orientation"

Put the code below inside your <activity> tag in Manifest.xml:

android:configChanges="screenLayout|screenSize|orientation"
心的憧憬 2024-10-05 10:50:41

这非常简单,只需执行以下步骤:

<activity
    android:name=".Test"
    android:configChanges="orientation|screenSize"
    android:screenOrientation="landscape" >
</activity>

这对我有用:

注意:方向取决于您的要求

It is very simple just do the following steps:

<activity
    android:name=".Test"
    android:configChanges="orientation|screenSize"
    android:screenOrientation="landscape" >
</activity>

This works for me :

Note: orientation depends on your requitement

攒眉千度 2024-10-05 10:50:41
onConfigurationChanged is called when the screen rotates. 
(onCreate is no longer called when the screen rotates due to manifest, see:  
android:configChanges)

清单的哪一部分告诉它“不要调用 onCreate()”?

还,
Google 的文档表示避免使用 android:configChanges (除非作为最后的手段)。但他们建议所有的替代方法都使用 android:configChanges

根据我的经验,模拟器总是在旋转时调用 onCreate()
但我运行相同代码的 1-2 台设备...却没有。
(不知道为什么会有任何差异。)

onConfigurationChanged is called when the screen rotates. 
(onCreate is no longer called when the screen rotates due to manifest, see:  
android:configChanges)

What part of the manifest tells it "don't call onCreate()"?

Also,
Google's docs say to avoid using android:configChanges (except as a last resort). But then the alternative methods they suggest all DO use android:configChanges.

It has been my experience that the emulator ALWAYS calls onCreate() upon rotation.
But the 1-2 devices that I run the same code on... do not.
(Not sure why there would be any difference.)

可是我不能没有你 2024-10-05 10:50:41

在 Android 清单中进行的更改包括:

android:configChanges="keyboardHidden|orientation" 

在 Activity 中进行的添加包括:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

Changes to be made in the Android manifest are:

android:configChanges="keyboardHidden|orientation" 

Additions to be made inside activity are:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}
浪荡不羁 2024-10-05 10:50:41

将此行添加到您的清单中:-

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

并将此代码段添加到活动中:-

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

Add this line to your manifest :-

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

and this snippet to the activity :-

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
口干舌燥 2024-10-05 10:50:41

有多种方法可以实现此目的:

保存 Activity 状态

您可以在 onSaveInstanceState 中保存 Activity 状态。

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example: outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

然后使用bundle恢复状态。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

自己处理方向变化

另一种选择是自己处理方向变化。但这不被认为是一个好的做法。

将其添加到您的清单文件中。

android:configChanges="keyboardHidden|orientation"

对于 Android 3.2 及更高版本:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);
    
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portrait mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

限制旋转

您还可以将活动限制为纵向或横向模式以避免旋转。

将其添加到清单文件中的活动标记中:

        android:screenOrientation="portrait"

或者在您的活动中以编程方式实现此操作:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

There are several ways to do this:

Save Activity State

You can save the activity state in onSaveInstanceState.

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example: outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

and then use the bundle to restore the state.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

Handle orientation changes by yourself

Another alternative is to handle the orientation changes by yourself. But this is not considered a good practice.

Add this to your manifest file.

android:configChanges="keyboardHidden|orientation"

for Android 3.2 and later:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);
    
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portrait mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

Restrict rotation

You can also confine your activity to portrait or landscape mode to avoid rotation.

Add this to the activity tag in your manifest file:

        android:screenOrientation="portrait"

Or implement this programmatically in your activity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
一江春梦 2024-10-05 10:50:41

我发现执行此操作的方法是使用 onRestoreInstanceStateonSaveInstanceState 事件在 Bundle 中保存某些内容(即使您不需要任何内容​​)保存的变量,只需在其中放置一些内容,这样 Bundle 就不为空)。然后,在onCreate方法中检查Bundle是否为空,如果是,则进行初始化,如果不是,则进行初始化。

The way I have found to do this is use the onRestoreInstanceState and the onSaveInstanceState events to save something in the Bundle (even if you dont need any variables saved, just put something in there so the Bundle isn't empty). Then, on the onCreate method, check to see if the Bundle is empty, and if it is, then do the initialization, if not, then do it.

家住魔仙堡 2024-10-05 10:50:41

尽管这不是“Android 方式”,但我通过自己处理方向更改并简单地在视图中重新定位小部件以考虑更改后的方向,获得了非常好的结果。这比任何其他方法都要快,因为您不必保存和恢复视图。它还为用户提供了更无缝的体验,因为重新定位的小部件是完全相同的小部件,只是移动和/或调整了大小。不仅模型状态,而且视图状态都可以通过这种方式保存。

对于需要不时重新调整自身方向的视图来说,RelativeLayout 有时可能是一个不错的选择。您只需为每个子小部件提供一组纵向布局参数和一组横向布局参数,每个参数具有不同的相对定位规则。然后,在 onConfigurationChanged() 方法中,将相应的值传递给每个子项的 setLayoutParams() 调用。如果任何子控件本身需要内部重新定向,您只需调用该子控件的方法即可执行重新定向。该子控件同样会调用其任何需要内部重新定向的子控件上的方法,等等。

Even though it is not "the Android way" I have gotten very good results by handling orientation changes myself and simply repositioning the widgets within a view to take the altered orientation into account. This is faster than any other approach, because your views do not have to be saved and restored. It also provides a more seamless experience to the user, because the respositioned widgets are exactly the same widgets, just moved and/or resized. Not only model state, but also view state, can be preserved in this manner.

RelativeLayout can sometimes be a good choice for a view that has to reorient itself from time to time. You just provide a set of portrait layout params and a set of landscaped layout params, with different relative positioning rules on each, for each child widget. Then, in your onConfigurationChanged() method, you pass the appropriate one to a setLayoutParams() call on each child. If any child control itself needs to be internally reoriented, you just call a method on that child to perform the reorientation. That child similarly calls methods on any of its child controls that need internal reorientation, and so on.

一曲琵琶半遮面シ 2024-10-05 10:50:41

每次旋转屏幕时,打开的 Activity 就会完成,并再次调用 onCreate()。

1.您可以做一件事,在屏幕旋转时保存 Activity 的状态,以便在再次调用 Activity 的 onCreate() 时恢复所有旧内容。
请参阅链接

2 。如果您想防止重新启动活动,只需将以下行放入您的manifest.xml 文件中即可。

<activity android:name=".Youractivity"
    android:configChanges="orientation|screenSize"/>

Every time when the screen is rotated, opened activity is finished and onCreate() is called again.

1 . You can do one thing save the state of activity when the screen is rotated so that, You can recover all old stuff when the activity's onCreate() is called again.
Refer this link

2 . If you want to prevent restarting of the activity just place the following lines in your manifest.xml file.

<activity android:name=".Youractivity"
    android:configChanges="orientation|screenSize"/>
颜漓半夏 2024-10-05 10:50:41

您需要使用 onSavedInstanceState 方法将所有值存储到其参数 is has 中,该参数是一个包

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

,并用于

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

检索和设置值以查看对象
它将处理屏幕旋转

you need to use the onSavedInstanceState method to store all the values to its parameter is has which is a bundle

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

and use

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

to retrieve and set the value to view objects
it will handle the screen rotations

执妄 2024-10-05 10:50:41

注意:如果将来有人遇到与我相同的问题,我会发布此答案。对我来说,以下行还不够:

android:configChanges="orientation"

当我旋转屏幕时,没有调用方法`onConfigurationChanged(Configuration new config)。

解决方案:即使问题与方向有关,我也必须添加“screenSize”。因此,在 AndroidManifest.xml 文件中添加以下内容:

android:configChanges="keyboardHidden|orientation|screenSize"

然后实现方法 onConfigurationChanged(Configuration newConfig)

Note: I post this answer if someone in the future face the same problem as me. For me the following line wasn't enough:

android:configChanges="orientation"

When I rotated the screen, the method `onConfigurationChanged(Configuration new config) didn't get called.

Solution: I also had to add "screenSize" even if the problem had to do with the orientation. So in the AndroidManifest.xml - file, add this:

android:configChanges="keyboardHidden|orientation|screenSize"

Then implement the method onConfigurationChanged(Configuration newConfig)

夜未央樱花落 2024-10-05 10:50:41

manifest 的活动部分中,添加:

android:configChanges="keyboardHidden|orientation"

In the activity section of the manifest, add:

android:configChanges="keyboardHidden|orientation"
深海夜未眠 2024-10-05 10:50:41

人们说你应该使用

android:configChanges="keyboardHidden|orientation"

但是在 Android 中处理旋转的最好、最专业的方法是使用 Loader 类。它不是一个著名的类(我不知道为什么),但它比 AsyncTask 好得多。有关更多信息,您可以阅读 Udacity 的 Android 课程中的 Android 教程。

当然,作为另一种方式,您可以使用 onSaveInstanceState 存储值或视图,并使用 onRestoreInstanceState 读取它们。这真的取决于你。

People are saying that you should use

android:configChanges="keyboardHidden|orientation"

But the best and most professional way to handle rotation in Android is to use the Loader class. It's not a famous class(I don't know why), but it is way better than the AsyncTask. For more information, you can read the Android tutorials found in Udacity's Android courses.

Of course, as another way, you could store the values or the views with onSaveInstanceState and read them with onRestoreInstanceState. It's up to you really.

放赐 2024-10-05 10:50:41

在清单中添加此行: android:configChanges="orientation|screenSize"

Add this line in manifest : android:configChanges="orientation|screenSize"

王权女流氓 2024-10-05 10:50:41

谷歌推出的 Android 架构最好的组件之一将满足 ViewModel 的所有要求。

它旨在以生命周期的方式存储和管理与 UI 相关的数据,并且允许数据在屏幕旋转时继续存在。

class MyViewModel : ViewModel() {

请参阅:https://developer.android.com/topic/libraries/architecture/viewmodel

One of the best components of android architecture introduced by google will fulfill all the requirements that are ViewModel.

That is designed to store and manage UI-related data in a lifecycle way plus that will allow data to survive as the screen rotates

class MyViewModel : ViewModel() {

Please refer to this: https://developer.android.com/topic/libraries/architecture/viewmodel

感受沵的脚步 2024-10-05 10:50:41

经过一段时间的尝试和错误,我找到了一个在大多数情况下都能满足我的需求的解决方案。这是代码:

清单配置:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

MainAttivity:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume  " + "");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause  " + "");
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy  " + "");
    }


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

和样本片段:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

可以在github

After a while of trial and error, I found a solution which fits my needs in the most situations. Here is the Code:

Manifest configuration:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

MainActivity:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume  " + "");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause  " + "");
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy  " + "");
    }


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

And sample Fragment:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

Can be found on github.

随遇而安 2024-10-05 10:50:41

使用orientation监听器在不同的方向上执行不同的任务。

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}

Use orientation listener to perform different tasks on different orientation.

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}
溺深海 2024-10-05 10:50:41

将以下代码放入 Android ManifestActivity 中。

android:configChanges="orientation"

当您改变方向时,这不会重新启动您的活动。

Put this below code in your Activity in Android Manifest.

android:configChanges="orientation"

This will not restart your activity when you would change orientation.

烛影斜 2024-10-05 10:50:41

修复屏幕方向(横向或纵向)

AndroidManifest.xml android:screenOrientation="portrait"android:screenOrientation="landscape"

中 您的 onResume() 方法不会被调用。

Fix the screen orientation (landscape or portrait) in AndroidManifest.xml

android:screenOrientation="portrait" or android:screenOrientation="landscape"

for this your onResume() method is not called.

呆萌少年 2024-10-05 10:50:41

您可以在活动中使用 ViewModel 对象。

ViewModel 对象在配置更改期间会自动保留,以便它们保存的数据可立即可供下一个活动或片段实例使用。
阅读更多:
https://developer.android.com/topic/libraries/architecture/viewmodel

You may use the ViewModel object in your activity.

ViewModel objects are automatically retained during configuration changes so that the data they hold is immediately available to the next activity or fragment instance.
Read more:
https://developer.android.com/topic/libraries/architecture/viewmodel

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文