關於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真是一個神奇的網站。

發佈了21 篇原創文章 · 獲贊 12 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章