Android 方向更改调用 onCreate

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3097909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:41:13  来源:igfitidea点击:

Android orientation change calls onCreate

androidandroid-activityandroid-orientation

提问by Samah

I've made a search screen that has one tab for keywords, filters, and a search button, and three optional tabs for the different types of results (each containing a ListViewwith an ArrayAdapter). When starting the activity, the developer can optionally pass in the results as an extra Parcelable[]if the search has already been performed. In the onCreate()method I'm creating each of the three tabs for the Parcelable[]passed through.

我制作了一个搜索屏幕,其中有一个用于关键字、过滤器和搜索按钮的选项卡,以及三个用于不同类型结果的可选选项卡(每个选项卡都包含一个ListViewArrayAdapter)。启动 Activity 时,Parcelable[]如果已经执行了搜索,开发人员可以选择将结果作为附加项传递。在该onCreate()方法中,我正在为Parcelable[]传递的三个选项卡中的每一个创建选项卡。

When I call a search from the button on the filter tab, I clear the tabs and recreate them with the new results, which works perfectly. The problem is that when you rotate the device, it appears that Android's automatic orientation switching support recreates the entire activity, calling onCreate(). This means that my search results are reset to the Parcelable[]passed through when starting the activity.

当我从过滤器选项卡上的按钮调用搜索时,我清除了选项卡并使用新结果重新创建它们,这非常有效。问题在于,当您旋转设备时,Android 的自动方向切换支持似乎会重新创建整个 Activity,调用onCreate(). 这意味着我的搜索结果Parcelable[]在开始活动时被重置为通过。

The only solution I've had so far is to call finish()then startActivity()to essentially restart the activity with the new results. I'm sure there must be a much simpler solution and that I've done something extremely noobish.

到目前为止,我唯一的解决方案是调用finish()thenstartActivity()基本上用新结果重新启动活动。我相信一定有一个更简单的解决方案,而且我做了一些非常菜鸟的事情。

Is there a better way to do this?

有一个更好的方法吗?

回答by Fedor

Of cource there is. Just add configChanges attribute to your AndroidManifest.xml, like that:

当然有。只需将 configChanges 属性添加到您的 AndroidManifest.xml 中,如下所示:

<activity android:name=".MyActivity" 
          android:configChanges="orientation|keyboardHidden" /> 

Activity restart on rotation AndroidHow do I disable orientation change on Android?http://developer.android.com/guide/topics/manifest/activity-element.html#config

Activity 在旋转时重新启动 Android如何在 Android 上禁用方向更改?http://developer.android.com/guide/topics/manifest/activity-element.html#config

回答by Pratik Butani

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 onConfigurationChangedmethod in whatever Activityyou call. If you override the method you can pass in the new values.

onConfigurationChanged无论Activity您调用什么,这都会触发该方法。如果覆盖该方法,则可以传入新值。

Hope this helps.

希望这可以帮助。

回答by lucidbrot

One option is using android:configChanges="orientation"to tell android that you want to handle the configuration changes yourself instead of having it recreate the Activity. However, this is discouraged:

一种选择是使用android:configChanges="orientation"告诉 android 您要自己处理配置更改,而不是让它重新创建 Activity。但是,这是不鼓励的:

When a configuration change occurs at runtime, the activity is shut down and restarted by default, but declaring a configuration with this attribute will prevent the activity from being restarted. Instead, the activity remains running and its onConfigurationChanged() method is called. Note: Using this attribute should be avoided and used only as a last resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change. ( Source)

当运行时发生配置更改时,活动默认关闭并重新启动,但使用此属性声明配置将阻止活动重新启动。相反,活动保持运行并调用其 onConfigurationChanged() 方法。注意:应避免使用此属性,并且仅将其用作最后的手段。请阅读处理运行时更改以获取有关如何正确处理由于配置更改而重新启动的更多信息。(来源

There is a different way to retain an object during a configuration change: The ViewModelcan be used to define a wrapper class for your data. Each instance of the Activity seems to have its own set of ViewModels, accessible through

在配置更改期间保留对象有一种不同的方法:ViewModel可用于为您的数据定义包装类。Activity 的每个实例似乎都有自己的一组 ViewModel,可以通过

MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);

and if you use LiveDatawithin it, you can subscribe to data changes as outlined in the documentation. Here is their example just in case the link dies at some point:

如果您LiveData在其中使用,您可以订阅文档中概述的数据更改。这是他们的示例,以防链接在某些时候失效:

Architecture Components provides ViewModel helper class for the UI controller that is responsible for preparing data for the UI. ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel, instead of an activity or fragment, as illustrated by the following sample code:

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    } } You can then access the list from an activity as follows:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    } }

If the activity is re-created, it receives the same MyViewModel instance that was created by the first activity. When the owner activity is finished, the framework calls the ViewModel objects's onCleared() method so that it can clean up resources.

架构组件为负责为 UI 准备数据的 UI 控制器提供 ViewModel 帮助程序类。ViewModel 对象在配置更改期间会自动保留,以便它们保存的数据可立即用于下一个活动或片段实例。例如,如果您需要在应用中显示用户列表,请确保将获取和保存用户列表的责任分配给 ViewModel,而不是 Activity 或 Fragment,如以下示例代码所示:

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    } } You can then access the list from an activity as follows:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    } }

如果重新创建该活动,它会收到与第一个活动创建的相同的 MyViewModel 实例。当所有者活动完成时,框架调用 ViewModel 对象的 onCleared() 方法,以便它可以清理资源。