




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Android開發(fā)藝術(shù)探索筆記第一章:Activity的生命周期和啟動模式一.序作為這本書的第一章,主席還是把Activity搬上來了,也確實,和Activity打交道的次數(shù)基本上是最多的,而且他的內(nèi)容和知識點也是很多的,非常值得我們優(yōu)先把他掌握,Activity中文翻譯過來就是”活動”的意思,但是主席覺得這樣翻譯有些生硬,直接翻譯成“界面”可能更好,的確,Activity主要也是用于UI效果的呈現(xiàn),不過兩者翻譯都不為過,我們知其意就行了,正常情況下,我們除了Window,Dialog,Toast,我們還能見到的就只有Activity了,他需要setContentView()去綁定一個視圖Vi
2、ew作為效果的呈現(xiàn),然而,作為一本高質(zhì)量的進(jìn)階書??隙ú粫@著入門知識講解,本章的側(cè)重點在于對Activity使用過程中搞不清楚的概念,生命周期和啟動模式已經(jīng)IntentFilter的匹配規(guī)則分析,畢竟Activity在異常狀態(tài)下的生命周期是多樣化的,至于Activity的啟動模式和各種各樣的Flags,更是讓很多人摸不著頭腦,還有隱式啟動Activity中也有著復(fù)雜的Intent匹配過程,所以我們還是一步步的去學(xué)習(xí)下去,真正的了解Activity這個小家伙!二.Activity的生命周期全面分析Activity的生命周期,本章主要講解兩個方面典型情況下的生命周期異常情況下的生命周期典型情
3、況是指用戶參與的情況下,Activity所經(jīng)過的生命周期的變化,異常情況下的話,就有多種可能了,比如系統(tǒng)回收或者由于當(dāng)前設(shè)備的Configuration發(fā)生改變從而導(dǎo)致Activity被銷毀重建,異常情況下的生命周期的關(guān)注點和典型情況下有些不同,所以要分開來描述才能描述的清楚些1.典型情況下的生命周期分析在正常的情況下,生命周期會經(jīng)歷以下的生命周期onCreate:表示Activity正在被創(chuàng)建,這是生命周期的第一個方法,在這個方法中,我們可以做一些初始化的工作,比如調(diào)用onContentView去加載界面布局資源,初始化Activity所需數(shù)據(jù)等onRestart:表示Activity正在重
4、新啟動,一般情況下,當(dāng)當(dāng)前Activity從不可見重新變?yōu)榭梢姇r,onRestart就會被調(diào)用,這總情況一般是用戶行為所導(dǎo)致的,比如用戶按home鍵切換到桌面或者用戶打開了一個新的Activity,這時當(dāng)前的Activity就會被暫停,也就是onPause和onStop方法被執(zhí)行了,接著用戶又回到了這個Activity,就會出現(xiàn)這種情況onStart:表示Activity正在被啟動,即將開始,這個時候Activity已經(jīng)可見了,但是還沒有出現(xiàn)在前臺,還無法和用戶交互,這個時候我們可以理解為Activity已經(jīng)啟動了,但是我們還沒有看見onResume:表示Activity已經(jīng)可見了,并且出現(xiàn)在
5、前臺,并開始活動了,要注意這個和onStart的對比,這兩個都表示Activity已經(jīng)可見了,但是onStart的時候Activity還處于后臺,onResume的時候Activity才顯示到前臺onPause:表示Activity正在停止,正常情況下,緊接著onStop就會被調(diào)用,在特殊情況下,如果這個時候再快速的回到當(dāng)前Activity,那么onResume就會被調(diào)用,主席的理解是這個情況比較極端,用戶操作很難重現(xiàn)這個場景,此時可以做一些數(shù)據(jù)存儲,停止動畫等工作,但是注意不要太耗時了,因為這樣會影響到新的Activity的顯示,onPause必須先執(zhí)行完,新Activity的onResum
6、e才會執(zhí)行onStop:表示Activity即將停止,同樣可以做一些輕量級的資源回收,但是不要太耗時了onDestroy:表示Activity即將被銷毀,這是Activity生命周期的最后一個回調(diào),在這里我們可以做一些最后的回收工作和資源釋放正常情況下,Activity的常用生命周期用官網(wǎng)的一張圖就足夠表示了這里附加幾個說明1.針對一個特定的Activity,第一次啟動,回調(diào)如下:onCreate > onStart > onResume2.當(dāng)用戶打開新的Activity或者切換到桌面的時候,回調(diào)如下:onPause > onStop > 這里有一種特殊的情況就是,如果
7、新的Activity采取了透明的主題的話,那么當(dāng)前Activity不會回調(diào)onStop3.當(dāng)用戶再次回到原來的Activity,回調(diào)如下:onRestart > onStart > onResume4.d當(dāng)用戶按back鍵的時候回調(diào)如下:onPause > onStop > onDestroy5.當(dāng)Activity被系統(tǒng)回收的時候再次打開,生命周期回調(diào)方法和1是一樣的,但是你要注意一下就是只是生命周期一樣,不代表所有的進(jìn)程都是一樣的,這個問題等下回詳細(xì)分析6.從整個生命周期來說,onCreate和onDestroy是配套的,分別標(biāo)示著Activity的創(chuàng)建和銷毀,并且只
8、可能有一次調(diào)用,從Activity是否可見來說,onStart和onStop是配套的,隨著用戶的操作和設(shè)備屏幕的點亮和熄滅,這兩個方法可能被調(diào)用多次,從Activity是否在前臺來說,onResume和onPause是配套的,隨著用戶操作或者設(shè)備的點亮和熄滅,這兩個方法可能被多次調(diào)用這里提出兩個問題1.onStart和onResume,onPause和onStop從描述上都差不多,對我們來說有什么實質(zhì)性的不同呢?2.假設(shè)當(dāng)前Activity為A,如果用戶打開了一個新的Activity為B,那么B的onResume和A的onPause誰先執(zhí)行尼?我們先來回答第一個問題,從實際使用過程來說, on
9、Start和onResume,onPause和onStop看起來的確差不多,甚至我們可以只保留其中的一對,比如只保留onStart和onStop,既然如此,那為什么Android系統(tǒng)還會提供看起來重復(fù)的接口呢?根據(jù)上面的分析,我們知道,這兩個配對的回調(diào)分別代表不同的意義,onStart和onStop是從Activity是否可見這個角度來回調(diào)的,除了這種區(qū)別,在實際的使用中,沒有其他明顯的區(qū)別第二個問題,我們就要從源碼的角度來分析以及得到解釋了,關(guān)于Activity的工作原理會在本書后續(xù)章節(jié)進(jìn)行講解,這里我們大致的了解即可,從Activity的啟動過程來看,我們來看一下系統(tǒng)的源碼,Activit
10、y啟動過程的源碼相當(dāng)復(fù)雜,設(shè)計到了Instrumentation,Activit和ActivityManagerService(AMS),這里不詳細(xì)分析這一過程,簡單理解,啟動Activity的請求會由 Instrumentation 來處理,然后他通過Binder向AMS發(fā)請求,AMS內(nèi)部維護(hù)著一個ActivityStack,并負(fù)責(zé)棧內(nèi)的Activity的狀態(tài)同步,AMS通過ActivityThread去同步Activity的狀態(tài)從而完成生命周期方法的調(diào)用,在ActivityStack中的resumeTopActivityLnnerLocked方法中,有這么這段代碼 /we need to
11、start pausing the current activity so the top one can be resumed boolean dontWaitForPause = (.flags& ActivityInfo.FLAG_RESUME_WHILE_PAUSING)!=0; boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, KeyStore.TrustedCertificateEntry,dontWaitForPause); if(mResumedActivity != nul
12、l) pausing != startPaUSINGlOCAKED(userLeaving,false,true,dontWaitForPause); if(DEBUG_STATES) Slog.d(TAG,"resumeTopActivityLocked:pausing" + mResumedActivity); 從上述的代碼中我們可以看出,在新Activity啟動之前,棧頂?shù)腁ctivity需要先onPause后,新的Activity才能啟動,最終,在ActvityStackSupervisor中的realStartActivityLocked方法中,會調(diào)用如下代碼ap
13、p.thread.scheduleLaunchActivity(new Intent(ent),r.appToken,System.identityHashCode(r),,new Configuration(mService.mConfiguration) ,pat,r.task.voiceInteractor,app.repProcState,r.icicle,r.persistentState,results,new Intents,!andResume,mService.isNextTransitionForward() ,profilerInfo);我們都知道,
14、在這個app.thread的類型是IApplicationThread的具體實現(xiàn)實在ActivityTread中,所以,這段代碼實際上遇到了ActivityThread當(dāng)中,即ApplicationThread的scheduleLaunchActivity方法,而scheduleLaunchActivity方法最終會完成生命周期的調(diào)用過程,因此可以得出結(jié)論,是舊Activity縣onPause,然后新的Activityy再啟動至于ApplicationThread的scheduleLaunchActivity方法為什么會完成新Activity的生命周期,請看接下來的代碼,scheduleLau
15、nchActivty為什么會完成新的Activtyprivate void handlerLaunchActivity(ActivityClientRecord r, Intent customIntent) /if we are getting ready to gc after going to the background,well we are back active so skip it unscheduleGcIdler(); mSomeActivitiesChanged =true; if(filerInfo != null) mProfiler.setProfiler
16、(filerInfo); mProfiler.startProfiling; /Make sure we are running with the most recent config handlerConfigurationChanged(null,null); if(localLOGV)Slog.v TAG,"Handling launch of"+r); /在這里新Activity被創(chuàng)建出來,其onCreate和onStart被調(diào)用 Activity a = PerformLaunchActivity(r,customIntent); if(a != nul
17、l) r.createdConfig = new Configuration(mConfiguration); Bundle oldState = r.start; handlerResumeActivity(r.token,false,r.isForward, !r.activity.mFinished && r.startsNotResumed); /省略. c從上面的分析可以看出,當(dāng)新的Activity啟動的時候,舊的Activity的onPause方法會先執(zhí)行,然后才啟動新的Activity,到底是不是這樣尼?我們可以寫一個小栗子來驗證一下,如下是兩個Activity的
18、代碼,在MainActivity中點擊按鈕可以跳轉(zhuǎn)到SecondActivity,同時為了分析生命周期,我們把log日志也打出來MainActivitypackage com.liuguilin.activitysample;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;public class MainActivity extends A
19、ppCompatActivity public static final String TAG = "MainActivity" Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btnTo).setOnClickListener(new View.OnClickListener() Override public vo
20、id onClick(View view) startActivity(new Intent(MainActivity.this, SecondActivity.class); ); Override protected void onPause() super.onPause(); Log.i(TAG, "onPause"); Override protected void onStop() super.onStop(); Log.i(TAG, "onStop"); SecondActivitypackage com.liuguilin.activit
21、ysample;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;/* * Created by lgl on 16/8/24. */public class SecondActivity extends AppCompatActivity private static final String TAG = "SecondActivity" Override protected void onCreate(Bundle savedI
22、nstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Log.i(TAG, "onCreate"); Override protected void onStart() super.onStart(); Log.i(TAG, "onStart"); Override protected void onResume() super.onResume(); Log.i(TAG, "onResume"); 這樣我
23、們可以觀察到他的生命周期通過這個生命周期我們可以觀察到,舊的Activity的onPause先調(diào)用,然后新的Activity才啟動,這也證實了我們上面的分析原理,也許有人問,你只是分析了Andorid5.0的源碼,你怎么所有的版本源碼邏輯都相同,的確,我們不能把所有的版本都概括,但是作為Android的一個運行過程的基本邏輯,隨著版本的更新并不會很大的改變,因為Android也需要兼容性,不能說在同一個版本上運行有兩種不同的邏輯,那根本不可能,關(guān)于這一點,我們要把握一個度,就是對于Android的基本運行機(jī)制,的不同,Android不能在onPause中做重量級的操作,因為必須在onPause
24、執(zhí)行完成以后新的Activity才能Resume,從這一點我們也間接性的證明了我們的結(jié)論,通過分析這個問題,我們知道onPause和onStop都不能做耗時的操作,尤其是onPause,這也意味著,我們應(yīng)當(dāng)盡量的在onStop中做操作,從而使新的Activity盡快顯示出來并且換到前后臺三.異常情況下的生命周期分析上一節(jié)我們分析的是正常事情下的生命周期,但是我們寫程序也不要理想化,居多的問題就是出在異常情況下,我們知道,Activity除了受用戶操作導(dǎo)致的正常生命周期的調(diào)度,同時還會存在一些異常的情況,比如當(dāng)資源相關(guān)的系統(tǒng)配置發(fā)生改變以及系統(tǒng)內(nèi)存不足的時候,Activity就有可能被殺死,下面
25、我們具體來分析下這幾種情況1.情況1:資源相關(guān)的系統(tǒng)配置發(fā)生改變導(dǎo)致Activity被殺死并重新創(chuàng)建理解這個問題,首先要對系統(tǒng)的資源加載有一定的了解,這里就不詳細(xì)分析系統(tǒng)資源加載的機(jī)制了,但是我們簡單說明一下,拿最簡單的圖片來說,當(dāng)我們把一張圖片擋在drawable中的時候,就可以通過Resources去獲取這張圖片了,同時為了兼容不同的設(shè)備,我們可能還需要在其他一些目錄下放置不同的圖片,比如drawable-xhdpi之類的,當(dāng)應(yīng)用程序啟動時,系統(tǒng)會根據(jù)當(dāng)前設(shè)備的情況去加載合適的Resources資源,比如說橫屏手機(jī)和豎屏手機(jī)會拿著兩張不同的圖片(設(shè)定了landscape或者portrait
26、狀態(tài)下的圖片),比如之前Activity處于豎屏,我們突然旋轉(zhuǎn)屏幕,由于系統(tǒng)配置發(fā)生了改變,在默認(rèn)情況下,Activity會被銷毀并且重新創(chuàng)建,當(dāng)然我們也可以阻止系統(tǒng)重新創(chuàng)建我們的Activity默認(rèn)情況下,如果我們的Activity不做特殊處理,那么當(dāng)系統(tǒng)配置發(fā)生改變之后,Activity就會銷毀并且重新創(chuàng)建,可以看圖當(dāng)系統(tǒng)配置發(fā)生改變的時候,Activity會被銷毀,其onPause,onStop,onDestroy均會被調(diào)用,同時由于Activity是異常情況下終止的,系統(tǒng)會調(diào)用onSaveInstanceState來保存當(dāng)前Activity的狀態(tài),這個方法調(diào)用的時機(jī)是在onStop之前
27、,他和onPause沒有既定的時序關(guān)系,他即可能在onPause之前調(diào)用,也有可能在之后調(diào)用,需要強(qiáng)調(diào)的是,這個方法只出現(xiàn)在Activity被異常終止的情況下,正常情況下是不會走這個方法的嗎,當(dāng)我們onSaveInstanceState保存到Bundler對象作為參數(shù)傳遞給onRestoreInstanceState和onCreate方法,因此我們可以通過onRestoreInstanceState和onCreate方法來判斷Activity是否被重建。如果被重建了,我們就取出之前的數(shù)據(jù)恢復(fù),從時序上來說,onRestoreInstanceState的調(diào)用時機(jī)應(yīng)該在onStart之后同時我們要
28、知道,在onSaveInstanceState和onRestoreInstanceState方法中,系統(tǒng)自動為我們做了一些恢復(fù)工作,當(dāng)Activity在異常情況下需要重新創(chuàng)建時,系統(tǒng)會默認(rèn)我們保存當(dāng)前的Activity視圖架構(gòu),并且為我們恢復(fù)這些數(shù)據(jù),比如文本框中用戶輸入的數(shù)據(jù),ListView滾動的位置,這些View相關(guān)的狀態(tài)系統(tǒng)都會默認(rèn)恢復(fù),具體針對某一個特定的View系統(tǒng)能為們恢復(fù)那些數(shù)據(jù)?我們可以查看View的源碼,和Activity一樣,每一個View都有onSaveInstanceState和onRestoreInstanceState這兩個方法,看一下他們的實現(xiàn),就能知道系統(tǒng)能夠
29、為每一個View恢復(fù)數(shù)據(jù)關(guān)于保存和恢復(fù)View的層次結(jié)構(gòu),系統(tǒng)的工作流程是這樣的:首先Activity被意外終止時,Activity會調(diào)用onSaveInstanceState去保存數(shù)據(jù),然后Activity會委托Window去保存數(shù)據(jù),接著Window再委托上面的頂級容器去保存數(shù)據(jù),頂級容器是一個ViewGroup,一般來說他可能是一個DecorView,最后頂層容器再去一一通知他的子元素來保存數(shù)據(jù),這樣整個數(shù)據(jù)保存過程就完成了,可以發(fā)現(xiàn),這是一種典型的委托思想,上層委托下層,父容器委托子容器,去處理一件事件,這種思想在Android 中有很多的應(yīng)用,這里就不再重復(fù)介紹了,接下來舉個例子,那
30、TextView來說,我們分析一下他到底保存了那些數(shù)據(jù) Override public Parcelable onSaveInstanceState() Parcelable superState = super.onSaveInstanceState(); / Save state if we are forced to boolean save = mFreezesText; int start = 0; int end = 0; if (mText != null) start = getSelectionStart(); end = getSelectionEnd(); if (sta
31、rt >= 0 | end >= 0) / Or save state if there is a selection save = true; if (save) SavedState ss = new SavedState(superState); / XXX Should also save the current scroll position! ss.selStart = start; ss.selEnd = end; if (mText instanceof Spanned) Spannable sp = new SpannableStringBuilder(mText
32、); if (mEditor != null) removeMisspelledSpans(sp); sp.removeSpan(mEditor.mSuggestionRangeSpan); ss.text = sp; else ss.text = mText.toString(); if (isFocused() && start >= 0 && end >= 0) ss.frozenWithFocus = true; ss.error = getError(); return ss; return superState; 從上述源碼中我們可以看到
33、,TextView為了保存自己的文本選中和文本結(jié)構(gòu)內(nèi)容,并且通過查看onRestoreInstanceState方法的源碼,可以發(fā)現(xiàn)它的確恢復(fù)了這些數(shù)據(jù),具體源碼就不在貼出,讀者可以自己去看下源碼,下面我們看來看下實際的例子,對比一下Activity正常終止和異常終止的不同,同時驗證一下系統(tǒng)的數(shù)據(jù)恢復(fù)能力,為了方便測試,我們采用了旋轉(zhuǎn)屏幕來終止Activity,在我們旋轉(zhuǎn)屏幕以后,Activity被銷毀重建,我們輸入的文本被正確還原了,說明我們的系統(tǒng)能夠正確的做一些View層的分析,我們看下代碼package com.liuguilin.activitysample;import androi
34、d.os.Bundle;import android.os.PersistableBundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;public class MainActivity extends AppCompatActivity public static final String TAG = "MainActivity" Override protected void onCreate(Bundle savedInstanceState) super.onCr
35、eate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) String test = savedInstanceState.getString("extra_test"); Log.i(TAG, test); Override public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) super.onSaveInstance
36、State(outState, outPersistentState); Log.i(TAG, "onSaveInstanceState"); outState.putString("extra_test", "test"); Override protected void onRestoreInstanceState(Bundle savedInstanceState) super.onRestoreInstanceState(savedInstanceState); String test = savedInstanceState
37、.getString("extra_test"); Log.i(TAG, test); 上面的代碼很簡單,首先我們在onSaveInstanceState中保存一個字符串,然后當(dāng)我們的Activity被銷毀并且重新創(chuàng)建之后,我們再去獲取之前存儲的字符串,接收的位置可以選擇onRestoreInstanceState或者onCreate,兩者的區(qū)別是:onRestoreInstanceState一旦被調(diào)用,其參數(shù)Bundler savedInstanceState一定有值,我們不用額外的判斷是否為空但是onCreate不行,onCreate如果正常啟動的話,其參數(shù)Bundle
38、r onSaveInstanceState為null,所以需要一些額外的判斷,這兩個方法我們選擇任意一個都是可以進(jìn)行數(shù)據(jù)恢復(fù)的,但是關(guān)鍵建議我們使用onRestoreInstanceState去恢復(fù)數(shù)據(jù)Activity銷毀后調(diào)用了onSaveInstanceState來保存數(shù)據(jù),重新創(chuàng)建以后再onCreate和onRestoreInstanceState中能恢復(fù)數(shù)據(jù),這個正好證明了我們剛才的分析,針對onSaveInstanceState我們有一點要說明,那就是系統(tǒng)只會在即將被銷毀并且有機(jī)會重新顯示的情況下才會去調(diào)用它,考慮到這一種情況,當(dāng)Activity正常銷毀的時候,系統(tǒng)不會調(diào)用onSav
39、eInstanceState,因為被銷毀的Activity不可能再次被顯示出來,這句話不好理解,但是我們可以對比一下旋轉(zhuǎn)屏幕所造成的Activity異常銷毀,這個過程和正常停止的Activity是不一樣的,因為旋轉(zhuǎn)屏幕之后,Activity被銷毀的同時會立即創(chuàng)建新的Activity實例,這個時候Activcity有機(jī)會再次立刻顯示,所以系統(tǒng)進(jìn)行了數(shù)據(jù)存儲,這里可以簡單的這么理解,系統(tǒng)只在Activity異常終止的情況下才會調(diào)用onSaveInstanceState和onRestoreInstanceState來存儲和恢復(fù)數(shù)據(jù),其他情況不會觸發(fā)2.情況2:資源內(nèi)存不足導(dǎo)致低優(yōu)先級的Activit
40、y被殺死這個情況我們不好模擬,但是其數(shù)據(jù)的存儲和恢復(fù)過程和情況一是一致的,這里我們描述一下Activity的優(yōu)先級情況,Activity按照優(yōu)先級的從高往低,可以分為三種:1.前臺Activity:正在和用戶交互的Activity,優(yōu)先級最高2.可見但非前臺Activity:比如對話框,導(dǎo)致Activity可見但是位于后臺無法和用戶直接交互3.后臺Activity:已經(jīng)被暫停的Activity,比如執(zhí)行了onStop,優(yōu)先級最低當(dāng)系統(tǒng)內(nèi)存不足的時候,系統(tǒng)就會按照上述優(yōu)先級去殺死目標(biāo)Activity所在的進(jìn)程,并且在后續(xù)通過onSaveInstanceState和onRestoreInstanc
41、eState來存儲和恢復(fù)數(shù)據(jù),如果一個進(jìn)程中沒有四大組件在執(zhí)行,那么這個進(jìn)程將很快被系統(tǒng)殺死,因此,一些后臺工作不適合脫離四大組建而獨立運行在后臺中,這樣進(jìn)程很容易就被殺死了,比較好的方法就是將后臺工作放在Service中從而保證了進(jìn)程有一定的喲徐愛你集,這樣就不會輕易的被殺死上面分析了系統(tǒng)的數(shù)據(jù)存儲和恢復(fù)機(jī)制,我們知道,當(dāng)系統(tǒng)配置發(fā)生改變后,Activity會被重新創(chuàng)建,那我們有沒有什么辦法不重新創(chuàng)建尼?答案是有的,接下來我們來分析一下這個問題,系統(tǒng)配置中有很多內(nèi)容,如果當(dāng)某項內(nèi)容發(fā)生改變后,我們不想系統(tǒng)重新創(chuàng)建,就可以給configChangs屬性加上orientation這個值andro
42、id:configChanges="orientation"如果想指定多個值的話可以用“|”連接起來mcc:The IMSI mobile country code (MCC) has changed a SIM has been detected and updated the MCC. IMSI(國際移動用戶識別碼)發(fā)生改變,檢測到SIM卡,或者更新MCCmnc:The IMSI mobile network code (MNC) has changed a SIM has been detected and updated the MNC. IMSI網(wǎng)絡(luò)發(fā)生改變,檢測
43、到SIM卡,或者更新MCC其中mcc和mnc理論上不可能發(fā)生變化locale:The locale has changed the user has selected a new language that text should be displayed in. 語言發(fā)生改變,用戶選擇了一個新的語言,文字應(yīng)該重新顯示touchscreen:The touchscreen has changed. (This should never normally happen.) 觸摸屏發(fā)生改變,這通常是不應(yīng)該發(fā)生的keyboard:The keyboard type has changed for e
44、xample, the user has plugged in an external keyboard. 鍵盤類型發(fā)生改變,例如,用戶使用了外部鍵盤keyboardHidden:The keyboard accessibility has changed for example, the user has revealed the hardware keyboard. 鍵盤發(fā)生改變,例如,用戶使用了硬件鍵盤navigation:The navigation type (trackball/dpad) has changed. (This should never normally happe
45、n.) 導(dǎo)航發(fā)生改變,(這通常不應(yīng)該發(fā)生) 舉例:連接藍(lán)牙鍵盤,連接后確實導(dǎo)致了navigation的類型發(fā)生變化。因為連接藍(lán)牙鍵盤后,我可以使用方向鍵來navigate了screenLayout:The screen layout has changed this might be caused by a different display being activated. 屏幕的布局發(fā)生改變,這可能導(dǎo)致激活不同的顯示ontScale:The font scaling factor has changed the user has selected a new global font siz
46、e. 全局字體大小縮放發(fā)生改變orientation:The screen orientation has changed that is, the user has rotated the device.設(shè)備旋轉(zhuǎn),橫向顯示和豎向顯示模式切換。screenSize: 屏幕大小改變了smallestScreenSize: 屏幕的物理大小改變了,如:連接到一個外部的屏幕上4.2增加了一個layoutDirection屬性,當(dāng)改變語言設(shè)置后,該屬性也會成newConfig中的一個mask位。所以ActivityManagerService(實際在ActivityStack)在決定是否重啟Activi
47、ty的時候總是判斷為重啟。 需要在android:configChanges 中同時添加locale和layoutDirection。 在不退出應(yīng)用的情況下切換到Settings里切換語言,發(fā)現(xiàn)該Activity還是重啟了。從上面的屬性中我們可以知道,如果我們沒有在Activity的configChanges中設(shè)備屬性的話,當(dāng)系統(tǒng)發(fā)生改變后就會導(dǎo)致Activity重新被創(chuàng)建,上面表格中的項目很多,但是我們常用的只有l(wèi)ocale,orientation,keyboardHidden這三個選項,其他用的還是比較少的,這里設(shè)置之后顯示的效果我就不演示了四.Activity的啟動模式Android的啟
48、動模式,是很有用的,對于Activity的棧的處理,也是極其講究的,所以你一定要清除他的標(biāo)志位和啟動模式一.Activity的LaunchMode首先說一下Activity為什么需要啟動模式,我們知道,在默認(rèn)的情況下,當(dāng)我們多次啟動同一個Activity的時候,系統(tǒng)會創(chuàng)建多個實例并把他們一一放入任務(wù)棧中,當(dāng)我們點擊back鍵的時候會發(fā)現(xiàn)這些Activity會一一回退,任務(wù)棧是一種先進(jìn)先出的棧結(jié)構(gòu),這個好理解, 每按一次back鍵就有一個activity退出棧,知道??諡橹?,當(dāng)這個棧為空的時候,系統(tǒng)就會回收這個任務(wù)棧,關(guān)于任務(wù)棧的系統(tǒng)工作原理,這里我們暫且不說,在后續(xù)章節(jié)也會介紹任務(wù)棧,知道了A
49、ctivity的啟動模式,我們可發(fā)現(xiàn)一個問題,:多次啟動同一個Activity會創(chuàng)建多個實例,這樣是不是很逗,Activity在設(shè)計的時候不可能不考慮到這個問題,所以他提供了啟動模式來修改系統(tǒng)的默認(rèn)行為,目前有四種啟動模式standardsingleTopsingleTasksingleInstance我們先來把這幾種啟動模式都給介紹完standard:標(biāo)準(zhǔn)模式,這也是系統(tǒng)的默認(rèn)模式,每次啟動一個Activity都會重新創(chuàng)建一個實例,是否這個實例已經(jīng)存在,被創(chuàng)建的實例的生命周期符合典型情況下Activity的生命周期,如上述:onCreate(),onStart();onResume()都會被
50、調(diào)用,這是一種典型的多實例實現(xiàn),一個任務(wù)棧都可以有多個實例,每個實例都可以屬于不同的任務(wù)棧,在這種模式下,誰啟動了這個Activity,那么這個Activity就運行在啟動它的Activity所在的棧內(nèi),比如Activity A啟動了Activity B(B是標(biāo)準(zhǔn)模式),那么B就會進(jìn)入到A所在的棧內(nèi),不知道讀者有沒有注意到,當(dāng)我們用ApplicationContext去啟動standard模式的Activity的時候就會報錯:E/AndroidRuntime(674): android.util.androidruntiomException: Calling startActivity fr
51、om outside of an Activity context requires the FLAG_ACTIVITY_TASK flag . Is this really what are want?11相信讀者對這句話不會陌生,這是因為我們的standard模式的Activity默認(rèn)會進(jìn)入啟動它的Activity所屬的任務(wù)棧中,但是由于非Activity類型的Context(如ApplicationContext)并沒有所謂的任務(wù)棧,所以這就有問題了,解決這個問題,就是待啟動Activity指定FLAG_ACTIVITY_TASK標(biāo)記位,這樣啟動的時候就會為他創(chuàng)建一個新的任務(wù)棧,這個時候
52、待啟動Activity實際上是以singleTask模式啟動的,讀者可以仔細(xì)體會singleTop:棧頂復(fù)用模式,在這個模式下,如果新的Activity已經(jīng)位于任務(wù)棧的棧頂,那么此Activity不會被重新創(chuàng)建,同時他的onNewIntent方法會被調(diào)用,通過此方法的參數(shù)我們可以取出當(dāng)前請求的信息,需要注意的是,這個Activity的onCreate,onStart不會被系統(tǒng)調(diào)用,因為他并沒有發(fā)生改變,如果新Activity已存在但不是在棧頂,那么新Activity則會重新創(chuàng)建,舉個例子,假設(shè)現(xiàn)在棧內(nèi)的情況為ABCD,其中ABCD為四個Activity,A位于棧底,D位于棧頂,這個時候假設(shè)要再
53、啟動D,如果D的啟動模式為singleTop,那么站棧內(nèi)的情況仍然是ABCD,如果D的啟動模式是standard,那么由于D會被重新創(chuàng)建,導(dǎo)致情況就是ABCDDsingTask:棧內(nèi)復(fù)用模式,這是一種單實例模式,在這種模式下,只要Activity在一個棧內(nèi)存在,那么多次啟動此Activity都不會創(chuàng)建實例,和singTop一樣,系統(tǒng)也會回調(diào)其onNewIntent方法,具體一點,當(dāng)一個具有singleTask模式的Activity請求啟動后,比如Activity A,系統(tǒng)首先會去尋找是否存在A想要的任務(wù)棧,如果不存在,就小紅心創(chuàng)建一個任務(wù)棧,然后創(chuàng)建A的實例把A放進(jìn)棧中,如果存在A所需要的棧,
54、這個時候就要看A是否在棧中有實例存在,如果實例存在,那么系統(tǒng)就會把A調(diào)到棧頂并調(diào)用它的onNewIntent方法,如果實例不存在,就創(chuàng)建A的實例并且把A壓入棧中,舉幾個例子比如目前任務(wù)棧S1中的情況為ABC,這個時候Activity D以singleTask模式請求啟動,其所需的任務(wù)棧為S2,由于S2和D的實例都不存在,所以系統(tǒng)會先創(chuàng)建任務(wù)棧S2,然后創(chuàng)建D的實例將其入棧到S2另外一種情況,假設(shè)D所需的任務(wù)棧為S1,其他情況如如上面的一樣,那么由于S1已經(jīng)存在,所以系統(tǒng)會直接創(chuàng)建D的實例并將其引入到S1中如果D所需要的任務(wù)棧為S1,并且當(dāng)前任務(wù)棧S1的情況為ABCD,根據(jù)棧內(nèi)復(fù)用的原則,此時D不會被重新創(chuàng)建,系統(tǒng)會把D切換到棧頂并且調(diào)用其oNnNewIntent方法,同時由于singleTask默認(rèn)具有clearTop的效果,會導(dǎo)致棧內(nèi)所有在D上面的Activity全部出棧,于是最終S1中的情況為AD,這一點比較特殊,在后面還會對此情況詳細(xì)的分析通過上述的三個例子,讀者應(yīng)該還是比較清晰的理解singTask的含義吧singleInstance:單實例模式,這是一種加強(qiáng)的singleTask的模式,他除了具有singleTask的所有屬性之外,還加強(qiáng)了一點,那就是具有此模式下的Activity只能單獨的處于一個任務(wù)棧中
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度供暖供氣設(shè)施施工安全協(xié)議
- 二零二五年度鋼材現(xiàn)貨交易居間服務(wù)協(xié)議
- 2025年度電子商務(wù)合伙拆伙協(xié)議終止協(xié)議
- 2025年度離職解除勞動合同模板:傳媒廣告行業(yè)員工離職流程
- 會計財務(wù)審計作業(yè)指導(dǎo)書
- 公司股權(quán)購買協(xié)議詳細(xì)版
- 金融服務(wù)個人風(fēng)險免責(zé)聲明
- 《數(shù)學(xué)思維訓(xùn)練課程:數(shù)形結(jié)合學(xué)習(xí)指導(dǎo)》
- 肉類銷售代理合同
- 關(guān)于項目進(jìn)度管理的解決方案
- 主持課課件教學(xué)課件
- 第四節(jié)-全電路歐姆定律
- 中學(xué)生的儀容儀表規(guī)范主題班會課件
- GB/T 44672-2024體外診斷醫(yī)療器械建立校準(zhǔn)品和人體樣品賦值計量溯源性的國際一致化方案的要求
- Unit 2 Bridging Cultures Reading for writing 課件-高中英語(2019)選擇性必修第二冊
- 2024年全國統(tǒng)一高考數(shù)學(xué)試卷(新高考Ⅰ)含答案
- 2024年河南省高考對口升學(xué)語文試卷及參考答案
- 司索工安全技術(shù)交底
- 解析:2023年廣西壯族自治區(qū)中考數(shù)學(xué)真題(原卷版)
- 爬模施工應(yīng)急處置措施
- 2024年越南高純碳化硅粉末行業(yè)現(xiàn)狀及前景分析2024-2030
評論
0/150
提交評論