【问题标题】:Activity created twice活动创建了两次
【发布时间】:2017-10-21 14:16:04
【问题描述】:

我已设置锁定方向

并添加了带有 2 个简单类的示例代码,如下所示:

SplashLandscapeActivity.java

public class SplashLandscapeActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("start", "xxxx start Activity SplashLandscapeActivity");
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                startActivity(new Intent(SplashLandscapeActivity.this, TestActivity.class));
                finish();
            }
        }, 500);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("start", "xxxx onDestroy Activity SplashLandscapeActivity");
    }
}

TestActivity.java

public class TestActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("start", "xxxx start Activity TestActivity "
                + getResources().getConfiguration().orientation);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("start", "xxxx onDestroy Activity TestActivity "
                + getResources().getConfiguration().orientation);
    }
}

AndroidManifest.xml

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".SplashLandscapeActivity"
            android:theme="@style/SplashTheme"
            android:screenOrientation="landscape">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

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

        <activity
            android:name=".TestActivity"
            android:screenOrientation="portrait"/>
    </application>
</manifest>

当我使用new Handler().postDelayed (SplashLandscapeActivity.java) 启动TestActivity 时,它启动了两次,第一个具有Landscape 方向,然后切换回portrait。日志显示了一切:

xxxx 启动 Activity SplashLandscapeActivity

xxxx 启动 Activity TestActivity 2 //

xxxx onDestroy Activity TestActivity 1

xxxx 开始 Activity TestActivity 1 //

xxxx onDestroy Activity SplashLandscapeActivity

如果我删除 HandlerTestActivity 现在开始像正常的肖像。

xxxx 启动 Activity SplashLandscapeActivity

xxxx 开始活动 TestActivity 1

xxxx onDestroy Activity SplashLandscapeActivity

所以,我的问题是:

1- 此系统是否存在问题或其预期行为?为什么activity 被重新启动,即使screenOrientation 被设置为固定在Manifest 中?

2- 实际上,我的真实项目没有任何Handler,但与activity 启动两次(在以Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK 启动之后)存在相同的问题。我该如何处理这个问题?

【问题讨论】:

  • 您是否尝试过修改清单方向。就像同时保持纵向模式一样
  • 什么意思?我用它们来模拟我的问题。无论如何,我的预期是 activity 从未启动过两次。
  • 如果处理程序被删除并且您在设备处于锁定纵向时启动了应用程序,应用程序是否会像在到达TestActivity 之前那样旋转?还是直接纵向跳转到TestActivity而不旋转?我的猜测是,这可能是由于在活动已执行 onCreate 并且可能 onResume 执行之后调用了配置更改,并且如果没有发生配置更改,例如跳过 SplashLandscapeActivity 并直接启动 TestActivity 它不会被调用,因此它不会重新启动TestActivity
  • @ahasbini onConfigurationChanged 永远不会在 TestActivity 上调用,即使它已被系统重新启动(我猜的)。
  • 我可以给个提示,你可以从onCreate方法中检查onSaveInstanceState,第二次活动活动将有一些不同于null的东西。

标签: android screen-orientation activity-lifecycle


【解决方案1】:

在您的清单文件中,像这样编辑 TestActivity 块

<activity android:name=".TestActivity" android:launchMode="singleInstance" android:screenOrientation="portrait"/>

【讨论】:

    【解决方案2】:

    有 2 个 cmets 可以防止 TestActivity 启动两次。希望能帮到你

    1. 在 TestActivity 中使用 sensorPortrait 而不是 portrait。并且 TestActivity 不会启动两次,但它会旋转它以匹配用户持有设备的方式。
    2. android:configChanges="keyboardHidden|orientation|screenSize" 添加到Manifest.xml 中的TestAcitivty。它将调用public void onConfigurationChanged(Configuration newConfig) 而不是重新启动。

    我在 Android N 中没有发现这个问题。

    【讨论】:

    • 如果LandPort 的UI 不同,是否推荐setContentView 中的setContentView?另外,你能回答我why activity is restarted even the screenOrientation was set fixed in Manifest?
    • 我还没有找到任何官方文档来讨论为什么在screenOrientation和starter不一样的情况下activity会重启。但似乎由于启动器是纵向的,android 以纵向启动活动,并忽略当前的横向状态。原因似乎是为了预测你正在使用的状态。所以你必须在运行时处理这个问题。link
    • 不确定starter 或任何关系,因为没有handleractivity 的启动与manifest 配置完全相同。无论如何,谢谢你的时间,这个问题的主要思想不是关于How to fix...,而是关于why...
    【解决方案3】:

    更新您的manifest.xml

     <?xml version="1.0" encoding="utf-8"?>
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="com.example">
    
            <application
                android:allowBackup="true"
                android:icon="@mipmap/ic_launcher"
                android:label="@string/app_name"
                android:supportsRtl="true"
                android:theme="@style/AppTheme">
                <activity
                    android:name=".SplashLandscapeActivity"
                    android:theme="@style/SplashTheme"
                    android:screenOrientation="landscape"
                android:configChanges="keyboardHidden|orientation|screenSize">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN"/>
    
                        <category android:name="android.intent.category.LAUNCHER"/>
                    </intent-filter>
                </activity>
    
                <activity
                    android:name=".TestActivity"
                    android:screenOrientation="portrait"
    android:configChanges="keyboardHidden|orientation|screenSize"/>
            </application>
        </manifest>
    

    【讨论】:

    • 我不喜欢configChanges 选项,你的回答也没有集中在我的问题上。
    • 如果你不想要 configChanges 那么你应该使用这个 了解更多细节:@987654321 @
    【解决方案4】:

    我认为你需要添加标志

    android:configChanges="orientation|screenSize"
    

    到清单文件中的 TestActivity 如下所示:

    <activity
    android:name=".TestActivity"
    android:screenOrientation="portrait"
    android:configChanges="orientation|screenSize"
    />
    

    这应该可以解决您的问题。

    原因,为什么需要更改配置是: 现在关于为什么需要 configChanges,来自 android 文档:

    如果您的应用程序在特定期间不需要更新资源 配置更改并且您有一个性能限制 要求您避免活动重新启动,然后您可以声明 您的活动自己处理配置更改,从而防止 系统不会重新启动您的活动。

    访问android doc

    【讨论】:

    • 您的回答不能解决我的问题。见我的评论here
    • 你试过了吗。我得到了以下日志以及我建议的更改: D/start: xxxx start Activity TestActivity 1 D/start: xxxx onDestroy Activity SplashLandscapeActivity
    • 和我的其他 cmets 一样,您的回答并没有集中在我的问题上。为什么我已经设置了固定的screenOrientation,还需要设置configChanges选项?
    • 但这能解决问题吗?这是第一个担心。请参阅我的更新答案。
    • 不,用你的简单代码修复我的真实项目并不容易,它会导致很多副作用。我想在这里问我的问题,以找出问题的根本原因是Why do I need to set configChanges option while I already set fixed screenOrientation?
    【解决方案5】:

    可以将 MainActicity 更改为

    public class SplashLandscapeActivity extends AppCompatActivity {
        static boolean isRunStop = false;
        static int counter = 0;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
                counter++;
                Log.d("start", "xxxx run handler SplashLandscapeActivity. Time : "+counter);
                Toast.makeText(SplashLandscapeActivity.this, ""+counter, Toast.LENGTH_SHORT).show();
                new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    Log.d("start", "xxxx run handler SplashLandscapeActivity");
                    if(!isRunStop )
                    {
                          startActivity(new Intent(SplashLandscapeActivity.this, TestActivity.class));
                          isRunStop =true;
                          finish();
                    }
    
                }
            }, 500);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.d("start", "xxxx onDestroy Activity SplashLandscapeActivity");
        }
    }
    

    处理程序在另一个线程中调用,当您更改屏幕方向前一个处理程序消失并运行时,该线程不会消失。您可以有更多时间多次测试处理程序以更改屏幕方向。

    【讨论】:

    • 你的回答没有集中在我的问题上。另外,正如我所说,startActivity 只调用了 1 次,但TestActivity 启动了两次。
    • 记录Log.d("start", "xxxx run handler SplashLandscapeActivity");此代码运行两次。
    • 你的模拟器是哪个版本的?在我所有的模拟器上,Handler 只运行了 1 次。
    • 我的模拟器版本是23。为了测试,将增加时间从500改为5000并快速改变屏幕方向。
    • 感谢您的宝贵时间,但我不希望您尝试制作新案例。
    猜你喜欢
    • 2015-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    相关资源
    最近更新 更多