屏幕锁定时,Activity 返回到竖屏状态

3

相关问题:


我的Activity表现出一种奇怪的行为。

竖屏模式(正常)

  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会表现出这种行为?
  • 你的Activity是如何表现的?

我的问题的原始描述:

当我按下手机的锁屏按钮时,当我的Activity处于横屏模式时,我注意到(在我输出到Eclipse的调试信息中)Activity被重新创建为其竖屏模式(当然屏幕全黑)。然后当我再次按下锁屏按钮解锁屏幕时,Activity被销毁并重新创建为其竖屏模式。

据我记得(不确定),和我期望的一样,在横屏模式下锁定屏幕时,我的Activity只应该经历 onSaveInstanceState()onPause(),就像在竖屏模式下一样。而不是将Activity重新创建为竖屏模式,然后再返回到横屏模式。

是我在手机上弄错了什么吗?我该如何恢复正常?

谢谢!


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

总结大家目前的贡献,我得出以下结论:

1. 这是一种正常现象。

在移动设备上,运行在横屏模式下的Activities在屏幕锁定后会切换到纵向模式,这似乎是正常的行为。至少在目前测试的手机上是如此。因此,我们必须确保我们的生命周期函数始终可以优雅地处理这种变化。

2. 我们猜测这是由于锁定屏幕中的“默认方向”所导致的。

我们没有关于这个问题的文档或许多资源。但假设运行的Activities在屏幕锁定后切换回设备的“默认方向”,因为大多数设备的锁定屏幕都是纵向,这是相当合理的。

进一步研究:

我想知道如果我们有一个横向的锁定屏幕,Activities会怎样表现?


当屏幕锁定时,所有应用程序似乎都将被假定为具有默认方向。 - Hoan Nguyen
感谢@HoanNguyen的回复。您在设备上测试过吗?如果您能引用一些关于这个假设的参考资料,那就太完美了!非常感谢! - midnite
1
我在3部手机上进行了测试,其中一部是JB系统,另一部是ICS系统。我没有任何相关的参考资料。但是如果你仔细想想,当设备平放时,Android无法告诉你是横屏还是竖屏,因此它必须默认为设备的默认方向。现在,如果你锁定屏幕,然后将其平放,如果现在屏幕解锁但是平放的话,你该怎么办? - Hoan Nguyen
非常感谢@HoanNguyen的测试!因此,我们几乎可以得出结论,这是一个“特性”,而不是“奇怪的行为”(:我同意您对默认方向的需求。但是,在屏幕锁定时,我希望它保持先前的方向,或者使用传感器方向。(因此,对您的问题的答案将是:如果平放,则为先前的方向。)默认方向仅应在手机初始化(第一次打开)并且平放时使用。 - midnite
2个回答

2
您可以阻止活动在方向更改时重新启动,但这通常是一个非常糟糕的想法。
Android文档有一个处理运行时更改的部分,其中包含以下说明: 引用: 注意:自己处理配置更改可能会使使用替代资源变得更加困难,因为系统不会自动为您应用它们。只有在必须避免由于配置更改而重新启动时,才应考虑使用此技术,并且不建议大多数应用程序使用此技术。
Android通常仅建议您在不需要备用资源并且更重要的是具有性能要求的情况下抑制旋转时重新创建。在大多数情况下,设计良好的应用程序不需要这样做。
如果您坚持走抑制默认Android行为的道路,我会修改Raghunandan的代码并包括屏幕尺寸属性。从API级别13开始,屏幕大小会随方向更改而更改。因此,除非您仅针对API 12及以下版本进行定位,否则必须包括screenSize。
<activity android:name=".MyActivity"
      android:configChanges="orientation|screenSize"
      android:label="@string/app_name">

感谢您的回复。很抱歉我第一次没有表达清楚。也感谢您提供了android:configChanges的方法。 - midnite

0
为了避免活动重新启动
<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

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

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

在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;
        }          

  }

谢谢回复。所以你认为这是由于内存不足引起的?我想不是这个原因。我有很多内存,我只是在使用一个非常简单的Activity进行测试,在onCreate()中有一行代码System.out.println(getResources().getConfiguration().orientation + ":onCreate");。我不确定IntentFilterBroadcastReceiver是用来做什么的。你能解释一下吗?谢谢。 - midnite
我并不是默认这是一个需要考虑的情况。我们将会接收到屏幕锁定和解锁时发送的广播意图(系统级广播)。只需尝试通过重写onDestroy()、onPause()和onResume()方法向logcat中记录一些内容即可。你可以处理屏幕锁定和解锁。 - Raghunandan
你不想让你的活动重新启动吗? - Raghunandan
嗯...再次感谢。我知道并期望当屏幕被锁定时,Activity会暂停并在解锁后恢复。但是我注意到当我处于横屏模式时,Activity会完全重新创建!这正常吗?还有一个跟进的问题:这是否意味着使用您提供的代码,原始的onPause()和onResume()将不会在屏幕锁定和解锁时被调用,并且应该在这些if-else函数中实现代码? - midnite
感谢提供android:configChanges方法。但我认为当我们锁定屏幕时,Activity不应该重新启动。 - midnite
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接