【问题标题】:Activity return to Portrait when Screen is Locked屏幕锁定时活动返回纵向
【发布时间】:2013-03-26 19:20:27
【问题描述】:

相关问题:


这是我在活动中遇到的奇怪行为。

人像模式(正常)

  1. 按锁屏,Activity: onPause();
  2. 解锁屏幕,Activity: onResume()

横向模式(很奇怪)

  1. 按下屏幕锁定,Activity: onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onResume() 加载纵向布局;
  2. 解锁屏幕Activity: onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onResume() 并加载横向布局。

我的期望是:

人像模式:(相同)

横向模式:(应该像纵向模式)

  1. 按锁屏,Activity: onPause();
  2. 解锁屏幕,Activity: onResume()

所以我的问题:

  • 为什么我的活动会这样?
  • 您的活动表现如何?

我的问题的原文描述:

当我按下手机的锁定屏幕按钮时,当我的 Activity 处于横向模式时,我注意到(在我输出到 Eclipse 的调试消息中)Activity 被重新创建为纵向模式(而屏幕是当然,全黑)。然后当我再次按下 Lock Screen 按钮解锁屏幕时,Activity 被销毁并重新创建为它的 Portrait。

我记得(虽然不是 100% 肯定),而且我期望的是,我的 Activity 应该只经历 onSaveInstanceState()onPause(),而在横向模式下锁定屏幕,就像在纵向模式下一样。而不是将 Activity 重新创建为 Portrait 并再次返回 Landscape。

是不是我的手机搞砸了?怎样才能恢复正常?

谢谢!


感谢大家对此问题的贡献。特别感谢@HoanNguyen 在他的设备中为我进行的测试。特别感谢@Raghunandan 与我就这个问题进行了深入讨论。

总结到目前为止大家的贡献,我有以下结论:

1。这是正常现象。

看来,在手机上,处于横向模式的正在运行的活动在屏幕锁定时切换到纵向模式是正常行为。至少到目前为止,在经过测试的手机上是这样。因此,我们必须确保我们的生命周期函数能够始终优雅地处理这种变化。

2。猜猜这是因为锁定屏幕中的“默认方向”。

我们没有关于这个问题的文档或很多资源。但是假设正在运行的活动在屏幕锁定时切换回设备的“默认方向”,就像在大多数设备中锁定的屏幕是纵向的一样,这是非常合乎逻辑的。

进一步研究:

我只是想知道如果我们有一个横向锁定屏幕,活动会如何表现?

【问题讨论】:

  • 当屏幕锁定时,似乎所有的应用程序都会被假定为默认方向,
  • 感谢@HoanNguyen 的回复。你在你的设备上测试过吗?如果你能引用一些关于这个假设的参考资料,那将是完美的!非常感谢!
  • 我在 3 部手机上进行了测试,一部带有 JB,另一部带有 ICS。我没有关于此的任何参考资料。但是如果你想一想,当设备是平板时,android 将无法告诉你什么是纵向或横向,因此它必须默认为设备默认方向。现在如果你锁定屏幕那么你可以把它平放,如果现在屏幕解锁但是平放你怎么办?
  • 非常感谢@HoanNguyen 的测试!所以我们几乎可以得出结论,这是一个“功能”而不是“奇怪的行为”(:我同意你的观点,需要默认方向。但是在屏幕锁定时,我希望它保持以前的方向,使用传感器方向。(所以回答你的问题是:以前的方向,如果平坦。)默认方向应该只在手机初始化时使用(第一时间打开)和 i> 平放。

标签: android android-activity android-lifecycle android-orientation lockscreen


【解决方案1】:

您可以阻止活动在方向更改时重新启动,但这通常是一个非常糟糕的主意。

Android 文档有a section on handling runtime changes with this note:

注意:自己处理配置更改会使使用替代资源变得更加困难,因为系统不会自动为您应用它们。当您必须避免因配置更改而重新启动并且不建议用于大多数应用程序时,应将此技术视为最后的手段。

Android 通常只建议您在不需要备用资源并且(更重要的是,有性能要求)时禁止循环重新创建。在大多数情况下,设计良好的应用不需要这样做。

如果您坚持采用抑制默认 Android 行为的方式,我会修改 Raghunandan 的代码并添加屏幕尺寸属性。从 API 级别 13 开始,屏幕尺寸会随着方向的变化而变化。因此,除非您只针对 API 12 及以下版本,否则您必须包含 screenSize。

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

【讨论】:

  • 感谢您的回复。抱歉,我一开始没有让自己足够清楚。也感谢您提供android:configChanges 方法。
【解决方案2】:

为了避免活动重新启动

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

http://developer.android.com/guide/topics/resources/runtime-changes.html.

在正常情况下,当您的屏幕锁定时,您的活动会暂停,当屏幕解锁时,活动会恢复。

锁屏时的问题是:当前的Activity如果发现内存不足可能会被系统强行停止,而不是把Activity移到后台。在这种情况下,我们应该保存(所有必要的数据)Activity 的当前状态。

在 onSaveInstanceState() 中保存数据并在 onRestoreInstanceState() 中恢复数据。

@Override
 public void  onSaveInstanceState(Bundle outState)
 {
  Log.v("$````$", "In Method: onSaveInstanceState()");
  //if necessary,set a flag to check whether we have to restore or not
  //handle necessary savings…
 }

@Override
public void onRestoreInstanceState(Bundle inState)
{
  Log.v("$````$", "In Method: onRestoreInstanceState()");
  //if any saved state, restore from it…
}

在你的 onCreate() 中

IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);

mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter); //register


public class ScreenReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent)
   {
        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
        {    
              Log.v("$$$$$$", "In Method:  ACTION_SCREEN_OFF");
              // onPause() will be called.
        }
        else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
        {
              Log.v("$$$$$$", "In Method:  ACTION_SCREEN_ON");
              //onResume() will be called.
              //Better check for whether the screen was already locked
              // if locked, do not take any resuming action in onResume()
              //Suggest you, not to take any resuming action here.       
        }
        else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT))
        {
              Log.v("$$$$$$", "In Method:  ACTION_USER_PRESENT"); 
              //Handle resuming events
        }
  }

在你的 onDestroy 中

  @Override
  public void onDestroy()
  {
        super.onDestroy();
        Log.v("$$$$$$", "In Method: onDestroy()");

        if (mReceiver != null)
        {
              unregisterReceiver(mReceiver); //unregister 
              mReceiver = null;
        }          

  }

【讨论】:

  • 感谢您的回复。所以你假设这是由内存不足引起的?我猜不会。我有足够的内存,我只是在onCreate() 中用一行System.out.println(getResources().getConfiguration().orientation + ":onCreate"); 测试一个非常简单的活动。我不确定IntentFilterBroadcastReceiver。你能解释一下它们的用途吗?谢谢。
  • 我不认为这是一个需要考虑的案例。我们将收到屏幕锁定和解锁的广播意图。(系统范围广播)。只需尝试通过覆盖 onDestory() onPause() 和 onResume() 将某些内容记录到 logcat。您可以处理屏幕锁定和解锁。
  • 你的活动没有重启吗??
  • 嗯...再次感谢。我知道并且我希望屏幕锁定时,活动会暂停并在解锁后恢复。但我注意到当我处于横向模式时,Activity 完全重新创建!这是正常的吗?还有一个后续问题:这是否意味着您提供的代码,在屏幕锁定和解锁时不会调用原始的onPause()和onResume(),而是在那些if-else函数中实现代码?
  • 感谢您提供android:configChanges 方法。但我只是认为,当我们锁定屏幕时,Activity 应该重新启动。
猜你喜欢
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-20
  • 2021-04-01
相关资源
最近更新 更多