Android開發藝術探索--第一章生命週期和啓動方式總結(2)

最近在拜讀任主席的Android開發藝術探索,現在看了一半,再回頭看前面的,感覺跟沒有看一樣,所以還是把知識點總結一下吧

Actvity的LaunchMode

  這節來講一下Activity的啓動方式,Activity有四種啓動方式:standard、singleTop、singleTask、singleInstance。在默認情況下,多次啓動同一個Activity的時候,系統會創建多個實例並把他們一一放入任務棧中,單擊back鍵,這些Activity會一一回退。下面介紹一下這四種啓動模式:

  • standard:標準模式,也是系統默認模式。每次啓動不管是否存在都會新建一個實例,一個任務棧中可以有多個實例,每個實例也可以屬於不同的任務棧。誰啓動的Activity,這個Activity就運行在它的那個Activity所在的棧中。這裏有一條需要注意的,當我們用ApplicationContext去啓動standard模式的Activity時會報錯:

    calling startActivity from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag.Is this really what you want?

    這是因爲standard模式的Activity默認會進入啓動它的Activity所屬的任務棧中,但是由於非Activity類型的Context並沒有任務棧,所以就報錯了。解決這個問題的方式是在Intent中addFlag–FLAG_ACTIVITY_NEW_TASK,這個時候的Activity是以singleTask模式啓動的,放在一個新的任務棧中(這個問題碰到過幾次,以前只知道要加上flag,但是沒有仔細想過爲什麼,現在看到這塊就豁然開朗了)

  • singleTop:棧頂複用模式。如果此模式的Activity當前位於任務棧的棧頂,那麼再啓動此Activity的時候不會重新創建, 但是會調用它的onNewIntent方法,此方法相當有用,如果此Activity不在棧頂,那麼這時會再次創建實例
  • singleTask:棧內複用模式。這是一種單實例模式,在這種模式下,只要當前任務棧中有目標Activity,那麼該Acticity不會被重新創建,同時它的onNewIntent方法會被回調,如果該Activity不在棧頂,則系統會把該Activity之上的元素全部退棧,此時該Activity調到棧頂。
  • singleInstance:單例模式,這是一種加強的singleTask模式,除了具有singleTask模式的所有特性之外,還加強了一點,具有此模式的Activity只能單獨位於一個任務棧,並且此棧中只有此一個Activity

這裏有一個參數需要說明一下TaskAffinity,這個參數標識了一個Activity歸屬哪個任務棧,默認情況下所有Avtivity所需要的任務棧的名字是包名,通過這個參數可以指定,這個參數通過配合singTask啓動模式或者allowTaskReparenting屬性配對使用,在其他情況下沒有意義。具體說明看這篇博客android當中taskAffinity屬性與launchMode相關。

再來說一下常用的幾個Activity的Flags:

  • FLAG_ACTIVITY_NEW_TASK:指定singleTask啓動模式,效果和XML中指定相同
  • FLAG_ACTIVITY_SINGLE_TOP:指定singleTop模式,效果和XML中指定相同
  • FLAG_ACTIVITY_CLEAR_TOP:當此標記位的Activity啓動時,在同一個任務棧中所有位於它上面的Activity都要出棧,這個標記位一般會和singleTask啓動模式一起出現,在這種情況下,被啓動的Activity如果已經存在,那麼系統就會調用它的onNewIntent。如果被啓動的Activity採用standard模式,那麼它連同它之上的Activity都要出棧,再重新創建新的Activity實例並放入棧頂。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有這個標記的Activity不會出現在歷史Activity的列表中,當某些情況下我們不希望用戶通過歷史列表回到我們的Activity的時候這個標記比較有用。

IntentFilter的匹配原則

  啓動Activity的方式有兩種:顯示調用和隱式調用。顯示調用就不多說了,來說一說隱式調用,隱式調用需要Intent能夠匹配目標組件的IntentFilter中所設置的過濾信息。IntentFilter中的過濾信息有action、category、data,下面是一個過濾規則的示例:

<intent-filter>
    <action android:name="com.wpp.action"/>
    <category android:name="com.wpp.category"/>
    <data android:name="com.wpp.data"/>
</intent-filter>

  爲了匹配過濾列表,需要同時匹配過濾列表中的action、category、data信息,否則匹配失敗,一個過濾列表中的action、category、data可以有多個,只有完全匹配activity才能啓動成功,另外,一個activity中可以有多個intent-filter,一個Intent只要能匹配任何一組intent-filter即可匹配成功。
  下面詳細分析各種屬性的匹配規則
  1. action的匹配規則
  action是個字符串,系統預定義了一些action,同時我們可以在應用中定義自己的action。action的匹配規則是Intent中的action必須能夠和過濾規則中的action匹配,即字符串值完全一樣,一個過濾規則中可以有多個action,只要任何一個action相同即可匹配成功。 如果Intent中沒有指定action則匹配失敗,注意,action區分大小寫!
  2.category的匹配規則
  category也是字符串,跟action一樣,系統有預定義的,我們也可以在應用中自定義。匹配規則和action不同,它要求Intent中如果含有category,則intent中所有的category都必須和一組intent-filter中的任何一個category完全匹配,如果沒有category也可以匹配成功,但是一旦有category,不管幾個,都必須和intent-filter中任何一個category匹配。爲什麼不設置category也可以匹配成功呢?因爲系統在startActivity的時候會默認加上”android.intent.category.DEFAULT”這個category,爲了我們的activity能夠接收隱式調用,就必須在intent-filter中指定這個category
  3.data的匹配規則
  先了解一下data的結構:

<data android:scheme="string"
    android:host="string"
    android:port="string"
    android:path="string"
    android:pathPattern="string"
    android:pathPrefix="string"
    android:mimeType="string"/>

data由兩部分組成,mimeType和URI,mimeType指媒體類型,比如image/jpeg、audio/mpeg4-generic和video/*等,可以表示圖片、文本、視頻等不同的媒體格式,而URI的結構:

<scheme>://<host>:<port>/[path]|[pathPattern]|[pathPrefix]
比如:http://www.baidu.com:80/search/info
  • Scheme:URI的模式,比如http、file、content等,如果URI中沒有指定scheme,那麼URI無效
  • Host:URI的主機名,如果Host沒有指定,那麼整個URI無效
  • Port:URI中的端口號,比如80,僅當URI指定了scheme和host參數的時候port參數纔是有意義的
  • Path、pathPattern、pathPrefix:這三個參數表述路徑信息,其中path表示完整的路徑信息;pathPattern也表示完整的路徑信息,但是它裏面包含通配符”*”,表示0個或任意字符。由於正則表達式的規範,如果想表示真實的字符串,”*”要寫成”\\*”,”\”要寫成”\\\\”;path表示路徑的前綴信息。

再講一下匹配規則:
(1)如下過濾規則

<intent-filter>
    <data android:mimtType="image/*"/>
    ……
</intent-filter>

這種規則制定了媒體類型爲所有類型的圖標,那麼Intent中的mimeType屬性必須爲”image/*”才能匹配,這種清下雖然過濾規則中沒有指定URI,但是卻有默認值,URI的默認值爲content和file,示例比如:

intent.setDataAndType(Uri.parse("file://abc"),"image/png")

如果要爲Intent指定完整的data,必須要調用setDataAndType方法,不能分開調用,因爲setData和setType會彼此清除對方的值
(2)如下過濾規則

<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" ···/>
    <data android:mimeType="audio/mpeg" android:scheme="http" ···>
    ···
</intent-filter>

這種規則指定了兩組data規則,且每個data都指定了完整的屬性值,既有URI,又有mimeType,示例如下:

intent.setDataAndType(Uri.pase("http://abc"),"video/mpeg")
或者
intent.setDataAndType(Uri.parse("http://abc"),"audio/mpeg")

IntentFilter的過濾規則已經講完了,這裏有個地方需要注意一下,如果通過隱式調用來啓動activity,當intent匹配不到activity的時候會報錯,提示無法找到activity,所以通常情況下,當我們需要通過隱式調用來啓動一個activity時,需要先做一下判斷,方法有兩種:通過PackageManager的resolveActivity或者Intent的resolveActivity方法,如果找不到匹配的Activity就會返回null,我們再來做處理就能避免activity找不到的錯誤了。另外,PackageManager還提供了queryIntentActivities方法,這個方法返回所有匹配的Activity信息。

public abstract List<ResolveInfo> queryIntentActivities(Intent intent, int flags);

public abstract ResolveInfo resolveActivity(Intent intent, int flags);

第二個參數要使用MATCH_DEFAULT_ONLY這個標記位,這個標記位含義是僅僅匹配那些在intent-filter中聲明瞭DEFAULT這個category的Activity,使用這個標記位只要上面兩個不返回null,那麼startActivity一定成功。在action和category中,有一類action和category比較重要,

<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>

二者同時作用來標記一個入口activity。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章