活动创建了两次

Posted

技术标签:

【中文标题】活动创建了两次【英文标题】: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的东西。 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

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

    在 TestActivity 中使用 sensorPortrait 而不是 portrait。并且 TestActivity 不会启动两次,但它会旋转它以匹配用户持有设备的方式。 将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并快速改变屏幕方向。 感谢您的宝贵时间,但我不希望您尝试制作新案例。

以上是关于活动创建了两次的主要内容,如果未能解决你的问题,请参考以下文章

Android Fragment 创建了两次方向更改

Android片段生命周期:onResume调用了两次

NuxtJS 页面被创建了两次

在 iOS7 上,applicationDidEnterBackground 被调用了两次

为啥我的对象似乎被创建了两次?

自定义 UITableViewCell 创建了两次......让我发疯