Android Activity使用拾遺

來源:互聯網
上載者:User

標籤:

一、onWindowFocusChanged

  有時我們需要測量一個Activity多長時間才能顯示出來,那麼在代碼中打點計時的時機選在哪兒呢?在onCreate和onResume執行完成後,Activity的介面仍不可見,在onResume之後,framework還會回調一個叫onWindowFocusChanged的函數,它表示使用者是否已經可以與Activity的介面進行互動了。onWindowFocusChanged為true意味著Activity的介面已經能夠被使用者看到了(自然也能和使用者互動了)。實際上activity變為visible的時間點出現在onWindowFocusChanged之前,但是這個狀態只能在ActivityManagerService中擷取,在用戶端還是只能通過onWindowFocusChanged作為介面可見或不可見的標誌。

  在介面變為不可見時,先調用onPause,然後再是onWindowFocusChanged為false。這也容易理解,onPause本來就是Activity被部分遮住時調用的,調用完onPause後才會讓介面不能與使用者繼續互動。

  如果想加快Activity的啟動時間,把在onCreate裡一些耗時操作挪到onResume裡,有時會發現並沒有什麼變化,所以如果要想先讓Activity的介面儘快展現給使用者還是得把這些邏輯放在onWindowFocusChanged變為true之後執行。

 

二、onUserLeaveHint

  這個回呼函數主要用來監聽按Home鍵退出到案頭的動作,發生在onPause之前。在啟動一個新的Activity時,ActivityStackSupervisor裡會調用startActivityUncheckedLocked,在它裡面會給mUserLeaving賦值。mUserLeaving用於指示當前activity退到後台時函數onUserLeaving是否被調用。

 

 

  可見,只有當設定了FLAG_ACTIVITY_NO_USER_ACTION標誌時mUserLeaving才會為false,其他情況下mUserLeaving均為true,也就是onUserLeaveHint會被調用,注釋裡也說了onUserLeaveHint會在onPause之前被調用。

 

 

三、taskAffinity

  task是一組用來處理某一任務的Activity的集合,位於一個回退棧內,當新啟動一個應用時framework就會建立一個新的task來承載相應的Activity。taskAffinity用來描述Activity的親和性,即Activity屬於哪個task。如果在AndroidManifest.xml的application中沒顯式定義taskAffinity,那麼預設的affinity名字就是包名。同一affinity的Activity會被放在同一task裡,task的affinity名字由根Activity的taskAffinity決定,如果根Activity沒設taskAffinity屬性,則affinity就由application的affinity決定。

  如果taskAffinity設為空白字串,那說明該Activity和其他的task都不存在親和性。不同應用的Activity也可以設定相同的affinity,這樣當啟動後它們就會位於同一task中。 

四、launchMode

1. standard

  預設的launchMode,可以執行個體化多次。

2.singleTop

  使用這種launchMode的情況是,如果要啟動的Activity已經在棧的最頂端,那麼startActivity時不再會重新調用它的onCreate,而是調用它的onNewIntent。但如果要啟動的Activity不在棧頂,比如A –> B à C,這時C再啟動B,就會再執行個體化一個新的B,棧裡面變成A à Bà C à B。

  如果A中點擊一個button來啟動B,但系統反應慢,使用者在極短的時間內點了兩次,如果是B是standard,則會有兩個B,如果是singleTop則只會有一個。更典型的情境是使用者使用外賣App支付了一筆訂單後,從支付頁面返回到訂單詳情頁面,如果訂單的狀態有發生變化,比如商家接單了,這時通知欄會有通知,點擊通知會跳入訂單詳情頁面。如果此時訂單詳情頁面是standard的話,那麼使用者按back鍵後發現還是在訂單詳情頁面,體驗就很差了。如果是singleTop,只需在onNewIntent裡更新狀態資訊,就可以顯示出最新的資訊,而不必再新建立一個相同的Activity了。

3.singleTask

  以這種模式啟動的Activity,如果在task中已經存在該Activity的執行個體,就調用它的onNewIntent方法,進入該task中。如果沒有該Activity的執行個體,就建立一個新的task,把該Activity作為新task的根Activity。所以以singleTask啟動的Activity不一定會新建立一個task。需要注意的是,即使Activity位於新的task裡,按back鍵仍然會回到啟動它的上一個Activity中,雖然它們不在同一個task裡。

  如果singleTask的Activity的taskAffinity和現有task的affinity相同,那就直接在現有的task裡建立該Activity,所以以singleTask啟動的Activity未必就是位於棧底的根Activity。

4.singleInstance

  以這種模式啟動的Activity自己獨佔一個task,如果已經有該Activity的執行個體,再次啟動時會調它的onNewIntent。但以singleInstance啟動的Activity按back的行為卻與singleTask不同。比如 A啟動B,B是singleInstance,B再啟動C,則B自己單獨位於一個新的task中,A和C位於一個task中,則按back鍵時,從C不會退回到B,而是先退回到A,再按back鍵再退回到B。

  注意,在代碼中也可以設定Intent的flag來控制Activity的啟動模式,代碼中動態設定的比AndroidManifest.xml中靜態寫的Android:lauchMode優先順序高。 

 

五、Intent的flags

1.FLAG_ACTIVITY_NEW_TASK

  為Activity新建立一個task,如果startActivity的context不是Activity,而是service或Application,那一定要加上這個flag。以這個flag啟動Activity的行為跟launchMode為singleTask的一致。但並不是每次都新建立一個task,把Activity放在裡面,而是會先找是否已經有taskAffinity相同的task,如果有就把要啟動Activity放在該task裡,如果沒有taskAffinity相同的task,才會建立一個task。

2.FLAG_ACTIVITY_SINGLE_TOP

  作用同singleTop。

3.FLAG_ACTIVITY_CLEAR_TOP

  啟動Activity時,如果所在task裡已經有該Activity的執行個體,則會清除在它上面所有的Activity。例如,task裡的Activity啟動關係是Aà Bà Cà D,然後在D啟動B時,加上了FLAG_ACTIVITY_CLEAR_TOP標誌,在B啟動後task裡就只有A和B了,C和D被清除了。如果B的launchMode是standard,那麼當它收到Intent後,會先銷毀掉原來B的執行個體,然後重新onCreate構建一個新的B;如果B是singleTask類型,那麼會保留原有的B的執行個體,調用它的onNewIntent,傳入新的Intent。

4.FLAG_ACTIVITY_CLEAR_TASK

  啟動Activity時,會清除所在task裡其他所有的Activity。例如,task裡的Activity啟動關係是A à Bà C,在B啟動C時,加上FLAG_ACTIVITY_CLEAR_TASK,那麼在C啟動後,task裡就只剩C了,A、B被清除了。如果這個應用中只有這一個task,那麼在C中按back鍵就退回到案頭了。

5.FLAG_ACTIVITY_REORDER_TO_FRONT

  以該標誌啟動的Activity如果已經在task中存在,會被移動到棧頂,其他的Activity順序不變。如果在task中不存在,則建立一個。例如,task裡的Activity啟動關係是A ->B ->C->D,在D啟動B時,加上這個flag,則B就被移到了棧頂,task裡就變成了A ->C ->D -> B了。如果B已經調了finish,但系統還沒來得及把它從task中移出,這時以FLAG_ACTIVITY_REORDER_TO_FRONT方式啟動B,則無法啟動B。只有當B destroy以後才可以啟動B。

6.FLAG_ACTIVITY_NO_HISTORY

  這個FLAG可以讓啟動的Activity一旦退出,就finish掉,不再存在於棧中。例如,Activity的啟動關係是A-> C->D,在B啟動C時加上FLAG_ACTIVITY_NO_HISTORY,在C啟動完D後,task裡仍然是 A-> B->C->D的棧布局,C並沒從棧中清除。當在D中按back鍵,不會退到C而是退到B,這時dumpsysactivity會發現task中沒有C了,只有A和B,在D中按back鍵時,C就finish掉了。

7.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

  以這個flag啟動的Activity將不會在最近啟動的應用列表中出現。

8.FLAG_ACTIVITY_FORWARD_RESULT

  我們用startActivityForResult和setResult在兩個Activity之間傳遞資料,如果中間還隔著另一個Activity,比如A -> B->C,要想在A和C之間用startActivityForResult和setResult的話,就要在B啟動C時加上這個參數。也就是A正常的startActivityForResult啟動B,B以FLAG_ACTIVITY_FORWARD_RESULT方式啟動C,在C中setResult,這樣當從C退回B,再退回到A,即C和B都finish後,A的onActivityResult會收到C中setResult傳的值。

9.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY

  這個是從最近工作清單中啟動Activity時由系統設定的,第三方應用不會用到這個標誌,系統的SystemUI在最近工作清單中才會設這個標誌。

10.FLAG_ACTIVITY_NO_ANIMATION

  要啟動Activity將不執行入場動畫。

11.FLAG_ACTIVITY_TASK_ON_HOME

  以這個flag啟動的Activity所在的task將會位於Home所在的task之上,也就是說在這個Activity中按back鍵會回到home,而不是啟動它的那個Activity。例如,A -> B,B的taskAffinity與A不同,A啟動B時同時加上了FLAG_ACTIVITY_TASK_ON_HOME和FLAG_ACTIVITY_NEW_TASK這兩個標誌,那麼A和B位於不同的task中,如果僅是以newtask方式啟動B,那麼即使B和A不在一個task中,那麼在B中按back鍵還是會退到A的,但加上了FLAG_ACTIVITY_TASK_ON_HOME後,按back鍵就退回到home了,此時A已經被移動到了後台。 

      嵌入式企鵝圈原創團隊由阿里、魅族、nvidia、龍芯、炬力、拓爾思等資深工程師組成。百分百原創,每周兩篇,分享嵌入式、Linux、物聯網、GPU、Android、自動駕駛等技術。歡迎掃碼關注公眾號:嵌入式企鵝圈,即時推送原創文章!

Android Activity使用拾遺

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.