摘要:,表明執(zhí)行操作的字符串。,這個屬性可以指示系統(tǒng)如何啟動一個,以及啟動之后如何處理。是一個字符串,例如這里的的構(gòu)造函數(shù)傳入了兩個參數(shù),和組件名,調(diào)用了方法后,會在當前的應用中啟動這個服務。
1. 前言
? ? ? ?在Android中有四大組件,這些組件中有三個組件與Intent相關,可見Intent在Android整個生態(tài)中的地位高度。Intent是信息的載體,用它可以去請求組件做相應的操作,但是相對于這個功能,Intent本身的結(jié)構(gòu)更值得我們?nèi)パ芯俊?/p> 2. Intent與組件
? ? ? ?Intent促進了組件之間的交互,這對于開發(fā)者非常重要,而且它還能做為消息的載體,去指導組件做出相應的行為,也就是說Intent可以攜帶數(shù)據(jù),傳遞給Activity/Service/BroadcastReceiver。
啟動Activity。Activity可以簡單的理解為手機屏幕中的一個頁面,你可以通過將Intent傳入startActivity方法來啟動一個Activity的實例,也就是一個頁面,同時,Intent也可以攜帶數(shù)據(jù),傳遞給新的Activity。如果想要獲取新建的Activity執(zhí)行結(jié)果,可以通過onActivityResult()方法去啟動Activity。
啟動Service。Service是一個不呈現(xiàn)交互畫面的后臺執(zhí)行操作組件,可以通過將Intent穿入startService()方法來啟動一個Service來啟動服務。
傳遞廣播BroadCast。廣播是任何應用都可以接收到的消息,通過將Intent傳遞給 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast()方法,可以將廣播傳遞接收方。
3. Intent類型在Android中,Intent分為兩種類型,顯式和隱式。
顯式Intent,可以通過類名來找到相應的組件,在應用中用顯式Intent去啟動一個組件,通常是因為我們知道這個組件(Activity或者Service)的名字。如下代碼,我們知道具體的Activity的名字,要啟動一個新的Activity,下面就是用的顯示Intent。
Intent intent = new Intent(context,XXActivity.class); startActivity(intent);
隱式Intent,不指定具體的組件,但是它會聲明將要執(zhí)行的操作,從而匹配到相應的組件。最簡單的Android中調(diào)用系統(tǒng)撥號頁面準備打電話的操作,就是隱式Intent。
Intent intent = new Intent(Intent.ACTION_DIAL); Uri data = Uri.parse("tel:" + "135xxxxxxxx"); intent.setData(data); startActivity(intent);
使用顯示Intent去啟動Activity或者Service的時候,系統(tǒng)將會立即啟動Intent對象中指定的組件。
? ? ? ?使用隱式Intent的時候,系統(tǒng)通過將Intent對象中的IntentFilter與組件在AndroidManifest.xml或者代碼中動態(tài)聲明的IntentFilter進行比較,從而找到要啟動的相應組件。如果組件的IntentFilter與Intent中的IntentFilter正好匹配,系統(tǒng)就會啟動該組件,并把Intent傳遞給它。如果有多個組件同時匹配到了,系統(tǒng)則會彈出一個選擇框,讓用戶選擇使用哪個應用去處理這個Intent,比如有時候點擊一個網(wǎng)頁鏈接,會彈出多個應用,讓用戶選擇用哪個瀏覽器去打開該鏈接,就是這種情況。
? ? ? ?IntentFilter通常是定義在AndroidManifest.xml文件中,也可以動態(tài)設置,通常是用來聲明組件想要接受哪種Intent。例如,你如果為一個Activity設置了IntentFilter,你就可以在應用內(nèi)或者其他應用中,用特定的隱式Intent來啟動這個Activity,如果沒有為Activity設置IntentFilter,那么你就只能通過顯示Intent來啟動這個Activity。
4. Intent的屬性注意,為了確保系統(tǒng)的穩(wěn)定性,官方建議使用顯示Intent來啟動Service,同時也不要為Service設置IntentFilter,因為如果使用隱式Intent去啟動Service,我們并不知道那些服務會響應Intent,而且由于服務大多是不可見的,我們也不知道那些服務被啟動了,這是非常危險的。在Android 5.0(API 21)以后,如果使用隱式的Intent去調(diào)用bindService()方法,系統(tǒng)會拋出異常。
? ? ? ?Intent作為消息的載體,系統(tǒng)根據(jù)它去決定啟動哪個具體的組件同時將組件執(zhí)行中需要的信息傳遞過去。Intent能夠包含的屬性有Component、Action、Data、Category、Extras、Flags,關于這些屬性的更詳細信息可查看這里。
Component,要啟動的組件名稱。這個屬性是可選的,但它是顯式Intent的一個重要屬性,設置了這個屬性后,該Intent只能被傳遞給由Component定義的組件。隱式Intent是沒有該屬性的,系統(tǒng)是根據(jù)其他的信息(例如,Action、Data等)來判斷該Intent應該傳遞給哪個組件。這個屬性是目標的組件的具體名稱(完全限定類名),例如,com.example.DemoActivity。該屬性可以通過setComonentName()、setClass()、setClassName()或者Intent的構(gòu)造函數(shù)來設置。
Action,表明執(zhí)行操作的字符串。它會影響Intent的其余信息,比如Data、Extras。該屬性可以通過setAction()方法或者Intent的構(gòu)造函數(shù)來設置。用戶可以自定義這個屬性,也可以使用系統(tǒng)中已經(jīng)有的Action值。下面列出啟動Activity時候的一些通用Action屬性。
ACTION_VIEW,當有一些信息需要展示出來,可以設置Intent的Action為這個值,并調(diào)用startActivity()方法
ACTION_SEND,當用戶有一些信息需要分享到其他應用,可以設置Intent的Action為這個值,并調(diào)用startActivity()方法
ACTION_DIAL,撥打電話,可以設置Intent的Action為這個值,并調(diào)用startActivity()方法
ACTION_EDIT,編輯某些文件,可以設置Intent的Action為這個值,并調(diào)用startActivity()方法
Data,它是待操作數(shù)據(jù)的引用URI或者數(shù)據(jù)MIME類型的URI,它的值通常與Intent的Action有關聯(lián)。比如,如果設置Action的值為ACTION_EDIT,那么Data的值就必須包含被編輯文檔的URI。當我們創(chuàng)建Intent的時候,設置MIME類型非常重要。例如,一個可以顯示圖片的Activity可能不能播放音頻,圖片和音頻的URI非常類似,如果我們設置了MIME類型,可以幫助系統(tǒng)找到最合適的組件接受Intent。有時候,MIME類型也可以從URI判斷出來,例如當Data是一個包含content:字符串的URI時候,可以明確的知道,待處理的數(shù)據(jù)存在設備中,而且由ContentProvider控制。
使用setData()方法設置數(shù)據(jù)引用的URI,使用setType()方法設置數(shù)據(jù)的MIME類型,使用setDataAndType()方法同時設置這兩個屬性。
注意:如果想要設置兩個的屬性,直接用setDataAndType()方法,不要同時調(diào)用setData()和setType()方法,因為這兩個方法設置的值會相互覆蓋
public Intent setData(Uri data) { mData = data; mType = null; return this; } public Intent setType(String type) { mData = null; mType = type; return this; }
Category,這個屬性是對處理該Intent組件信息的補充。它是一個ArraySet類型的容器,所以可以向里面添加任意數(shù)量的補充信息,同時,Intent沒有設置這個屬性不會影響解析組件信息。可以通過addCategory()方法來設置該屬性。下面列出一些常用的Category的值。
CATEGORY_BROWSABLE,設置Category為該值后,在網(wǎng)頁上點擊圖片或鏈接時,系統(tǒng)會考慮將此目標Activity列入可選列表,供用戶選擇以打開圖片或鏈接。
CATEGORY_LAUNCHER,應用啟動的初始Activity,這個Activity會被添加到系統(tǒng)啟動launcher當中。
以上列出的這些關于Intent的屬性(Component、Action、Data、Category)可以幫助系統(tǒng)來確定具體的組件,但是有一些Intent的屬性,不會影響到組件的確定。
Extras,以key-value鍵值對的形式來存儲組件執(zhí)行操作過程中需要的額外信息,可以調(diào)用putExtra()方法來設置該屬性,這個方法接受兩個參數(shù),一個是key,一個是value。也可以通過實例化一個儲存額外信息的Bundle對象,然后調(diào)用putExtras()方法將我們實例化的Bundle添加到Intent中。
Flags,這個屬性可以指示系統(tǒng)如何啟動一個Activity,以及啟動之后如何處理。例如Activity屬于哪一個task(參考Activity的四種啟動方式)。
5. 顯式Intent示例? ? ? ?上文說到,顯式Intent是用于啟動某個特定的組件(Activity或者Service)的Intent,穿創(chuàng)建顯式的Intent的時候需要設置組件名稱(Component)屬性,其他的屬性都是可選屬性。
// fileUrl是一個URL字符串,例如 "http://www.example.com/image.png" Intent downloadIntent = new Intent(context, DownloadService.class); downloadIntent.setData(Uri.parse(fileUrl)); startService(downloadIntent);
這里的Intent的構(gòu)造函數(shù)傳入了兩個參數(shù),context和組件名(Component),調(diào)用了startService()方法后,會在當前的應用中啟動DownloadService這個服務。
顯示Intent中設置的組件名(Component)需要在AndroidManifest.xml進行注冊,所以它一般用來啟動當前應用內(nèi)的組件。
? ? ? ?隱式Intent比顯示的Intent會復雜一些,它既可以啟動當前應用內(nèi)的組件,也可以啟動當前應用外的組件。如果當前應用無法處理隱式Intent,但是其他應用中的組件可以處理,那么系統(tǒng)會彈框讓用戶選擇啟動哪個應用中的組件。
? ? ? ?例如,如果用戶有內(nèi)容想分享給其他應用,就創(chuàng)建一個Intent,將它的Action屬性設置為ACTION_SEND,然后將要分享的內(nèi)容設置到Extras屬性中,然后調(diào)用startActivity()方法,用戶就可以選擇將內(nèi)容分享到哪一個應用。
注意,如果沒有任何應用能處理用戶發(fā)送的隱形Intent,調(diào)用組件失敗,應用可能會崩潰。調(diào)用resolveActivity()方法可以確認是否有Activity能夠處理這個Intent,如果返回為非空,那么至少有一個組件能夠處理這個Intent,調(diào)用startActivity()就很安全了;如果返回的是空(null),那么說明沒有組件能夠處理這個Intent,這個時候就不應該使用這個隱式的Intent了。
// 要將textMessage信息分享出去 Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // 確認是否有組件能夠處理這個隱式Intent if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(sendIntent); }
? ? ? ?調(diào)用startActivity()傳入一個隱式Intent時候,系統(tǒng)會檢查設備中所有的應用,確定哪些應用可以處理這個隱式的Intent(含有startActivity()操作并攜帶text/plain類型的Intent),如果只有一個應用可以處理這個Intent,那么直接喚起這個應用,并將Intent傳給它;如果有多個應用可以處理這個Intent,那么系統(tǒng)會彈出一個選擇框,讓用戶選擇喚起哪個應用。
7. 強制喚起選擇框? ? ? ?上文說了,如果多個應用可以處理同一個隱式Intent,系統(tǒng)會彈出選擇框,讓用戶選擇喚起哪個應用,并設置該應用為默認的打開方式,以后就不會彈出選擇框了。如果用戶希望以后一直使用該用戶處理這個隱式Intent(比如打開網(wǎng)頁,用戶通常會傾向于使用同一個web瀏覽器),那么十分方便。
? ? ? ?但是如果用戶想每一次都用不同的應用去處理這個隱式的Intent的,就應該每次彈出選擇框,用戶可以在選擇框中選擇喚起的應用,但是無法設置默認的打開方式。例如,當用戶想根據(jù)當前的位置將內(nèi)容分享到不同的應用,所以每次都需要彈出選擇框。
用戶需要通過Intent.createChooser()創(chuàng)建一個Intent,然后調(diào)用startActivity()。
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // 分享的標題 String title = getResources().getString(R.string.chooser_title); // 創(chuàng)建一個調(diào)用選擇框的Intent Intent chooser = Intent.createChooser(sendIntent, title); // 確認是否有應用可以處理這個Intent if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }8. 接受隱式Intent
? ? ? ?想配置你的應用可以處理哪些隱式的Intent,需要在AndroidManifest.xml文件中使用
? ? ? ?組件應該為為一個它可以處理的操作多帶帶設置一個處理器。例如,相冊中的Activity可能有兩個過濾器,一個過濾器對應瀏覽照片的操作,另一個過濾器對應編輯照片的操作。當這個Activity被啟動的時候,根據(jù)Intent中攜帶的信息來決定執(zhí)行哪種操作。
? ? ? ?每一個過濾器是在AndroidManifest.xml使用
,使用一個或者多個數(shù)據(jù)URI(scheme、host、port、path等等)和數(shù)據(jù)的MIME類型來指定接受的數(shù)據(jù)類型
? ? ? ?Activity組件要接受隱式Intent,它必須有一個
例如,以下代碼聲明了一個Activity組件,這個組件可以處理action屬性為ACTION_SEND,數(shù)據(jù)類型是文本(text/plain)的隱式Intent。
用戶也可以創(chuàng)建一個包含多個
如果是根據(jù)
系統(tǒng)會以這三個屬性將隱式Intent與所有組件聲明的過濾器進行對比,如果這三個屬性全部能夠匹配上,系統(tǒng)才有可能將這個隱式Intent傳遞給這個組件,因為如果多個應用的組件都能匹配上會彈出選擇框,讓用戶選擇一個應用去處理這個隱式Intent。
為了避免無意中啟動了其他的Service,所以在應用內(nèi),建議一直使用顯示的Intent去啟動服務,這樣就不必再AndroidManifest.xml文件中為Service聲明過濾器了。
對于Activity的過濾器,必須在AndroidManifest.xml文件中聲明,也可以不聲明,直接使用顯示Intent喚起Activity組件。
廣播接收器的過濾器聲明可以在AndroidManifest.xml文件中聲明,也可以使用registerReceiver()方法動態(tài)注冊,使用完畢后,使用unregisterReceiver()方法動態(tài)注銷。
9. 過濾器聲明示例下面一些過濾器的聲明能夠幫助你更好的理解。
第一個名為MainActivity的組件,是應用的啟動入口頁面,當用戶點擊應用圖標,該Activity會被啟動。
android.intent.action.MAIN,表示該Activity是應用的啟動入口,且不需要任何Intent攜帶的數(shù)據(jù)。
android.intent.category.LAUNCHER,表示將該Activity的圖標設為手機主屏幕上的應用圖標,如果它沒有圖標,就用Application的圖標。
第二個名為ShareActivity的組件,能夠處理兩種隱式Intent,可以接受文本和媒體內(nèi)容的分享操作,也就是說如果一個隱式Intent能夠匹配到任意一個過濾器都可以喚起該Activity。當然,也可以直接通過顯示Intent指定啟動它。
9. PendingIntentPendingIntent是對Intent的一種封裝。它主要作用在于,讓外部的應用執(zhí)行內(nèi)部的Intent時候,就好像是在你的應用中還行一樣。
通常在以下場景中會使用PendingIntent。
當用戶點擊通知欄時候,才執(zhí)行的Intent(系統(tǒng)的NotificationManager執(zhí)行的Intent),詳情參考這里
當用戶操作懸浮在主屏幕中的小工具,才執(zhí)行的Intent(主屏幕應用執(zhí)行的Intent),詳情參考這里
在未來某一個特定時間執(zhí)行的Intent(系統(tǒng)的AlarmManager執(zhí)行的Intent)
因為每一個Intent對象都是針對具體的組件類別(Activity/Service/BroadcastReceiver)進行實例化,因此在創(chuàng)建PendingIntent的時候,也要基于相同的因素去實例化,使用以下方法實例化PendingIntent。
PendingIntent.getActivity(),返回一個適用于Activity組件的PendingIntent
PendingIntent.getService(),返回一個適用于Service組件的PendingIntent
PendingIntent.getBroadcast(),返回一個適用于BroadcastReceiver的PendingIntent
當然官方還有一些其他獲取PendingIntent對象的方法,不過內(nèi)部也是使用上面三個方法來獲取實例化對象的。
這三個方法都需要當前應用的context,需要封裝的Intent,以及一個或者多個該如何使用該Intent的標志(例如,是否可以多次使用該Intent)。
關于Pending的具體使用也不再這里展開,需要了解具體使用的可以查看Notification中PendingIntent的使用和懸浮工具欄中PendingIntent的使用
10. Intent匹配規(guī)則? ? ? ?上文中提到了,當發(fā)送一個隱式Intent后,系統(tǒng)會將它與設備中的每一個組件的過濾器進行匹配,匹配屬性有Action、Category、Data三個,需要這三個屬性都匹配成功才能喚起相應的組件。
10.1 Action匹配規(guī)則一個過濾器可以不聲明Action屬性也可以聲明多個Action屬性。如下:
...
隱式Intent中的Action屬性,與組件中的某一個過濾器的Action能夠匹配(如果一個過濾器聲明了多個Action屬性,只需要匹配其中一個就行),那么就算是匹配成功。
如果過濾器沒有聲明Action屬性,那么只有沒有設置Action屬性的隱式Intent才能匹配成功。
10.2 Category匹配規(guī)則一個過濾器可以不聲明Category屬性也可以聲明多個Category屬性,如下:
...
? ? ? ?隱式Intent中聲明的Category必須全部能夠與某一個過濾器中的Category匹配才算匹配成功。比如說一個Category屬性設為CATEGORY_BROWSABLE的隱式Intent也可以通過上面的過濾器,也就是說,過濾器的Category屬性內(nèi)容必須是大于或者等于隱式Intent的Category屬性時候,隱式Intent才能匹配成功。
如果一個隱式Intent沒有設置Category屬性,那么它可以通過任何一個過濾器的Category匹配。
10.3 Data匹配規(guī)則一個過濾器可以不聲明Data屬性也可以聲明多個Data屬性,如下:
...
每個Data屬性都可以指定數(shù)據(jù)的URI結(jié)構(gòu)和數(shù)據(jù)MIME類型。URI包括scheme、host、port 和path四個部分,host和port合起來也成authority(host:port)部分。
:// : /
例如:
content://192.168.0.1:8080/folder/subfolder/etc
在這個URI中,scheme是content,host是192.168.0.1,port是8080,path是folder/subfolder/etc。我們平時使用的網(wǎng)絡url就是這種格式。
在URI中,每個組成部分都是可選的,但是有線性的依賴關系
如果沒有scheme部分,那么host部分會被忽略
如果沒有host部分,那么port部分會被忽略
如果host部分和port部分都沒有,那么path部分會被忽略
當進行URI匹配時候,并不是比較全部,而是局部對比,以下是URI匹配規(guī)則。
如果一個URI僅聲明了scheme部分,那么所有擁有與其相同的scheme的URI都會通過匹配,其他部分不做匹配
如果一個URI聲明了scheme部分和authority部分,那么擁有與其相同scheme和authority的URI才能匹配成功,path部分不做匹配
如果一個URI所有的部分都聲明了,那么只有所有部分都相同的URI才能匹配成功
注意:path部分可以使用通配符(*),也就是path其中的一部分進行匹配。
Data匹配時候,MIME類型和URI兩者都會進行匹配,匹配規(guī)則如下:
如果過濾器未聲明URI和MIME類型,則只有不含URI和MIME類型的隱形Intent才能匹配成功
如果過濾器中聲明URI但是未聲明MIME類型(也不能從URI中分析出MIME類型),則只有URI與過濾器URI相同且不包含IME類型的隱式Intent才能匹配成功
如果過濾器聲明MIME類型但是未聲明URI,只有包含相同MIME類型但是不包含URI的隱式Intent才能匹配成功
如果過濾器聲明了URI和MIME類型(既可以是直接設置,也可以是從URI分析出來),只有包含相同的URI和MIME類型的隱式Intent才能匹配成功
11. 其他注意:進行匹配時候必須以過濾器為單位進行匹配,不能跨過濾器匹配。如果一個過濾器聲明了多個Action、Category、Data,隱式Intent包含的Action、Category、Data都能在過濾器中匹配到相應的屬性即可,也就是說過濾器中聲明的屬性是大于或者等于Intent中包含的屬性,Intent才能匹配成功
? ? ? ?系統(tǒng)通過過濾器去匹配Intent,啟動相應組件,在PackageManager類中提供了一系列的查詢(queryIntentActivities()/queryIntentServices()/queryBroadcastReceivers())方法去查詢可以處理某個Intent的組件,也提供了一系列的解析(resolveActivity()/resolveService())方法來確定最佳啟動組件。這些方法在某些場景下是非常有用的,也可以幫助我們降低程序crash風險。
12. 思考? ? ? ?上文中對Intent以及IntentFilter進行了詳細的講解,大多都是系統(tǒng)級別的處理過程。但是Intent作為一個官方已經(jīng)封裝好的信息攜帶者,我們可以用它來做很多事情。比如可以寫自己的一套匹配規(guī)則,Intent僅僅作為數(shù)據(jù)攜帶者,通過它去傳遞一些信息,實現(xiàn)Fragment/Activity的頁面跳轉(zhuǎn)邏輯。關于Intent的使用,我相信還有更多的用處,需要用戶一步一步的去探索。
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70545.html
摘要:消息處理的方法也只能限定于和,分別代表四種線程模型。如果使用事件處理函數(shù)指定了線程模型為,那么無論事件在哪個線程發(fā)布,該事件處理函數(shù)都會在新建的子線程中執(zhí)行。分別使用上面四個方法訂閱同一事件,打印他們運行所在的線程。 前言:EventBus出來已經(jīng)有一段時間了,github上面也有很多開源項目中使用了EventBus。所以抽空學習順便整理了一下。目前EventBus最新版本是3.0,所...
閱讀 870·2021-11-22 09:34
閱讀 1003·2021-10-08 10:16
閱讀 1816·2021-07-25 21:42
閱讀 1790·2019-08-30 15:53
閱讀 3519·2019-08-30 13:08
閱讀 2174·2019-08-29 17:30
閱讀 3342·2019-08-29 17:22
閱讀 2173·2019-08-29 15:35