天天看點

基礎篇-Activity解析一,Activity生命周期二.Fragment 碎片三.Activity的加載模式解析 四.Activity與Window,View的關系解析

一,Activity生命周期

基礎篇-Activity解析一,Activity生命周期二.Fragment 碎片三.Activity的加載模式解析 四.Activity與Window,View的關系解析

相信不少朋友也已經看過這個流程圖了,也基本了解了Activity生命周期的幾個過程,我們就來說一說一些常見操作的生命周期執行情況吧 (1) 啟動Activity:onCreate()->onStart()->onResume->Activity進入運作狀态 (2) 被其他Activity,視窗覆寫或鎖屏:onPause()->暫停目前Activity狀态 (3) 目前Activity由被覆寫狀态回到前台或解鎖屏: onResume()->再次進入運作狀态 (4) 目前Activity轉到新的Activity界面或按Home鍵回到主屏,自身退居背景:onPause()->onStop->不可見狀态 (5) 回退到不可見狀态的Activity: onRestart()->onStart()->onResume->再次進入運作狀态 (6) 目前Activity處于被覆寫狀态或者背景不可見狀态,即第2步和第4步,系統記憶體不足,殺死目前Activity,而後使用者退回目前Activity:onCreate()->onStart()->onResume()->進入運作狀态 (7) 使用者finish退出目前Activity:onPause()->onStop()->onDestory()->結束目前Activity

擴充一些:

1 . onWindowFocusChanged:在 Activity視窗獲得或失去焦點時被調用,在onResume與onPause後調用 onResume()-> onWindowFocusChanged()->運作狀态->onPause-> onWindowFocusChanged() 比如onCreate中Window對象沒有初始化完成,一些動态計算控件大小,動畫加載可能報錯,是以可以将加載相關的代碼放在這個方法中執行

2 . onSaveInstanceState與 onRestoreInstanceState: (1)在Activity被覆寫或退居背景之後,系統資源不足将其殺死, onSaveInstanceState 會被調用,回退到此Activity時,調用 onRestoreInstanceState (2)在使用者改變螢幕方向時, 系統先銷毀目前的Activity,然後再重建一個新的,調用此方法儲存一些臨時資料 ; (3)在目前Activity跳轉到其他Activity或者按Home鍵回到主屏,自身退居背景時,此方法會被調用。系統調用此方法是為了儲存目前視窗各個View元件的狀态.

儲存狀态時調用順序:運作狀态-> onSaveInstanceState()->onPause() 恢複狀态時調用順序:onStart()->onRestoreInstanceState()->onResume

3.onConfigurationChange():當指定了android:configChanges="orientation"後,方向改變時onConfigurationChanged被調用,可以setContentView(R.layout.orientation_landscape),設定Activity不同的xml布局檔案适配

二.Fragment 碎片

1.産生與介紹

為了讓界面可以在平闆上更好地展示,Android在3.0版本引入了Fragment(碎片)功能,它非常類似于Activity,可以像Activity一樣包含布局。Fragment通常是嵌套在Activity中使用的, 可以把Fragment當成Activity的一個界面的一個組成部分, Fragment擁有自己的生命周期和接收、處理使用者的事件,這樣就不必在Activity寫一堆控件的事件處理的代碼了。更為重要的是,你可以動态的添加、替換和移除某個Fragment.碎片化管理螢幕顯示的思路 比如,一個應用,其中2個頁面,listview清單顯示所有内容項FragmentA,對應詳情頁FragmentB,在豎屏時隻嵌入FragmentA,橫屏時,嵌入FragmentA與FragmentB,并列左邊清單,右邊詳情. 以及ViewPager+Fragment導航欄組合的應用首頁等

2.生命周期

基礎篇-Activity解析一,Activity生命周期二.Fragment 碎片三.Activity的加載模式解析 四.Activity與Window,View的關系解析

對比Activity的生命周期,可見Activity的回掉方法碎片中幾乎都有,碎片還提供了一些附加方法

  • onAttach() 當碎片和活動建立關聯的時候調用,add後, 在這個方法中可以獲得所在的activity,
  • onCreateView()為碎片建立視圖(加載布局)時調用
  • onActivityCreated()確定與碎片相關聯的活動一定已經建立完畢的時候調用
  • onDestroyView()當與碎片關聯的視圖被移除的時候調用
  • onDetach()當碎片和活動解除關聯的時候調用

(1).第一次加載螢幕: onAttach() -- onCreate()--- onCreateView()--onActivityCreated()--onStart()--onResume() (2)點選替換: onPause()--onStop()---onDestoryView() (如果替換的時候沒有調用addToBackStack()方法,此時onDestory()--onDetach()方法也會得到執行) (3) 當點選Back重新回到這個Frament界面:   o nCreateView ()--onStart()--onResume() (onCreate()和 onAttach ()并沒有執行,是以我們使用的addToBackStacck()方法使得Fragment沒有銷毀,與Activity解綁) (4)按下back時響應: onPause()--onStop()---onDestoryView()--onDestory()--onDetach()

動态添加碎片 主要有以下五個步驟:

  • 建立待添加碎片執行個體
  • 擷取到FragmentManager,在活動中可以直接調用getFragmentManager()方法得到
  • 開啟一個事務,FragmentTransaction transaction = fm.benginTransatcion();通過調用beginTransaction()方法開啟,保證Fragment操作的原子性
  • 向容器内加入碎片,一般使用transaction.replace()方法實作,就是remove和add合體,需要傳入容器的ID和待添加的碎片執行個體
  • transaction. add(),remove(),hide(),show(),detach(),attach()
  • 送出事物,調用commit()方法來完成

實用情景 a、比如:我在FragmentA中的EditText填了一些資料,當切換到FragmentB時,如果希望會到A還能看到資料,則适合你的就是hide和show;也就是說,希望保留使用者操作的面闆,你可以使用hide和show,當然了不要使勁在那new執行個體,進行下非null判斷。

b、再比如:我不希望保留使用者操作,你可以使用remove(),然後add();或者使用replace()這個和remove,add是相同的效果。

c、remove和detach有一點細微的差別,在不考慮回退棧的情況下,remove會銷毀整個Fragment執行個體,而detach則隻是銷毀其視圖結構,執行個體并不會被銷毀。那麼二者怎麼取舍使用呢?如果你的目前Activity一直存在,那麼在不希望保留使用者操作的時候,你可以優先使用detach

Fragment與Activity通信

因為所有的Fragment都是依附于Activity的,是以通信起來并不複雜,大概歸納為:

a、如果你Activity中包含自己管理的Fragment的引用,可以通過引用直接通路所有的Fragment的public方法

b、如果Activity中未儲存任何Fragment的引用,那麼沒關系,每個Fragment都有一個唯一的TAG或者ID,可以通過getFragmentManager.findFragmentByTag()或者findFragmentById()獲得任何Fragment執行個體,然後進行操作。

c、在Fragment中可以通過getActivity得到目前綁定的Activity的執行個體,然後進行操作。

使用DialogFragment來管理對話框,當旋轉螢幕和按下後退鍵時可以更好的管理其聲明周期,它和Fragment有着基本一緻的聲明周期。且DialogFragment也允許開發者把Dialog作為内嵌的元件進行重用,類似Fragment(可以在大螢幕和小螢幕顯示出不同的效果)

FragmentTransaction解析:

Fragment事務使得你可以執行一系列fragment操作,不幸的是,送出事務是異步的,而且是附加在主線程handler隊列尾部的。當你的app接收到多個點選事件或者配置發生變化時,将處于不可知的狀态。樓主就因為曾在複用DialogFragmeng視窗時,由于互動操作導緻并發觸發,雖然用DialogFragmeng.isAdded(),進行了過濾判斷,但是,還是會出現Fragmeng Already add異常,還無法捕捉,導緻未知的程式閃退.就是因為在判斷DialogFragmeng.isAdded()的時候,并發的DialogFragmeng事物送出的還在handler隊列裡面,未真正執行,而到了handler中,要執行的時候,Activity狀态未知對于,Fragment來說就很危險.是以在使用是,進行生命周期管理,要謹慎處理

提示:對于每個Fragment事務,你能夠在送出之前通過調用setTransition()方法,申請一個過渡動畫。

調用commit()方法并不立即執行這個事務,而是在Activity的UI線程之上(”main”線程)排程運作,以便這個線程能夠盡快執行這個事務。但是,如果需要,可以調用來自UI線程的executePendingTransactions()方法,直接執行被commit()方法送出的事務。通常直到事務依賴其他線程的工作時才需要這樣做。

警告: 你能夠使用commit()方法送出一個隻儲存之前Activity狀态的事務(在使用者離開Activity時)。如果試圖在使用者離開Activity之後送出,将會發生一個異常。這是因為如果Activity需要被恢複,而送出之後的狀态卻丢失了。這種情況下,使用commitAllowingStateLoss()方法,你丢失的送出就沒問題了。

三.Activity的加載模式解析

1.Activity stack 每個Activity的狀态是由它在Activity棧中的位置決定的。 Activity棧是一個後進先出LIFO,包含所有正在運作Activity的隊列

當一個新的Activity啟動時,目前的活動的Activity将會移到Activity棧的頂部。

如果使用者使用後退按鈕傳回的話,或者前台的Activity結束,在棧上的Activity将會移上來并變為活動狀态 一個應用程式的優先級是受最高優先級的Activity影響的。當決定某個應用程式是否要終結去釋放資源,Android記憶體管理使用棧來決定基于Activity的應用程式的優先級。

2.Activity狀态 

一般認為Activity有以下四種狀态:

活動的:當一個Activity在棧頂,它是可視的、有焦點、可接受使用者輸入的。Android試圖盡最大可能保持它活動狀态,殺死其它Activity來確定目前活動Activity有足夠的資源可使用。當另外一個Activity被激活,這個将會被暫停。 

暫停:在很多情況下,你的Activity可視但是它沒有焦點,換句話說它被暫停了。有可能原因是一個透明或者非全屏的Activity被激活。 

當被暫停,一個Activity仍會當成活動狀态,隻不過是不可以接受使用者輸入。在極特殊的情況下,Android将會殺死一個暫停的Activity來為活動的Activity提供充足的資源。當一個Activity變為完全隐藏,它将會變成停止。 

停止:當一個Activity不是可視的,它“停止”了。這個Activity将仍然在記憶體中儲存它所有的狀态和會員資訊。盡管如此,當其它地方需要記憶體時,它将是最有可能被釋放資源的。當一個Activity停止後,一個很重要的步驟是要儲存資料和目前UI狀态。一旦一個Activity退出或關閉了,它将變為待用狀态。  待用: 在一個Activity被殺死後和被裝在前,它是待用狀态的。待用Acitivity被移除Activity棧,并且需要在顯示和可用之前重新啟動它。

3.四種加載模式

Activity中特性launchMode的 四種加載模式解析: 标準,單頂(棧頂複用),單棧(單棧共享),單例(多棧共享)。

  • standard: 标準模式,一調用startActivity()方法就會産生一個新的執行個體。
  • singleTop: 如果已經有一個執行個體位于Activity棧的頂部時,就不産生新的執行個體,而隻是調用Activity中的newInstance()方法。如果不位于棧頂,會産生一個新的執行個體,。
  • singleTask: 會在一個新task的棧中産生這個執行個體,以後每次調用都會使用這個,不會去産生新的執行個體了,并且處于棧低,加入其它Activity,傳回自動彈出銷毀。
  • singleInstance: 這個跟singleTask基本上是一樣,會在一個新task的棧中産生這個執行個體.隻有一個差別:在這個模式下的Activity執行個體所處的task中,隻能有這個activity執行個體,不能有其他的執行個體, 是其所在棧的唯一activity,整個系統單例,任何task中調用,它會每次都被重用,多棧共用,2個應用調用顯示同一個Activity,第一個中退出,隻是把這個棧移開了,第二個退出時,這個activity棧才會退出。

在Android平台上可以将task簡單的了解為由多個Activity共同協作完成某項應用任務,而不管Activity具體屬于哪個Application,每一個Task有自己對應的 Activity Stack. Activity的加載模式受啟動Activity的Intent對象中設定的Flag和manifest檔案中Activity的<activity>元素的特性值互動控制。

下面是影響加載模式的一些特性

核心的Intent Flag有: 

FLAG_ACTIVITY_NEW_TASK 

FLAG_ACTIVITY_CLEAR_TOP 

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 

FLAG_ACTIVITY_SINGLE_TOP 

核心的<activity>特性有: 

taskAffinity 

launchMode 

allowTaskReparenting 

clearTaskOnLaunch 

alwaysRetainTaskState  finishOnTaskLaunc

加載模式便是決定以哪種方式啟動一個跳轉到某個Activity執行個體,各種加載模式差別在于下面幾點: (1)所屬task的差別 一般情況下,“standard”和”singleTop”的activity的目标task,和收到的Intent的發送者在同一個task内,就相當于誰調用它,它就跟誰在同一個Task中。 除非Intent包括參數FLAG_ACTIVITY_NEW_TASK。設定FLAG_ACTIVITY_NEW_TASK參數,會啟動到别的task裡。  “singleTask”和”singleInstance” 總是把要啟動的activity作為一個task的根元素,他們會被啟動到一個其他task裡。 (2)是否允許多個執行個體 “standard”和”singleTop”可以被執行個體化多次,并且是可以存在于不同的task中;這種執行個體化時一個task可以包括一個activity的多個執行個體; 

“singleTask”和”singleInstance”則限制隻生成一個執行個體,并且是task的根元素。  singleTop 要求如果建立intent的時候棧頂已經有要建立的Activity的執行個體,則将intent發送給該執行個體,而不建立新的執行個體。   (3)是否允許其它activity存在于本task内 “singleInstance”獨占一個task,其它activity不能存在那個task裡; 即便此Activity又啟動了一個新的activity,不管新的activity的launch mode 如何,新的activity都将會到别的task裡運作(如同加了FLAG_ACTIVITY_NEW_TASK參數)。 而另外三種模式,則可以和其它activity共存。 (4)是否每次都生成新執行個體 “standard”對于每一個啟動Intent都會生成一個activity的新執行個體;  “singleTop”的activity如果在task的棧頂的話,則不生成新的該activity的執行個體,直接使用棧頂的執行個體,否則,生成該activity的執行個體。 “singleInstance”是其所在棧的唯一activity,所有task共享,它會每次都被重用。 “singleTask”  如果不存在,則在新task中生成執行個體,存在即複用,彈出該task棧中其他activity 。

四.Activity與Window,View的關系解析

Android系統中的所有UI類都是建立在View和ViewGroup這兩個類的基礎上的。所有View的子類成為”Widget”,所有ViewGroup的子類成為”Layout”。View和ViewGroup之間采用了組合設計模式,可以使得“部分-整體”同等對待。ViewGroup作為布局容器類的最上層,布局容器裡面又可以有View和ViewGroup。LayoutInfalter就是用來生成View的一個工具,XML布局檔案就是用來生成View的原料 LayoutInflater是一個用來執行個體化XML布局檔案為View對象的類 LayoutInflater.infalte(R.layout.test,null)用來從指定的XML資源中填充一個新的View

Activity構造的時候隻能初始化一個Window(PhoneWindow),另外這個PhoneWindow有一個”DecorView”,是主視窗中頂級view,這個”DecorView”是一個ViewGroup,是最初始的根視圖,之後不斷重疊ad view,removeview管理,放到window顯示窗, 還可以onCreater中設定視窗,顯示屬性,比如設定無标題,全屏等。

getWindow().setContentView(LayoutInflater.from(this).inflate(R.layout.main, null)),

public void setContentView(View view,ViewGroup.LayoutParams params) {

        if (mContentParent == null) {

            installDecor();

        } else {

            mContentParent.removeAllViews();

        }

        mContentParent.addView(view, params);

        final Callback cb = getCallback();

        if (cb != null) {

           cb.onContentChanged();  //視窗類容發生變化時更新

        }

    }

繼續閱讀