?之前在學(xué)習(xí)Fragment和總結(jié)Android異步操作的時(shí)候會(huì)在很多blog中看到對(duì)Configuration Change的討論,以前做的項(xiàng)目都是固定豎屏的,所以對(duì)橫豎屏切換以及橫豎屏切換對(duì)程序有什么影響都沒(méi)什么了解。見(jiàn)到的次數(shù)多了,總是掠過(guò)去心理總覺(jué)得不踏實(shí),最終還是好好看了些介紹Congifuration Change的blog,在此做個(gè)梳理也不枉花了那么多時(shí)間。有疏漏和描述不準(zhǔn)確的地方懇請(qǐng)指正。
?
前言 在研究Configuration Change之前我主要的疑問(wèn):
?
橫豎屏切換對(duì)布局有影響嗎,要做什么處理嗎? 屏幕旋轉(zhuǎn)的話為什么要保存數(shù)據(jù)? 啟動(dòng)一個(gè)線程(worker thread或者AsyncTask)來(lái)跑一個(gè)耗時(shí)任務(wù),此時(shí)旋轉(zhuǎn)屏幕會(huì)對(duì)線程有什么影響嗎? 異步操作過(guò)程會(huì)顯示進(jìn)度對(duì)話框,旋轉(zhuǎn)屏幕造成程序終止的原因及解決方法? 在AndroidManifest.xml中通過(guò)配置android:configuration的方法來(lái)防止Activity被銷毀并重建為什么不被推薦,這種方法有哪些缺點(diǎn)? 推薦使用Fragment的setRetainInstance(true)來(lái)處理配置變化時(shí)保存對(duì)象,具體怎么實(shí)現(xiàn)? ?
屏幕方向是設(shè)備配置的一個(gè)屬性,屏幕旋轉(zhuǎn)是影響配置變化的因素之一,在項(xiàng)目中最常見(jiàn)。在對(duì)Configuration Change有個(gè)全面認(rèn)識(shí)后,這些問(wèn)題都會(huì)迎刃而解。
?
由一道網(wǎng)上總結(jié)的Android測(cè)試題引發(fā)的測(cè)試 對(duì)Configuration Change的第一印象還是看網(wǎng)上總結(jié)的Andorid面試題里有問(wèn)到:
問(wèn)題:橫豎屏切換時(shí)Activity的生命周期?
答案:
1、不設(shè)置Activity的android:configChanges時(shí),切屏?xí)匦抡{(diào)用各個(gè)生命周期,切橫屏?xí)r會(huì)執(zhí)行一次,切豎屏?xí)r會(huì)執(zhí)行兩次
2、設(shè)置Activity的android:configChanges=”orientation”時(shí),切屏還是會(huì)重新調(diào)用各個(gè)生命周期,切橫、豎屏?xí)r只會(huì)執(zhí)行一次
3、設(shè)置Activity的android:configChanges=”orientation|keyboardHidden”時(shí),切屏不會(huì)重新調(diào)用各個(gè)生命周期,只會(huì)執(zhí)行onConfigurationChanged方法
但是經(jīng)過(guò)測(cè)試后結(jié)果表明并不都和‘答案’一致:
測(cè)試環(huán)境:在HTC t329d 4.1和模擬器2.2.3上的測(cè)試結(jié)果:
1、和答案中的第1點(diǎn)不一致。不設(shè)置Activity的android:configChanges時(shí),不管切橫屏還是切豎屏,都只會(huì)重新調(diào)用生命周期一次。
2、和‘答案’中第2點(diǎn)一致
3、和答案中的第3點(diǎn)不一致。設(shè)置Activity的android:configChanges=”orientation|keyboardHidden”時(shí),在Android 3.2(API Level 13)之前,切屏還是會(huì)重新調(diào)用各個(gè)生命周期,不會(huì)執(zhí)行onConfigurationChanged()方法。在Android 3.2之后必須在configChanges中添加screenSize才不會(huì)在切屏?xí)r重新調(diào)用各個(gè)生命周期。并執(zhí)行onConfigurationChanged()方法。另:android:targetSdkVersion的設(shè)置會(huì)影響Activity生命周期的創(chuàng)建,自行測(cè)試。
從測(cè)試結(jié)果和‘答案’的不一致告訴me,對(duì)于所謂的'答案'最好親測(cè)比較靠譜,而且對(duì)于給答案的人最好指明下測(cè)試環(huán)境,否則測(cè)試結(jié)果不同也無(wú)處對(duì)照。全面透徹盡可能多地去覆蓋有關(guān)Configuration Change的知識(shí)。其實(shí)對(duì)于第一點(diǎn),切橫屏還是豎屏導(dǎo)致Activity重建的次數(shù)并不重要,重要的是它被重建了以及重建會(huì)引發(fā)什么問(wèn)題。
?
Configuration Change概述 Configuration?這個(gè)類描述了設(shè)備的所有配置信息,這些配置信息會(huì)影響到應(yīng)用程序檢索的資源。包括了用戶指定的選項(xiàng)(locale和scaling)也包括設(shè)備本身配置(例如input modes,screen size ?and ?screen orientation).可以在該類里查看所有影響Configuration Change 的屬性。
橫豎屏切換是我們最常見(jiàn)的影響配置變化的因素,還有很多其他影響配置的因素有語(yǔ)言的更改(例如中英文切換)、鍵盤(pán)的可用性(這個(gè)沒(méi)理解)等
?
常見(jiàn)的引發(fā)Configuration Change的屬性:
?
橫豎屏切換:android:configChanges="orientation"
?
鍵盤(pán)可用性:android:configChanges="keyboardHidden"
?
屏幕大小變化:android:configChanges="screenSize"
?
語(yǔ)言的更改:android:configChanges="locale"
?
在程序運(yùn)行時(shí),如果發(fā)生Configuration Change會(huì)導(dǎo)致當(dāng)前的Activity被銷毀并重新創(chuàng)建,即先調(diào)用onDestroy緊接著調(diào)用onCreate()方法。重建的目的是為了讓?xiě)?yīng)用程序通過(guò)自動(dòng)加載可替代資源來(lái)適應(yīng)新的配置。
?
?
Configuration Change引發(fā)的問(wèn)題 ?
當(dāng)程序運(yùn)行時(shí),設(shè)備配置的改變會(huì)導(dǎo)致當(dāng)前Activity被銷毀并重新創(chuàng)建。
在Activity被銷毀之前我們需要保存當(dāng)前的數(shù)據(jù)以防Activity重建后數(shù)據(jù)丟失。例如界面中用戶選擇了checkbox和radiobutton選項(xiàng)或者通過(guò)網(wǎng)絡(luò)請(qǐng)求顯示在界面上的數(shù)據(jù)在屏幕旋轉(zhuǎn)后Activity被destroy-recreate,這些控件上被選擇的狀態(tài)和界面上的數(shù)據(jù)都會(huì)消失。
再比如當(dāng)進(jìn)入某個(gè)Activity時(shí)加載頁(yè)面進(jìn)行網(wǎng)絡(luò)請(qǐng)求,此時(shí)旋轉(zhuǎn)屏幕會(huì)重新創(chuàng)建網(wǎng)絡(luò)連接請(qǐng)求,這樣的用戶體驗(yàn)非常不好。而且常見(jiàn)的一個(gè)問(wèn)題是如果伴隨異步操作顯示一個(gè)progressDialog的話,異步任務(wù)未完成去旋轉(zhuǎn)屏幕,程序會(huì)因?yàn)锳ctivity has leaked window 而終止。而當(dāng)old Activity被銷毀后,線程執(zhí)行完畢后還是會(huì)把結(jié)果返回給old Activity而非新的Activity,而且新的Activity如果又觸發(fā)了后臺(tái)任務(wù)(在onCreate()中會(huì)啟動(dòng)線程),就又會(huì)去啟動(dòng)一個(gè)子線程,消耗可用的資源。
?
? ? ? ?下面通過(guò)一個(gè)例子來(lái)看看橫豎屏切換引發(fā)的以上問(wèn)題:
?
異步操作結(jié)束后旋轉(zhuǎn)屏幕,界面數(shù)據(jù)丟失 顯示進(jìn)度對(duì)話框的異步操作,未結(jié)束時(shí)旋轉(zhuǎn)屏幕,程序終止 ?
該示例,通過(guò)點(diǎn)擊屏幕按鈕啟動(dòng)一個(gè)異步操作(模擬執(zhí)行耗時(shí)任務(wù)),同時(shí)顯示一個(gè)進(jìn)度對(duì)話框。當(dāng)異步操作執(zhí)行完畢后更新界 面,并取消進(jìn)度對(duì)話框。在本節(jié)最后可查看代碼。
? ? ? ? 1. 異步操作結(jié)束后旋轉(zhuǎn)屏幕,界面數(shù)據(jù)丟失
2. 異步操作未結(jié)束旋轉(zhuǎn)屏幕,程序終止
log打印出的錯(cuò)誤信息:
?
[plain] ?view plaincopy
04-14?21:34:10.192??26254-26254/com.aliao.myandroiddemo?E/WindowManager﹕?Activity?com.aliao.myandroiddemo.view.handler.TestHandlerActivity?has?leaked?window?com.android.internal.policy.impl.PhoneWindow$DecorView@4208a548?that?was?originally?added?here?? ????android.view.WindowLeaked:?Activity?com.aliao.myandroiddemo.view.handler.TestHandlerActivity?has?leaked?window?com.android.internal.policy.impl.PhoneWindow$DecorView@4208a548?that?was?originally?added?here?? ????????????at?android.view.ViewRootImpl.<init>(ViewRootImpl.java:415)?? ????????????at?android.view.WindowManagerImpl.addView(WindowManagerImpl.java:322)?? ????????????at?android.view.WindowManagerImpl.addView(WindowManagerImpl.java:234)?? ????????????at?android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:153)?? ????????????at?android.view.Window$LocalWindowManager.addView(Window.java:557)?? ????????????at?android.app.Dialog.show(Dialog.java:277)?? ????????????at?android.app.ProgressDialog.show(ProgressDialog.java:116)?? ????????????at?android.app.ProgressDialog.show(ProgressDialog.java:104)?? ????????????at?com.aliao.myandroiddemo.view.handler.TestHandlerActivity.excuteLongTimeOperation(TestHandlerActivity.java:60)?? ????????????at?com.aliao.myandroiddemo.view.handler.TestHandlerActivity.onClick(TestHandlerActivity.java:51)?? ????????????at?android.view.View.performClick(View.java:4191)?? ????????????at?android.view.View$PerformClick.run(View.java:17229)?? ????????????at?android.os.Handler.handleCallback(Handler.java:615)?? ????????????at?android.os.Handler.dispatchMessage(Handler.java:92)?? ????????????at?android.os.Looper.loop(Looper.java:137)?? ????????????at?android.app.ActivityThread.main(ActivityThread.java:4963)?? ????????????at?java.lang.reflect.Method.invokeNative(Native?Method)?? ????????????at?java.lang.reflect.Method.invoke(Method.java:511)?? ????????????at?com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)?? ????????????at?com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)?? ????????????at?dalvik.system.NativeStart.main(Native?Method)?? 04-14?21:34:11.692??????483-635/??E/Watchdog﹕?!@Sync?3825?? 04-14?21:34:12.192??????142-142/??E/SMD﹕?DCD?ON?? 04-14?21:34:12.502??26254-26254/com.aliao.myandroiddemo?E/AndroidRuntime﹕?FATAL?EXCEPTION:?main?? ????java.lang.IllegalArgumentException:?View?not?attached?to?window?manager?? ????????????at?android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:696)?? ????????????at?android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:379)?? ????????????at?android.view.WindowManagerImpl$CompatModeWrapper.removeView(WindowManagerImpl.java:164)?? ????????????at?android.app.Dialog.dismissDialog(Dialog.java:319)?? ????????????at?android.app.Dialog.dismiss(Dialog.java:302)?? ????????????at?com.aliao.myandroiddemo.view.handler.TestHandlerActivity$1.handleMessage(TestHandlerActivity.java:87)?? ????????????at?android.os.Handler.dispatchMessage(Handler.java:99)?? ????????????at?android.os.Looper.loop(Looper.java:137)?? ????????????at?android.app.ActivityThread.main(ActivityThread.java:4963)?? ????????????at?java.lang.reflect.Method.invokeNative(Native?Method)?? ????????????at?java.lang.reflect.Method.invoke(Method.java:511)?? ????????????at?com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)?? ????????????at?com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)?? ????????????at?dalvik.system.NativeStart.main(Native?Method)?? ?
該示例的代碼:
res/layout/activity_handler.xml——TestHandlerActivity的布局文件
?
[html] ?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>?? ?? <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"?? ????android:orientation="vertical"?android:layout_width="match_parent"?? ????android:layout_height="match_parent">?? ?? ????<TextView?? ????????android:layout_width="match_parent"?? ????????android:layout_height="wrap_content"?? ????????android:text="通過(guò)點(diǎn)擊按鈕來(lái)啟動(dòng)一個(gè)線程模擬運(yùn)行一個(gè)網(wǎng)絡(luò)耗時(shí)操作,獲取新聞詳情并顯示在按鈕下面"?? ????????android:textSize="16sp"/>?? ?? ????<Button?? ????????android:layout_width="wrap_content"?? ????????android:layout_height="wrap_content"?? ????????android:text="獲取MH370航班最新新聞動(dòng)態(tài)"?? ????????android:textSize="16sp"?? ????????android:id="@+id/btn_createthread"?? ????????android:layout_gravity="center_horizontal"?/>?? ?? ????<TextView?? ????????android:layout_width="match_parent"?? ????????android:layout_height="match_parent"?? ????????android:textAppearance="?android:attr/textAppearanceLarge"?? ????????android:textColor="@android:color/holo_green_dark"?? ????????android:textSize="16sp"?? ????????android:id="@+id/tv_showsth"?? ????????android:layout_marginTop="10dp"/>?? ?? </LinearLayout>?? ?
TestHandlerActivity——進(jìn)行異步操作,獲取數(shù)據(jù)并更新界面
?
[java] ?view plaincopy
package?com.aliao.myandroiddemo.view.handler;?? ?? import?android.app.Activity;?? import?android.app.ProgressDialog;?? import?android.content.res.Configuration;?? import?android.os.Bundle;?? import?android.os.Handler;?? import?android.os.Message;?? import?android.util.Log;?? import?android.view.View;?? import?android.widget.Button;?? import?android.widget.TextView;?? ?? import?com.aliao.myandroiddemo.R;?? import?com.aliao.myandroiddemo.utils.ThreadUtil;?? ?? public?class?TestHandlerActivity?extends?Activity?implements?View.OnClickListener{?? ?? ????private?final?String????TAG?=?"testhandler";?? ????private?TextView????????showNewsInfoTxt;?? ????private?ProgressDialog??progressDialog;?? ????private?String??????????newsInfo;?? ?? ????@Override?? ????protected?void?onCreate(Bundle?savedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????setContentView(R.layout.activity_handler);?? ???????? ????????ThreadUtil.logThreadSignature();?? ????????Button?anrBtn?=?(Button)?findViewById(R.id.btn_createthread);?? ????????anrBtn.setOnClickListener(this);?? ????????showNewsInfoTxt?=?(TextView)?findViewById(R.id.tv_showsth);?? ????????if(getResources().getConfiguration().orientation?==?Configuration.ORIENTATION_LANDSCAPE){?? ????????????Log.i(TAG,?"----onCreate?-?landscape---");?? ????????}else?if(getResources().getConfiguration().orientation?==?Configuration.ORIENTATION_PORTRAIT){?? ????????????Log.i(TAG,?"----onCreate?-?portrait?---");?? ????????}?? ????}?? ?? ????@Override?? ????public?void?onClick(View?view)?{?? ????????switch?(view.getId()){?? ????????????case?R.id.btn_createthread:?? ???????????????excuteLongTimeOperation();?? ????????????????break;?? ????????}?? ????}?? ?? ???? ????private?void?excuteLongTimeOperation()?{?? ????????progressDialog?=?ProgressDialog.show(TestHandlerActivity.this,"Load?Info","Loading...",true,true);?? ????????Thread?workerThread?=?new?Thread(new?MyNewThread());?? ????????workerThread.start();?? ????}?? ?? ????class?MyNewThread?extends?Thread{?? ????????@Override?? ????????public?void?run()?{?? ???????????? ????????????ThreadUtil.logThreadSignature();?? ???????????? ????????????ThreadUtil.sleepForInSecs(5);?? ????????????newsInfo?=?"#搜尋馬航370#【澳聯(lián)合協(xié)調(diào)中心今日記者會(huì)要點(diǎn)】1.發(fā)現(xiàn)油跡的地點(diǎn)距離信號(hào)發(fā)現(xiàn)地很近,油跡來(lái)源需進(jìn)一步調(diào)查。2.黑匣子一般只有30天壽命,最多40天,今天已經(jīng)是第38天了,但仍有可能收到信號(hào)";?? ????????????Message?message?=?handler.obtainMessage();?? ????????????Bundle?bundle?=?new?Bundle();?? ????????????bundle.putString("message",newsInfo);?? ????????????message.setData(bundle);?? ????????????handler.sendMessage(message);?? ????????}?? ????}?? ?? ???? ????private?Handler?handler?=?new?Handler(){?? ????????@Override?? ????????public?void?handleMessage(Message?msg)?{?? ????????????progressDialog.dismiss();?? ???????????? ????????????refreshNewsInfo(msg.getData().getString("message"));?? ????????}?? ????};?? ?? ???? ????private?void?refreshNewsInfo(String?newsInfo)?{?? ????????showNewsInfoTxt.setText(newsInfo);?? ????}?? ?? ???? ????@Override?? ????public?void?onConfigurationChanged(Configuration?newConfig)?{?? ????????super.onConfigurationChanged(newConfig);?? ????????Log.i(TAG,?"----onConfigurationChanged---");?? ????}?? ?? ????@Override?? ????protected?void?onDestroy()?{?? ????????super.onDestroy();?? ????????Log.i(TAG,?"====onDestroy====");?? ????}?? ?? ????@Override?? ????protected?void?onStart()?{?? ????????super.onStart();?? ????????Log.i(TAG,?"----onStart---");?? ????}?? ?? ????@Override?? ????protected?void?onResume()?{?? ????????super.onResume();?? ????????Log.i(TAG,?"----onResume---");?? ????}?? ?? ????@Override?? ????protected?void?onRestart()?{?? ????????super.onRestart();?? ????????Log.i(TAG,?"----onRestart---");?? ????}?? ?? ????@Override?? ????protected?void?onPause()?{?? ????????super.onPause();?? ????????Log.i(TAG,?"----onPause---");?? ????}?? ?? ????@Override?? ????protected?void?onStop()?{?? ????????super.onStop();?? ????????Log.i(TAG,?"----onStop---");?? ????}?? ?? ????@Override?? ????protected?void?onSaveInstanceState(Bundle?outState)?{?? ????????super.onSaveInstanceState(outState);?? ????????Log.i(TAG,?"----onSaveInstanceState---");?? ????}?? ?? }?? ?
?
解決方案 一、禁止屏幕旋轉(zhuǎn) 禁止屏幕旋轉(zhuǎn),也就無(wú)需考慮Configuration Change引發(fā)的問(wèn)題
在AcndroidManifest.xml里設(shè)置Activity的screenOrientation屬性為landscape(橫屏)或者portrait(豎屏)
?
[java] ?view plaincopy
<activity?? ????android:name="com.aliao.myandroiddemo.view.handler.TestHandlerActivity"?? ????android:label="@string/title_activity_animation"?? ????android:screenOrientation="portrait">?? </activity>?? ?
二、避免Activity重建 ?
?
?
1.配置andoird:configChanges屬性并回調(diào)onConfigurationChanged()手動(dòng)處理 ?
?
Handling the Configuration Change Yours?里指出如果應(yīng)用程序不需要在一個(gè)特定的configuration change期間更新資源(例如程序在橫屏和豎屏不同屏幕大小下不考慮資源調(diào)整),以及有防止activity重啟的性能限制,就可以通過(guò)該方法來(lái)阻止系統(tǒng)重啟activity。但是Google并不推薦使用該方法。
?
上一節(jié)討論了在某些情況下由于橫豎屏切換導(dǎo)致的一系列問(wèn)題,引起這些問(wèn)題的源頭是因?yàn)镃onfiguration Change會(huì)導(dǎo)致Activity被重建。如果Activity不被銷毀再重建也就沒(méi)有所謂的數(shù)據(jù)丟失,異步操作過(guò)程中內(nèi)存泄露程序終止等問(wèn)題了。Android提供了一種方法來(lái)避免Activity被重建:
在AndroidManifest.xml里通過(guò)android:configChanges指定要忽略的配置,例如:
?
[java] ?view plaincopy
<activity?? ????android:name="com.aliao.myandroiddemo.view.handler.TestHandlerActivity"?? ????android:configChanges="orientation|keyboardHidden"?? ????android:label="@string/title_activity_animation">?? </activity>?? Caution :需要注意的是,在Android 3.2(API Level 13)開(kāi)始,橫豎屏切換也會(huì)導(dǎo)致"screen size"(Configuraion的一個(gè)屬性)改變,所以要在android:configChanges加上該值android:configChanges="orientation|screenSize",否則當(dāng)切換屏幕時(shí),activity仍會(huì)被重建。
?
?
[java] ?view plaincopy
<activity?? ????android:name="com.aliao.myandroiddemo.view.handler.TestHandlerActivity"?? ????android:configChanges="orientation|screenSize|keyboardHidden"?? ????android:label="@string/title_activity_animation">?? </activity>?? ?
設(shè)置了android:configChanges后,Activity會(huì)在配置改變時(shí)只回調(diào)onConfigurationChanged(Configuration newConfig),不會(huì)重新走一遍Activity的生命周期:
啟動(dòng)TestHandlerActivity顯示界面Activity生命周期為:onCreate->onStart->onResume:
?
[plain] ?view plaincopy
04-14?22:56:18.092??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onCreate?-?portrait?---?? 04-14?22:56:18.092??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onStart---?? 04-14?22:56:18.092??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onResume---?? 豎屏切橫屏,只回調(diào)了onConfigurationChanged:
?
?
[plain] ?view plaincopy
04-14?22:59:29.912??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onCreate?-?portrait?---?? 04-14?22:59:29.912??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onStart---?? 04-14?22:59:29.912??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onResume---?? 04-14?22:59:33.442??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onConfigurationChanged---?? 切回豎屏,同樣只回調(diào)onConfigurationChanged:
?
?
[plain] ?view plaincopy
04-14?23:01:02.232??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onCreate?-?portrait?---?? 04-14?23:01:02.232??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onStart---?? 04-14?23:01:02.232??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onResume---?? 04-14?23:01:04.192??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onConfigurationChanged---?? 04-14?23:01:05.492??32095-32095/com.aliao.myandroiddemo?I/testhandler﹕?----onConfigurationChanged---?? 如果橫豎屏的界面布局不同,可以再res下新建layout-land目錄和layout-port目錄,然后把布局文件扔到這兩個(gè)目錄文件中:
?
res/layout-land/layout_main.xml
res/layout-port/layout_main.xml
當(dāng)程序運(yùn)行的時(shí)候會(huì)自動(dòng)判斷當(dāng)前的屏幕方向去layout里調(diào)用對(duì)應(yīng)的布局文件。 我們可以在onConfigurationChanged方法中對(duì)某些資源做調(diào)整
?
[java] ?view plaincopy
@Override?? public?void?onConfigurationChanged(Configuration?newConfig)?{?? ????super.onConfigurationChanged(newConfig);?? ?? ???? ????if?(newConfig.orientation?==?Configuration.ORIENTATION_LANDSCAPE)?{?? ????????Toast.makeText(this,?"landscape",?Toast.LENGTH_SHORT).show();?? ????}?else?if?(newConfig.orientation?==?Configuration.ORIENTATION_PORTRAIT){?? ????????Toast.makeText(this,?"portrait",?Toast.LENGTH_SHORT).show();?? ????}?? 如果不管屏幕配置變不變化,程序中使用的資源不會(huì)改變,可以不用實(shí)現(xiàn)onConfigurationChanged()回調(diào)。
?
2.不推薦<通過(guò)設(shè)置android:configChanges屬性的方法來(lái)避免activity被銷毀再重建>的原因 ?
這個(gè)方法真的很方便,在運(yùn)行上面的實(shí)例代碼時(shí),完全可以正常運(yùn)行沒(méi)有任何錯(cuò)誤。但是他也是指某種情形下適用,看了以下不推薦適用的原因后,還是掌握第二種方法比較靠譜!
先看Android Developers里怎么說(shuō)的:
?
?
Note: ?Handling the configuration change yourself can make it muchmore difficult to use alternative resources, because the system does not automatically apply them for you. This technique should be considered a last resort when you must avoid restarts due to aconfiguration change and?is not recommended for most applications .
?
?
However, your application should always be able to shut down and restart with its previous state intact, so you should not consider this technique an escape from retaining your state during normal activity lifecycle. Not only because there are other configuration changes that you cannot prevent from restarting your application, butalso because you should handle events such as when the user leaves your application and it gets destroyed before the user returns to it.
?
1.??配置改變和資源調(diào)整的問(wèn)題,因?yàn)橛眠@個(gè)方法我們需要自己往onConfigurationChanged()里寫(xiě)代碼,保證所用資源和設(shè)備的 當(dāng)前配置一致,如果一個(gè)馬虎程序很容易出現(xiàn)資源指定的bugs,原文:
?
Google engineers,however, discourage its use. The primary concern is that it requires youto handle device configuration changes manually in code. Handling configuration changes requires you to take many additional steps to ensure that each and every string, layout, drawable, dimension, etc.remains in sync with the device's current configuration, and if you aren't careful, your application can easily have a whole series of resource-specific bugs as a result.——Handling Configuration Changes With Fragments
?
2.?there are other configuration changes that you cannot prevent from restarting your application.有些configuration ? ? ?changes沒(méi)法阻止應(yīng)用重啟。(是說(shuō)的有些android:configChanges的屬性值對(duì)避免重建無(wú)效?不知道理解是否正確)
3.?很多開(kāi)發(fā)人員會(huì)錯(cuò)誤指定android:configChanges="orientation"來(lái)防止activity被銷毀或重建這種不可預(yù)知的情況。但是引起Configuration Changes的情況很多,不止是屏幕旋轉(zhuǎn)。比如修改設(shè)備默認(rèn)語(yǔ)言,修改設(shè)備默認(rèn)字體比例等等都可會(huì)引起配置改變。這種方法只對(duì)當(dāng)前設(shè)置的配置有效,除非在manifest里把所有配置都列全。
4.?當(dāng)用戶離開(kāi)應(yīng)用,在回到應(yīng)用前被銷毀的話,例如點(diǎn)擊了屏幕的Home鍵或者有個(gè)電話打進(jìn)來(lái),用戶很久之后才回到應(yīng)用程序,但是在此之前系統(tǒng)因?yàn)橘Y源緊張而銷毀了應(yīng)用進(jìn)程,當(dāng)用戶返回還是要重新創(chuàng)建activity,問(wèn)題等于沒(méi)解決。
?
Your application should be able to restart at any time without loss of user data or state in order to handle events such as configuration changes or when the user receives an incoming phone call and then returns to your application much later after your application process may have been destroyed.——Handling Runtime Changes
?
As a user you won't stay on that activity and stare at it. You would switch to the home screen or to another app like a game or a phone call might come in or something else resource hungry that will eventually destroy your activity. And what then? You are facing the same old issue which is NOT solved with that neat little trick. The activity will be recreated all over again when the user comes back.——How to handle screen orientation change when progress dialog and background thread active?中的一個(gè)評(píng)論
?
三、覆寫(xiě)onRetainNonConfigurationInstance()來(lái)保留activity中的數(shù)據(jù)對(duì)象
在Android 3.0發(fā)布之前,處理Configuration Change的方法是覆寫(xiě)onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()方法。在onRetainNonConfigurationInstance()中返回對(duì)象(持有數(shù)據(jù)),再通過(guò)getLastNonConfigurationInstance()方法獲取該對(duì)象,再更新界面數(shù)據(jù)即可。看個(gè)例子就很容易明白了,修改TestHandlerActivity代碼如下:
?
[java] ?view plaincopy
public?class?TestHandlerActivity?extends?Activity?implements?View.OnClickListener{?? ?? ????private?final?String????TAG?=?"testhandler";?? ????private?TextView????????showNewsInfoTxt;?? ????private?ProgressDialog??progressDialog;?? ????private?String??????????newsInfo;?? ?? ????@Override?? ????protected?void?onCreate(Bundle?savedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????setContentView(R.layout.activity_handler);?? ???????? ????????ThreadUtil.logThreadSignature();?? ????????Button?anrBtn?=?(Button)?findViewById(R.id.btn_createthread);?? ????????anrBtn.setOnClickListener(this);?? ????????showNewsInfoTxt?=?(TextView)?findViewById(R.id.tv_showsth);?? ????????if(getResources().getConfiguration().orientation?==?Configuration.ORIENTATION_LANDSCAPE){?? ????????????Log.i(TAG,?"----onCreate?-?landscape---");?? ????????}else?if(getResources().getConfiguration().orientation?==?Configuration.ORIENTATION_PORTRAIT){?? ????????????Log.i(TAG,?"----onCreate?-?portrait?---");?? ????????}?? ????????String?retain?=?(String)?getLastNonConfigurationInstance();?? ????????if?(retain?!=?null){?? ????????????refreshNewsInfo(retain);?? ????????}else{?? ???????????? ????????????excuteLongTimeOperation();?? ????????}?? ????}?? ?? ???? ????@Override?? ????public?Object?onRetainNonConfigurationInstance()?{?? ????????return?newsInfo;?? ????}?? ?? ???? ????private?void?excuteLongTimeOperation()?{?? ????????progressDialog?=?ProgressDialog.show(TestHandlerActivity.this,"Load?Info","Loading...",true,true);?? ????????Thread?workerThread?=?new?Thread(new?MyNewThread());?? ????????workerThread.start();?? ????}?? }?? ?
?
三、推薦使用Fragment來(lái)處理Configuration Change
具體步驟如下:
1.?Extend theFragment?class and declare references to your stateful objects.
2.?CallsetRetainInstance(boolean)?when the fragment is created. ?
3. Add the fragment to your activity.
4. Use?FragmentManager?to retrieve the fragment when the activity is restarted.
定義一個(gè)RetainedFragment類:
?
[java] ?view plaincopy
package?com.aliao.myandroiddemo.view.handler;?? ?? import?android.app.Activity;?? import?android.net.Uri;?? import?android.os.Bundle;?? import?android.os.Handler;?? import?android.os.Message;?? import?android.support.v4.app.Fragment;?? import?com.aliao.myandroiddemo.utils.ThreadUtil;?? ?? ?? public?class?RetaindFragment?extends?Fragment?{?? ?? ????private?OnFragmentInteractionListener?mListener;?? ?? ????@Override?? ????public?void?onCreate(Bundle?savedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ???????? ????????setRetainInstance(true);?? ????}?? ?? ???? ????public?void?excuteLongTimeOperation()?{?? ????????Thread?workerThread?=?new?Thread(new?MyNewThread());?? ????????workerThread.start();?? ????}?? ?? ????class?MyNewThread?extends?Thread{?? ????????@Override?? ????????public?void?run()?{?? ???????????? ????????????ThreadUtil.logThreadSignature();?? ???????????? ????????????ThreadUtil.sleepForInSecs(5);?? ????????????String?newsInfo?=?"#搜尋馬航370#【澳聯(lián)合協(xié)調(diào)中心今日記者會(huì)要點(diǎn)】1.發(fā)現(xiàn)油跡的地點(diǎn)距離信號(hào)發(fā)現(xiàn)地很近,油跡來(lái)源需進(jìn)一步調(diào)查。2.黑匣子一般只有30天壽命,最多40天,今天已經(jīng)是第38天了,但仍有可能收到信號(hào)";?? ????????????Message?message?=?handler.obtainMessage();?? ????????????Bundle?bundle?=?new?Bundle();?? ????????????bundle.putString("message",newsInfo);?? ????????????message.setData(bundle);?? ????????????handler.sendMessage(message);?? ????????}?? ????}?? ?? ???? ????private?Handler?handler?=?new?Handler(){?? ????????@Override?? ????????public?void?handleMessage(Message?msg)?{?? ?? ???????????? ????????????if(mListener?!=?null){?? ????????????????mListener.onFragmentInteraction(msg.getData().getString("message"));?? ????????????}?? ????????}?? ????};?? ?? ?? ?? ???? ????public?void?onButtonPressed(String?string)?{?? ????????if?(mListener?!=?null)?{?? ????????????mListener.onFragmentInteraction(string);?? ????????}?? ????}?? ?? ?? ?? ????@Override?? ????public?void?onAttach(Activity?activity)?{?? ????????super.onAttach(activity);?? ????????try?{?? ????????????mListener?=?(OnFragmentInteractionListener)?activity;?? ????????}?catch?(ClassCastException?e)?{?? ????????????throw?new?ClassCastException(activity.toString()?? ????????????????????+?"?must?implement?OnFragmentInteractionListener");?? ????????}?? ?? ????}?? ?? ????@Override?? ????public?void?onDetach()?{?? ????????super.onDetach();?? ????????mListener?=?null;?? ????}?? ?? ???? ????public?interface?OnFragmentInteractionListener?{?? ???????? ????????public?void?onFragmentInteraction(String??string);?? ????}?? ?? }?? 這個(gè)Fragment沒(méi)有界面,它用來(lái)處理異步操作,然后把結(jié)果就該界面的部分返回給Activity來(lái)處理,Activity會(huì)實(shí)現(xiàn)Fragment中定義的OnFragmentInteractionListener接口中的onFragmentInteraction(String string)方法(Fragment與Activity之間的通訊),這個(gè)接口我們可以自己定義。把之前在TestHandlerActivity中的異步操作移植到RetainedFragemnt類中。
?
TestHandlerActivity對(duì)應(yīng)的布局文件activity_handler.xml修改代碼如下:
?
[html] ?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>?? ?? <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"?? ????android:orientation="vertical"?android:layout_width="match_parent"?? ????android:layout_height="match_parent">?? ?? ????<TextView?? ????????android:layout_width="match_parent"?? ????????android:layout_height="wrap_content"?? ????????android:text="通過(guò)點(diǎn)擊按鈕來(lái)啟動(dòng)一個(gè)線程模擬運(yùn)行一個(gè)網(wǎng)絡(luò)耗時(shí)操作,獲取新聞詳情并顯示在按鈕下面"?? ????????android:textSize="16sp"/>?? ?? ????<Button?? ????????android:layout_width="wrap_content"?? ????????android:layout_height="wrap_content"?? ????????android:text="獲取MH370航班最新新聞動(dòng)態(tài)"?? ????????android:textSize="16sp"?? ????????android:id="@+id/btn_createthread"?? ????????android:layout_gravity="center_horizontal"?/>?? ?? ????<ProgressBar?? ????????android:id="@+id/progress_circular"?? ????????android:layout_width="wrap_content"?? ????????android:layout_height="wrap_content"?? ????????android:layout_margin="10dp"?? ????????style="@android:style/Widget.ProgressBar.Small"?? ????????android:visibility="gone"?? ????????android:layout_gravity="center_horizontal"/>?? ?? ????<TextView?? ????????android:layout_width="match_parent"?? ????????android:layout_height="match_parent"?? ????????android:textAppearance="?android:attr/textAppearanceLarge"?? ????????android:textColor="@android:color/holo_green_dark"?? ????????android:textSize="16sp"?? ????????android:id="@+id/tv_showsth"?? ????????android:layout_marginTop="10dp"/>?? ?? ?? ?? ?? </LinearLayout>?? ?
?
TestHandlerActivity中的代碼修改如下:
?
[java] ?view plaincopy
package?com.aliao.myandroiddemo.view.handler;?? ?? import?android.app.Activity;?? import?android.app.ProgressDialog;?? import?android.content.res.Configuration;?? import?android.os.Bundle;?? import?android.os.Handler;?? import?android.os.Message;?? import?android.support.v4.app.FragmentActivity;?? import?android.support.v4.app.FragmentManager;?? import?android.util.Log;?? import?android.view.View;?? import?android.widget.Button;?? import?android.widget.ProgressBar;?? import?android.widget.TextView;?? ?? import?com.aliao.myandroiddemo.R;?? import?com.aliao.myandroiddemo.utils.ThreadUtil;?? ?? public?class?TestHandlerActivity?extends?FragmentActivity?implements?View.OnClickListener,RetaindFragment.OnFragmentInteractionListener{?? ?? ????private?final?String????TAG?=?"testhandler";?? ????private?TextView????????showNewsInfoTxt;?? ????private?ProgressDialog??progressDialog;?? ????private?ProgressBar?????progressBar;?? ????private?String??????????newsInfo;?? ????private?RetaindFragment?dataFragment;?? ????private?static?final?String?KEY_CURRENT_NEWSDATA?=?"current_nesdata";?? ?? ????@Override?? ????protected?void?onCreate(Bundle?savedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????setContentView(R.layout.activity_handler);?? ????????Log.i(TAG,?"----onCreate---");?? ???????? ????????ThreadUtil.logThreadSignature();?? ????????Button?anrBtn?=?(Button)?findViewById(R.id.btn_createthread);?? ????????anrBtn.setOnClickListener(this);?? ????????showNewsInfoTxt?=?(TextView)?findViewById(R.id.tv_showsth);?? ????????progressBar?=?(ProgressBar)?findViewById(R.id.progress_circular);?? ????????if(null?!=?savedInstanceState){?? ????????????refreshNewsInfo((String)?savedInstanceState.get(KEY_CURRENT_NEWSDATA));?? ????????}?? ?? ???????? ????????FragmentManager?fm?=?getSupportFragmentManager();?? ????????dataFragment?=?(RetaindFragment)?fm.findFragmentByTag("data");?? ????????if(null?==?dataFragment){?? ???????????? ????????????dataFragment?=?new?RetaindFragment();?? ????????????fm.beginTransaction().add(dataFragment,?"data").commit();?? ???????????? ?????????????? ????????}?? ????}?? ?? ?? ????@Override?? ????public?void?onClick(View?view)?{?? ????????switch?(view.getId()){?? ????????????case?R.id.btn_createthread:?? ????????????????progressBar.setVisibility(View.VISIBLE);?? ???????????????? ????????????????dataFragment.excuteLongTimeOperation();?? ????????????????break;?? ????????}?? ????}?? ?? ????@Override?? ????public?void?onFragmentInteraction(String?newsInfo)?{?? ????????this.newsInfo?=?newsInfo;?? ????????refreshNewsInfo(newsInfo);?? ????}?? ?? ???? ????private?void?refreshNewsInfo(String?newsInfo)?{?? ????????progressBar.setVisibility(View.GONE);?? ????????showNewsInfoTxt.setText(newsInfo);?? ????}?? ?? ????@Override?? ????protected?void?onSaveInstanceState(Bundle?outState)?{?? ????????super.onSaveInstanceState(outState);?? ????????outState.putString(KEY_CURRENT_NEWSDATA,showNewsInfoTxt.getText().toString()); ????????Log.i(TAG,?"----onSaveInstanceState---");?? ????}?? ?? ???? ????@Override?? ????public?void?onConfigurationChanged(Configuration?newConfig)?{?? ????????super.onConfigurationChanged(newConfig);?? ????????Log.i(TAG,?"----onConfigurationChanged---");?? ????}?? ?? ????@Override?? ????protected?void?onDestroy()?{?? ????????super.onDestroy();?? ????????Log.i(TAG,?"====onDestroy====");?? ????}?? ?? ????@Override?? ????protected?void?onStart()?{?? ????????super.onStart();?? ????????Log.i(TAG,?"----onStart---");?? ????}?? ?? ????@Override?? ????protected?void?onResume()?{?? ????????super.onResume();?? ????????Log.i(TAG,?"----onResume---");?? ????}?? ?? ????@Override?? ????protected?void?onRestart()?{?? ????????super.onRestart();?? ????????Log.i(TAG,?"----onRestart---");?? ????}?? ?? ????@Override?? ????protected?void?onPause()?{?? ????????super.onPause();?? ????????Log.i(TAG,?"----onPause---");?? ????}?? ?? ????@Override?? ????protected?void?onStop()?{?? ????????super.onStop();?? ????????Log.i(TAG,?"----onStop---");?? ????}?? ?? ?? ?? }?? 在異步操作還未執(zhí)行完畢的時(shí)候旋轉(zhuǎn)屏幕,TestHandlerActivity會(huì)被銷毀再重建。新的TestHandlerActivity被創(chuàng)建,新的Activity實(shí)例會(huì)傳送給onAttach(Activity)方法,通過(guò)打印onAttach中的activity可以看到屏幕旋轉(zhuǎn)前后onAttach綁定的activity不同。這樣就確保不管配置是否改變RetainedFragment持有的都是當(dāng)前展示的Activity的引用。
?
在以上的示例中onSaveInstanceState的作用是在異步操作完畢時(shí)旋轉(zhuǎn)屏幕確保屏幕數(shù)據(jù)不丟失。
onSaveInstanceState:?it might not be possible for you to completely restore youractivity state with theBundle?that the system saves for you with theonSaveInstanceState()?callback—it is notdesigned to carry large objects (such as bitmaps) and the data within it must be serialized thendeserialized, which can consume a lot of memory and make the configuration change slow.——Handling Runtime Changes
?
異步操作顯示對(duì)話框在Configuration Changes時(shí)導(dǎo)致程序崩潰 之前看到一篇講內(nèi)存泄露的文章,其中一個(gè)內(nèi)存泄露的情境和上面的實(shí)例代碼情境很類似,大意是:在Activity里創(chuàng)建一個(gè)子線程來(lái)跑耗時(shí)操作,在異步操作沒(méi)結(jié)束前旋轉(zhuǎn)屏幕,線程沒(méi)執(zhí)行完,old Activity也就不會(huì)被銷毀,會(huì)導(dǎo)致內(nèi)存泄露。摘取部分原文內(nèi)容: “由于我們的線程是Activity的內(nèi)部類,所以MyThread中保存了Activity的一個(gè)引用,當(dāng)MyThread的run函數(shù)沒(méi)有結(jié)束時(shí),MyThread是不會(huì)被銷毀的,因此它所引用的老的Activity也不會(huì)被銷毀,因此就出現(xiàn)了內(nèi)存泄露的問(wèn)題。” “Thread只有在run函數(shù)不結(jié)束時(shí)才出現(xiàn)這種內(nèi)存泄露問(wèn)題” 用圖來(lái)表示上述內(nèi)容的話,應(yīng)該是:
看完這圖就delete掉記憶吧,錯(cuò)滴錯(cuò)滴
?
他這段話誤導(dǎo)了我好一陣:“線程的run函數(shù)沒(méi)有結(jié)束,線程不會(huì)被銷毀,他所引用的老activity也不會(huì)被銷毀。所以出現(xiàn)了內(nèi)存泄露。”在這種理解的基礎(chǔ)上,我一直以為帶進(jìn)度對(duì)話框的異步操作在屏幕旋轉(zhuǎn)的時(shí)候出現(xiàn)程序終止,是因?yàn)榫€程沒(méi)結(jié)束,activity不銷毀,所以導(dǎo)致了內(nèi)存泄露。而且logcat下還打印了這么一句:
?
04-16 00:26:18.703 ?17075-17075/com.aliao.myandroiddemo E/WindowManager﹕ Activity com.aliao.myandroiddemo.view.handler.TestHandlerActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@41f9a990 that was originally added here
?
當(dāng)時(shí)我就一直為了驗(yàn)證心里早已固定的認(rèn)同感,看到“TestHandlerActivity has leaked”TestHandlerActivity已經(jīng)泄露了...就不加思考的去相信了。
?
但是今天在看有關(guān)于異步操作帶對(duì)話框在configuration change時(shí)的處理辦法時(shí),總有一個(gè)疑問(wèn)就是舊的activity會(huì)在線程結(jié)束的時(shí)候被銷毀嗎?后來(lái)做了測(cè)試,代碼用的還是<Configuration Changes引發(fā)的問(wèn)題>里最后貼的代碼:
?
測(cè)試設(shè)備:HTC t329d Android4.1
?
測(cè)試操作:點(diǎn)擊按鈕啟動(dòng)線程,旋轉(zhuǎn)屏幕,記錄Activity被銷毀時(shí)間,查看debug模式下的Threads列表記錄線程消失時(shí)間
?
測(cè)試條件一:異步操作執(zhí)行時(shí)長(zhǎng)5秒
?
測(cè)試一結(jié)果:Activity的onDestroy調(diào)用的時(shí)間比worker thread結(jié)束時(shí)間晚或相等(這條件下就測(cè)了兩次)。
?
測(cè)試條件二:異步操作執(zhí)行時(shí)長(zhǎng)20秒
?
測(cè)試二結(jié)果:啟動(dòng)線程的時(shí)間:00:08:58
?
? ? ? ? ? ? ? ? ? ? ?activity的onDestroy()調(diào)用時(shí)間:00:09:04
?
? ? ?thread的在Threads列表消失時(shí)間:00:09:18
?
? ? ? 可以看到old activity的銷毀時(shí)間在thread結(jié)束之前!!!
?
測(cè)試結(jié)果表明:activity并不是在thread結(jié)束后才銷毀。這與之前說(shuō)的“thread沒(méi)有銷毀導(dǎo)致被持有引用的activity也不會(huì)銷毀”相互矛盾!所以因?yàn)檫@個(gè)原因?qū)е碌膬?nèi)存泄露的說(shuō)法就更沒(méi)有說(shuō)服力了。
?
再看之前l(fā)og打印的錯(cuò)誤:
?
1. WindowManager﹕ Activity com.aliao.myandroiddemo.view.handler.TestHandlerActivity has leaked windowcom.android.internal.policy.impl.PhoneWindow$DecorView@41f9a990 that was originally added here
?
不是TestHandlerActivity has leaked
?
2. java.lang.IllegalArgumentException:View not attached to window manager
?
這個(gè)錯(cuò)誤的發(fā)生是因?yàn)閐ismiss對(duì)話框時(shí),所屬Activity已經(jīng)不在了。
?
經(jīng)過(guò)上面的測(cè)試和打印的錯(cuò)誤log可以得出:這個(gè)bug不是因?yàn)閛ld activity沒(méi)銷毀導(dǎo)致內(nèi)存泄露,而是activity被銷毀后 progressDialog還持有這個(gè)activity的引用。異步任務(wù)開(kāi)始時(shí)顯示對(duì)話框,任務(wù)完成后去取消progressDialog。當(dāng)任務(wù)沒(méi)結(jié)束時(shí)旋轉(zhuǎn)屏幕,會(huì)導(dǎo)致old activity被銷毀,然后到了線程執(zhí)行結(jié)束要dismiss progressDialog的時(shí)候發(fā)現(xiàn)所屬的activity已經(jīng)不在了。
解決辦法(如果有其他好方法,推薦下下哇):
1.在布局文件創(chuàng)建progressBar來(lái)代替progressDialog
2. 創(chuàng)建一個(gè)AsyncTask的時(shí)候把當(dāng)前Activity的引用傳給其構(gòu)造函數(shù)。onRetainNonConfigurationInstance()中判斷線程是否結(jié)束,如果結(jié)束了就把progressDialog取消掉,然后將AsyncTask對(duì)象mTask返回。在onCreate中通過(guò)getLastNonConfigurationInstance()接收mTask,關(guān)聯(lián)當(dāng)前activity——mtask.mContext = this;再重新啟動(dòng)一個(gè)progressDialog。保證了progressDialog在actviity銷毀錢被dismiss掉。from?How to handle screen orientation change when progress dialog and background thread active?中的其中一個(gè)回答。單單只是測(cè)試progressDialog在橫豎屏切換時(shí)是否會(huì)崩潰,測(cè)試結(jié)果是正常的。
3.網(wǎng)上還有說(shuō)用IntentService來(lái)解決,沒(méi)用過(guò)這個(gè),先不測(cè)了。
遺留問(wèn)題: ?
1.在Configuration Changes引發(fā)的問(wèn)題一節(jié)中 "there are other configuration changes that you cannot prevent from restarting your application."該怎么正確的翻譯和理解
2. 在Configuration Changes引發(fā)的問(wèn)題一節(jié)中的第四點(diǎn)怎么理解才是正確的。不知道這種情況發(fā)生的情境,應(yīng)用進(jìn)程被銷毀是等于整個(gè)app被kill掉,那不就是又重新打開(kāi)app,重新進(jìn)入activity也是正常的步驟。重新進(jìn)入再重新請(qǐng)求唄。
?
參考資料: 強(qiáng)烈推薦閱讀 Handling Runtime Changes?——來(lái)自Android Developers,介紹Configuration changes及其對(duì)數(shù)據(jù)丟失的解決方法。 Handling Configuration Changes With Fragments?—— from?Alex Lockwood?的blog,介紹了Configuration Changes的引發(fā)的問(wèn)題、為什么不推薦適用android:configChanges方式來(lái)解決問(wèn)題以及適用Fragments如何處理Configuration Changes(異步操作用的AsyncTask,比Thread+Handler在mainThread和workerThread上的UI更新和耗時(shí)處理上更加模塊化,更方便)。 Handling progress dialogs and orientation changes?from?
ddewaele?的blog,主要介紹progress dialog與屏幕旋轉(zhuǎn)時(shí)產(chǎn)生的問(wèn)題以及其解決方法,從舉例到說(shuō)明非常詳細(xì)。 How to handle screen orientation change when progress dialog and background thread active??——from stackoverflow上的問(wèn)題,回答及評(píng)論值得一看。? [Android問(wèn)答]旋轉(zhuǎn)屏幕導(dǎo)致Activity重建怎么辦?——介紹了三種解決Activity重建的方法。
轉(zhuǎn)載于:https://www.cnblogs.com/dongweiq/p/4807591.html
總結(jié)
以上是生活随笔 為你收集整理的Android Configuration change引发的问题及解决方法 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。