关于onConfigurationChanged以及onConfigurationChanged 未被调用的问题

关于onConfigurationChanged

通过查阅Android API可以得知android:onConfigurationChanged实际对应的是Activity里的onConfigurationChanged()方法。在AndroidManifest.xml中添加上诉代码的含义是表示在改变屏幕方向、弹出软件盘和隐藏软键盘时,不再去执行onCreate()方法,而是直接执行onConfigurationChanged()。如果不申明此段代码,按照Activity的生命周期,都会去执行一次onCreate()方法,而onCreate()方法通常会在显示之前做一些初始化工作。所以如果改变屏幕方向这样的操作都去执行onCreate()方法,就有可能造成重复的初始化,降低程序效率是必然的了,而且更有可能因为重复的初始化而导致数据的丢失。这是需要千万避免的。 

  为了明白这个问题,特意写了一个Demo用于观察执行结果。 

public class ConsoleActivity extends Activity {   
 private String str = "0";   
 protected void onCreate(Bundle savedInstanceState) {   
 super.onCreate(savedInstanceState);   
 //模拟数据初始化   
 str = "1";   
 Log.e("FHT", "onCreate:" + str);   
 }   
 @Override   
 protected void onStart() {   
 super.onStart();   
 //模拟显示之后,数据发生改变   
str = (new Date()).getTime() + "";   
 Log.e("FHT", "onStart:" + str);   
 }   
 @Override   
 public void onConfigurationChanged(Configuration newConfig) {   
 super.onConfigurationChanged(newConfig);   
 Log.e("FHT", "onConfigurationChanged:" + str);   
 }   
 }

运行结果如下:

  从上图可以看出,当屏幕方向发生了三次翻转,三次翻转都没有重新进入onCreate()方法,所以str的值得以延续,如果去除AndroidManifest.xml中关于onConfigurationChanged的相关代码,程序的执行顺序将发生变化,每次屏幕方向的变化都将引起str值的重置。这是大多数开发过程中所不希望看到的。

  另外需要注意的是onConfigurationChanged()方法中的:super.onConfigurationChanged(newConfig);一定不能省去,否则将引发:android.app.SuperNotCalledException 异常。

就如上次所说的,如果改变了系统屏幕的设置方向,我们不妨可以这么认为,它算是一个触发事件的开始吧,那么假使有人触发了这个事件,我们是否能够直接进行某些操作呢,如改变界面的UI等?当然不行,因为上面的范例,我们直接是借助setRequestedOrientation这个方法设置的,而在这个方法中无法实现其他的操作。

android中,我们借助的是另外一个事件——onConfigerationChanged,这个方法也是能够重写的。

示范代码功能很简单,就是在改变屏幕的方向的同时,也改变了点击按钮的text:

package com.mobile.allove.wfp;   
import android.app.Activity;   
import android.content.pm.ActivityInfo;   
import android.content.res.Configuration;   
import android.os.Bundle;   
import android.view.View;   
import android.view.View.OnClickListener;   
import android.widget.Button;   
public class onConfigurationChangedTest extends Activity implements OnClickListener{   
private Button mButton;   
int intCurrentOrientation;   
@Override   
public void onCreate(Bundle savedInstanceState) {   
super.onCreate(savedInstanceState);   
setContentView(R.layout.main);   
this.Init();   
mButton.setOnClickListener(this);   
}   
public void Init()   
{   
mButton=(Button) this.findViewById(R.id.Button01);   
intCurrentOrientation=this.getRequestedOrientation();   
}   
@Override   
public void onClick(View v) {   
// TODO Auto-generated method stub   
switch(v.getId())   
{   
case R.id.Button01:   
if(this.intCurrentOrientation==ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)   
{   
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);   
}      
else if(this.intCurrentOrientation==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)   
{   
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);   
}      
break;   
}   
}   
@Override   
public void setRequestedOrientation(int requestedOrientation) {   
// TODO Auto-generated method stub   
super.setRequestedOrientation(requestedOrientation);   
}   
@Override   
public int getRequestedOrientation() {   
// TODO Auto-generated method stub   
return super.getRequestedOrientation();   
}   
@Override   
public void onConfigurationChanged(Configuration newConfig) {   
// TODO Auto-generated method stub   
if(newConfig.orientation==Configuration.ORIENTATION_PORTRAIT)   
{      
mButton.setText("现在是竖屏");   
System.out.println("435435435456454");   
}   
if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE)   
{   
mButton.setText("现在是横屏");   
System.out.println("kjkjhugggtvg");   
}   
super.onConfigurationChanged(newConfig);   
}   
}

这里需要注意几点,就是首先要设置初始的Orientation,而且还要设置捕捉更改的权限—— Android.permission.CHANGE_CONFIGURATION,还有一点,就是必须在Activity里设置 configChanges属性。这里我们不妨理解为声明!!为了好理解,我也把AndroidManifest.xml文件贴在这里了

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>   
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mobile.allove.wfp" android:versionCode="1"
android:versionName="1.0">   
<application android:icon="@drawable/icon" android:label="@string/app_name">   
<activity android:name=".onConfigurationChangedTest"
android:label="@string/app_name" android:screenOrientation="portrait"
android:configChanges="orientation">   
<intent-filter>   
<action android:name="android.intent.action.MAIN" />   
<category android:name="android.intent.category.LAUNCHER" />   
</intent-filter>   
</activity>   
</application>   
<uses-sdk android:minSdkVersion="3" />   
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>   
</manifest>

onConfigurationChanged为何不被调用?

onConfigurationChanged 最近一直遇到一个很奇怪的问题。那就是我在AndroidManifest.xml的确设置了android:configChanges="orientation“,在我的Activity里也重写了onConfigurationChanged。但是同样的代码 在Android 4.0.3的手机里就不执行onConfigurationChanged。在Android 2.3里的手机执行一切正常。好几次去找原因,都因为自己不够耐心和仔细,而无功而退。直到今天决定慢悠悠地找,终于在这里找到了答案。

英文原文如下:

Caution: Beginning with Android 3.2 (API level 13), the "screen size" also changes when the device switches between portrait and landscape orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing for API level 13 or higher (as declared by the minSdkVersion and targetSdkVersion attributes), you must include the "screenSize" value in addition to the "orientation" value. That is, you must decalare android:configChanges="orientation|screenSize". However, if your application targets API level 12 or lower, then your activity always handles this configuration change itself (this configuration change does not restart your activity, even when running on an Android 3.2 or higher device).

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

TL;DR: add "|screenSize" to configChanges when targeting API level 13+

 

我的翻译:

自从Android 3.2(API 13),screen size也开始跟着设备的横竖切换而改变。所以,在AndroidManifest.xml里设置的MiniSdkVersion和TargetSdkVersion属性大于等于13的情况下,如果你想阻止程序在运行时重新加载Activity,除了设置”orientation“,你还必须设置"ScreenSize",就像这样子,android:configChanges="orientation|screenSize"。但是呢,如果你的Target API 级别小于13,你的Activity自己会自动处理这种ScreenSize的变化。如果你的TargetSdkVersion小于13,即使你在Android 3.2或者更高级别的机器上运行程序,它还是会自己去处理ScreenSize的。

更多请参考http://developer.android.com/guide/topics/resources/runtime-changes.html

我的备注:可能翻译的不好,反正意思就是,如果你的TargetSdk超过12,然后你想在安装了Android API level 超过12的设备上使用onConfigurationChanged,你就必须再对应的Activity里加上对应的screenSize。 一句话答案,把

android:configChanges="orientation" 改成android:configChanges="orientation|screenSize" 就OK了。

另外,StackOverFlow真是一个神奇的网站。