活动创建了两次
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
如果我删除 Handler
,TestActivity
现在开始像正常的肖像。
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 中没有发现这个问题。
【讨论】:
如果Land
和Port
的UI 不同,是否推荐setContentView
中的setContentView
?另外,你能回答我why activity is restarted even the screenOrientation was set fixed in Manifest?
我还没有找到任何官方文档来讨论为什么在screenOrientation和starter不一样的情况下activity会重启。但似乎由于启动器是纵向的,android 以纵向启动活动,并忽略当前的横向状态。原因似乎是为了预测你正在使用的状态。所以你必须在运行时处理这个问题。link
不确定starter
或任何关系,因为没有handler
,activity
的启动与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并快速改变屏幕方向。
感谢您的宝贵时间,但我不希望您尝试制作新案例。以上是关于活动创建了两次的主要内容,如果未能解决你的问题,请参考以下文章