編輯:初級開發
1.Intents and Intent Filters
1.Intent Objects Intent對象
2.Intent Resolution Intent解析
1.Intent filters
3.Filters and security Filter和安全
1.Common cases 常見情況
2.Using intent matching 使用intent匹配
4.Note Pad Example 例子:記事本
Intents and Intent Filters
三種應用程序基本組件——activity, service和broadcast receiver——是使用稱為intent的消息來激活的。Intent消息傳遞是一種組件間運行時綁定的機制. intent是Intent對象, 它包含了需要做的操作的描述, 或者, 對於廣播來說, 包含了正在通知的消息內容. 對於向這三種組件發送intent有不同的機制:
•使用Context.startActivity() 或 Activity.startActivityForResult(), 傳入一個intent來啟動一個activity. 使用 Activity.setResult(), 傳入一個intent來從activity中返回結果.
•將intent對象傳給Context.startService()來啟動一個service或者傳消息給一個運行的service. 將intent對象傳給 Context.bindService()來綁定一個service.
•將intent對象傳給 Context.sendBroadcast(), Context.sendOrderedBroadcast(),或者Context.sendStickyBroadcast()等廣播方法,則它們被傳給 broadcast receiver.
在上述三種情況下, android系統會自己找到合適的activity, service, 或者 broadcast receivers來響應intent. 三者的intent相互獨立互不干擾.
Intent Objects Intent對象
一個intent對象包含了接受該intent的組件的信息(例如需要的動作和該動作需要的數據)和android系統所需要的信息(例如該組件的類別,以及如何啟動它). 具體的說:
組件名稱
為一個ComponentName 對象. 它是目標組件的完整名(例如"com.example.project.app.FreneticActivity")和應用程序manifest文件設定的包名(例如"com.example.project")的組合.前者的包名部分和後者不一定一樣.
組件名稱是可選的. 如果設定了的話, Intent對象會被傳給指定的類的一個實例. 如果不設定, 則android使用其它信息來定位合適的目標.
組件名稱是使用setComponent(), setClass(),或 setClassName()來設定, 使用 getComponent()來獲取.
Action
一個字符串, 為請求的動作命名, 或者, 對於broadcast intent, 發生的並且正在被報告的動作. 例如:
常量 目標組件
動作
ACTION_CALL activity 發起一個電話呼叫.
ACTION_EDIT activity 顯示數據給用戶來編輯.
ACTION_MAIN activity 將該activity作為一個task的第一個activity啟動,不傳入參數也不期望返回值.
ACTION_SYNC activity 將設備上的數據和一個服務器同步.
ACTION_BATTERY_LOW broadcast receiver 發出電量不足的警告.
ACTION_HEADSET_PLUG broadcast receiver 一個耳機正被插入或者拔出.
ACTION_SCREEN_ON broadcast receiver 屏幕被點亮.
ACTION_TIMEZONE_CHANGED broadcast receiver 時區設置改變.
你也可以定義自己的action字符串用來啟動你的應用程序. 自定義的action應該包含應用程序的包名.例如"com.example.project.SHOW_COLOR".
action很大程度上決定了intent的另外部分的結構, 就像一個方法名決定了它接受的參數和返回值一樣. 因此, 最好給action一個最能反映其作用的名字.
一個intent對象中的action是使用getAction()和setAction()來讀寫的.
Data
需要操作的數據的URI和它的MIME(多用途互聯網郵件擴展,Multipurpose Internet Mail Extensions)類型. 例如, 如果action為ACTION_EDIT, 那麼Data將包含待編輯的數據URI. 如果action為ACTION_CALL, Data將為tel:電話號碼的URI. 如果action為ACTION_VIEW, 則Data為http:網絡地址的URI.
當將一個intent和一個組件相匹配時, 除了URI外數據類型也很重要. 例如, 一個顯示圖片的程序不應該用來處理聲音文件.
數據類型常常可以從URI推斷, 特別是content:URI, 它表示該數據屬於一個content provider. 但數據類型也可以被intent對象顯示聲明. setData()方法設置URI, 而setType()方法指定MIME類型, setDataAndType()設置數據URI和MIME類型. 它們可以使用getData()和getType()來讀取.
Category
一個字符串,包含了關於處理該intent的組件的種類的信息. 一個intent對象可以有任意個category. intent類定義了許多category常數, 例如:
常量 含義
CATEGORY_BROWSABLE 目標activity可以使用浏覽器來顯示-例如圖片或電子郵件消息.
CATEGORY_GADGET 該activity可以被包含在另外一個裝載小工具的activity中.
CATEGORY_HOME 該activity顯示主屏幕,也就是用戶按下Home鍵看到的界面.
CATEGORY_LAUNCHER 該activity可以作為一個任務的第一個activity,並且列在應用程序啟動器中.
CATEGORY_PREFERENCE 該activity是一個選項面板.
addCategory()方法為一個intent對象增加一個category, removeCategory刪除一個category, getCategorIEs()獲取intent所有的category.
Extras
為鍵-值對形式的附加信息. 例如ACTION_TIMEZONE_CHANGED的intent有一個"time-zone"附加信息來指明新的時區, 而ACTION_HEADSET_PLUG有一個"state"附加信息來指示耳機是被插入還是被拔出.
intent對象有一系列put...()和set...()方法來設定和獲取附加信息. 這些方法和Bundle對象很像. 事實上附加信息可以使用putExtras()和getExtras()作為Bundle來讀和寫.
Flags
各種標志. 很多標志指示android系統如何啟動一個activity(例如該activity屬於哪個任務)和啟動後如何處理它(例如, 它是否屬於最近activity列表中).
android系統和應用程序使用intent對象來送出系統廣播和激活系統定義的組件.
Intent Resolution Intent解析
intent有兩種:
•顯式intent使用名字來指定目標組件. 由於組件名稱一般不會被其它開發者所熟知, 這種intent一般用於應用程序內部消息-- 例如一個activity啟動一個附屬的service或者另一個activity.
•隱式intent不指定目標的名稱. 一般用於啟動其它應用程序的組件.
android將顯式intent發送給指定的類. intent對象中名字唯一決定接受intent的對象.
對於隱式intent, android系統必須找到最合適的組件來處理它. 它比較intent的內容和intent filter. intent filter是組件的一個相關結構, 表示其接受intent的能力. android系統根據intent filter打開可以接受intent的組件. 如果一個組件沒有intent filter, 那麼它只能接受顯式intent. 如果有, 則能同時接受二者.
當一個intent和intent filter比較時, 只考慮三個屬性: action, data, category.
extra和flag在intent解析中沒有用.
Intent filters
activity, service和broadcast receiver可以有多個intent filter來告知系統它們能接受什麼樣的隱式intent. intent filter的名字很形象: 它過濾掉不想接受的intent, 留下想接受的intent. 顯式intent無視intent filter.
一個組件對能做的每件事有單獨的filter. 例如, 記事本程序的NoteEditor activity有兩個filter -- 一個啟動並顯示一個特定的記錄給用戶查看或編輯, 另一個啟動一個空的記錄給用戶編輯.
Filters and security Filter和安全
一個intent filter不一定安全可靠. 一個應用程序可以讓它的某個組件去接受隱式intent, 但是它沒法防止這個組件接受顯示intent. 其它的程序總是可以使用自定義的數據加上顯式的程序名稱來調用該組件.
一個intent filter是IntentFilter類的實例, 但是它一般不出現在代碼中,而是出現在android Manifest文件中, 以<intent-filter>的形式. (有一個例外是broadcast receiver的intent filter是使用 Context.registerReceiver()來動態設定的, 其intent filter也是在代碼中創建的.)
一個filter有action, data, category等字段. 一個隱式intent為了能被某個intent filter接受, 必須通過3個測試. 一個intent為了被某個組件接受, 則必須通過它所有的intent filter中的一個.
Action 測試
--------------------------------------------------------------------------------
<intent-filter . . . >
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
. . .
</intent-filter>
--------------------------------------------------------------------------------
一個intent對象只能指定一個action, 而一個intent filter可以指定多個action. action列表不能為空, 否則它將組織所有的intent.
一個intent對象的action必須和intent filter中的某一個action匹配, 才能通過.
如果intent filter的action列表為空, 則不通過.
如果intent對象不指定action, 並且intent filter的action列表不為空, 則通過.
Category 測試
--------------------------------------------------------------------------------
<intent-filter . . . >
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
. . .
</intent-filter>
--------------------------------------------------------------------------------
注意前面說到的對於action和category的常數是在代碼中用的,而不是manifest文件中用的. 例如, CATEGORY_BROWSABLE常數對應XML中的表示為"android.intent.category.BROWSABLE".
一個intent要通過category測試, 那麼該intent對象中的每個category都必須和filter中的某一個匹配.
理論上來說, 一個intent對象如果沒有指定category的話, 它應該能通過任意的category 測試. 有一個例外: android把所有的傳給startActivity()的隱式intent看做至少有一個category: "android.intent.category.DEFAULT". 因此, 想要接受隱式intent的activity必須在intent filter中加入"android.intent.category.DEFAULT". ("android.intent.action.MAIN" 和"android.intent.category.LAUNCHER"的intent filter例外. 它們不需要"android.intent.category.DEFAULT".)
Data test
--------------------------------------------------------------------------------
<intent-filter . . . >
<data android:mimeType="video/mpeg" android:scheme="http" . . . />
<data android:mimeType="audio/mpeg" android:scheme="http" . . . />
. . .
</intent-filter>
--------------------------------------------------------------------------------
每個<data>元素指定了一個URI和一個數據類型. URI每個部分為不同的屬性 -- scheme, host, port, path:
scheme://host:port/path
例如, 在如下的URI中:
content://com.example.project:200/folder/subfolder/etc
scheme為"content", host為"com.example.project", port為"200", path為"folder/subfolder/etc". host和port一起組成了URI authority. 如果host未指定,則port被忽略.
這些屬性都是可選的,但它們並非相互獨立: 要使一個authority有意義,必須指定一個scheme. 要使一個path有意義, 必須指定一個scheme和一個authority.
當intent對象中的URI和intent filter中相比較時, 它只和filter中定義了的部分比較. 例如, 如果filter中之定義了scheme,那麼所有包含該scheme的URI的intent對象都通過測試.對於path來說,可以使用通配符來進行部分匹配.
<data>元素的type屬性指定了數據類型. 它在filter中比在URI中更常見. intent對象和filter都可以使用"*"通配符作為子類型. 例如"text/*" "audio/*"表示所有的子類型都匹配.
data測試的規則如下:
1.一個不含uri也不含數據類型的intent對象只通過兩者都不包含的filter.
2.一個含uri但不含數據類型的intent對象(並且不能從uri推斷數據類型的)只能通過這樣的filter: uri匹配, 並且不指定類型. 這種情況限於類似mailto:和tel:這樣的不指定實際數據的uri.
3.一個只包含數據類型但不包含URI的intent只通過這樣的filter: 該filter只列出相同的數據類型, 並且不指定uri.
4.一個既包含uri又包含數據類型的intent對象只通過這樣的filter: intent對象的數據類型和filter中的一個類型匹配, intent對象的uri要麼和filter的uri匹配, 要麼intent對象的uri為content:或者file:, 並且filter不指定uri.
如果一個intent可以通過多於一個activity或者service的filter, 那麼用戶可能會被詢問需要啟動哪一個. 如果一個都沒有的話, 那麼會拋出異常.
Common cases 常見情況
上述的最後一個規則(d)說明了組件通常可以從文件和content provider中獲取數據. 因此, 它們的filter可以只列出數據類型不列scheme. 這是個特殊情況. 下列<data>元素告訴android該組件可以從一個content provider取得圖像數據並顯示之:
--------------------------------------------------------------------------------
<data android:mimeType="image/*" />
--------------------------------------------------------------------------------
由於大部分可用的數據由content provider提供, 指定數據類型但不指定uri的filter是最常見的情況.
另外一個常見的配置是filter具有一個scheme和一個數據類型. 例如, 下列<data>元素告訴android該component可以從網絡獲取圖像數據並顯示之:
--------------------------------------------------------------------------------
<data android:scheme="http" android:type="video/*" />
--------------------------------------------------------------------------------
考慮用戶點擊一個網頁時浏覽器的動作. 它首先試圖顯示這個數據(當做一個Html頁來處理). 如果無法顯示, 則創建一個隱式intent, 並啟動一個可以處理它的activity. 如果沒有這樣的activity, 那麼它請求下載管理器來下載該數據. 然後它將數據置於一個content provider的控制之下, 這樣有很多activity(擁有只有數據類型的filter)可以處理這些數據.
大部分應用程序還有一種方法來單獨啟動, 不需要引用任何特定的數據. 這些能啟動應用程序的activity具有action為"android.intent.action.MAIN" 的filter. 如果它們需要在應用程序啟動器中顯示, 它們必須指定"android.intent.category.LAUNCHER" 的category.
--------------------------------------------------------------------------------
<intent-filter . . . >
<action android:name="code android.intent.action.MAIN" />
<category android:name="code android.intent.category.LAUNCHER" />
</intent-filter>
--------------------------------------------------------------------------------
Using intent matching 使用intent匹配
intent和intent filter相匹配, 不僅為了尋找並啟動一個目標組件, 也是為了尋找設備上組件的信息. 例如, android系統啟動了應用程序啟動器, 該程序位於屏幕的頂層, 顯示了用戶可以啟動的程序, 這是通過查找設備上所有的action為"android.intent.action.MAIN" ,category為"android.intent.category.LAUNCHER"的intent filter所在的activity實現的. 然後它顯示了這些activity的圖標和標題. 類似的, 它通過尋找 "android.intent.category.HOME"的filter來定位主屏幕程序.
應用程序可以用相同的方式來使用intent匹配. PackageManager 有一組query...()方法來尋找接受某個特定intent的所有組件, 還有一系列resolve...()方法來決定響應一個intent的最佳組件. 例如, queryIntentActivitIEs()返回一個activity列表, 這些activity可以執行傳入的intent. 類似的還有queryIntentServices()和queryIntentBroadcastReceivers().
Note Pad Example 例子:記事本
記事本示例程序讓用戶可以浏覽一個筆記列表, 查看, 編輯, 刪除和增加筆記. 這一節關注該程序定義的intent filter.
在其manifest文件中, 記事本程序定義了三個activity, 每個有至少一個intent filter. 它還定義了一個content provider來管理筆記數據. manifest 文件如下:
--------------------------------------------------------------------------------
<manifest XMLns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.notepad">
<application android:icon="@drawable/app_notes"
android:label="@string/app_name" >
<provider android:name="NotePadProvider"
android:authoritIEs="com.google.provider.NotePad" />
<activity android:name="NotesList" android:label="@string/title_notes_list">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
</activity>
<activity android:name="NoteEditor"
android:theme="@android:style/Theme.Light"
android:label="@string/title_note" >
<intent-filter android:label="@string/resolve_edit">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="com.android.notepad.action.EDIT_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.INSERT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>
</activity>
<activity android:name="TitleEditor"
android:label="@string/title_edit_title"
android:theme="@android:style/Theme.Dialog">
<intent-filter android:label="@string/resolve_title">
<action android:name="com.android.notepad.action.EDIT_TITLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
</activity>
</application>
</manifest>
--------------------------------------------------------------------------------
第一個activity, NoteList, 和其它activity不同, 因為它操作一個筆記的目錄(筆記列表), 而不是一個單獨的筆記. 它一般作為該程序的初始界面. 它可以做以下三件事:
1.
--------------------------------------------------------------------------------
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
--------------------------------------------------------------------------------
該filter聲明了記事本應用程序的主入口. 標准的MAIN action是一個不需要任何其它信息(例如數據等)的程序入口, LAUNCHER category表示該入口應該在應用程序啟動器中列出.
2.
--------------------------------------------------------------------------------
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>
--------------------------------------------------------------------------------
該filter聲明了改activity可以對一個筆記目錄做的事情. 它允許用戶查看或編輯該目錄(使用VIEW和EDIT action), 或者選取特定的筆記(使用PICK action).
<data>元素的mimeType指定了這些action可以操作的數據類型. 它表明該activity可以從一個持有記事本數據的content provider(vnd.google.note)取得一個或多個數據項的Cursor(vnd.android.cursor.dir).
注意該filter提供了一個DEFAULT category. 這是因為 Context.startActivity() 和 Activity.startActivityForResult()方法將所有的intent都作為作為包含了DEFAULT category來處理, 只有兩個例外:
1.顯式指明目標activity名稱的intent.
2.包含MAIN action 和LAUNCHER category的intent.
因此, 除了MAIN和LAUNCHER的filter之外, DEFAULT category是必須的.
3.
--------------------------------------------------------------------------------
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
--------------------------------------------------------------------------------
這個filter描述了該activity能夠在不需要知道目錄的情況下返回用戶選擇的一個筆記的能力. GET_CONTENT action和PICK action相類似. 在這兩者中, activity都返回用戶選擇的筆記的URI. (返回給調用startActivityForResult()來啟動NoteList activity的activity.) 在這裡, 調用者指定了用戶選擇的數據類型而不是數據的目錄.
這個數據類型, vnd.android.cursor.item/vnd.google.note, 表示了該activity可以返回的數據類型 -- 一個筆記的URI. 從返回的URI, 調用者可以從持有筆記數據的content provider(vnd.google.note)得到一個項目(vnd.android.cursor.item)的Cursor.
也就是說, 對於PICK來說, 數據類型表示activity可以給用戶顯式的數據類型.對於GET_CONTENT filter, 它表示activity可以返回給調用者的數據類型.
下列intent可以被NoteList activity接受:
action: android.intent.action.MAIN
不指定任何數據直接啟動activity.
action: android.intent.action.MAIN
category: android.intent.category.LAUNCHER
不指定任何數據直接啟動activity. 這是程序啟動器使用的intent. 所有使用該組合的filter的activity被加到啟動器中.
action: android.intent.action.VIEW
data: content://com.google.provider.NotePad/notes
要求activity顯示一個筆記列表,這個列表位於content://com.google.provider.NotePad/notes. 用戶可以浏覽這個列表並獲取列表項的信息.
action: android.intent.action.PICK
data: content://com.google.provider.NotePad/notes
請求activity顯示content://com.google.provider.NotePad/notes下的筆記列表. 用戶可以選取一個筆記, activity將返回筆記的URI給啟動NoteList的activity.
action: android.intent.action.GET_CONTENT
data type: vnd.android.cursor.item/vnd.google.note
請求activity提供記事本數據的一項.
第二個activity, NoteEditor, 為用戶顯示一個筆記並允許他們編輯它. 它可以做以下兩件事:
1.
--------------------------------------------------------------------------------
<intent-filter android:label="@string/resolve_edit">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="com.android.notepad.action.EDIT_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
--------------------------------------------------------------------------------
這個activity的主要目的是使用戶編輯一個筆記--VIEW或者EDIT一個筆記. (在category中,EDIT_NOTE是EDIT的同義詞.) intent包含匹配MIME類型vnd.android.cursor.item/vnd.google.note的URI--也就是某一個特定的筆記的URI. 它一般來說是NoteList activity中的PICK或者GET_CONTENT action返回的.
像以前一樣,該filter列出了DEFAULT category.
2.
--------------------------------------------------------------------------------
<intent-filter>
<action android:name="android.intent.action.INSERT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>
--------------------------------------------------------------------------------
該activity的第二個目的是使用戶能夠創建一個新的筆記, 並插入到已存在的筆記目錄中. 該intent包含了匹配vnd.android.cursor.dir/vnd.google.note的URI, 也就是筆
有了這些能力, NoteEditor就可以接受以下intent:
action: android.intent.action.VIEW
data: content://com.google.provider.NotePad/notes/ID
要求activity顯示給定ID的筆記.
action: android.intent.action.EDIT
data: content://com.google.provider.NotePad/notes/ID
要求activity顯示指定ID的筆記,然後讓用戶來編輯它. 如果用戶保存了更改,則activity更新該content provider的數據.
action: android.intent.action.INSERT
data: content://com.google.provider.NotePad/notes
要求activity創建一個新的空筆記在content://com.google.provider.NotePad/notes, 並允許用戶編輯它, 如果用戶保存了更改,則該URI被返回給調用者.
最後一個activity, TitleEditor, 允許用戶編輯筆記的標題. 這可以通過直接調用activity(在intent中設置組件名稱)的方式來實現. 但是這裡我們用這個機會來展示如何在已有數據上進行另外的操作(類似於Windows中的打開方式->程序列表 -- 譯者注):
--------------------------------------------------------------------------------
<intent-filter android:label="@string/resolve_title">
<action android:name="com.android.notepad.action.EDIT_TITLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
--------------------------------------------------------------------------------
它必須在一個特定的筆記上調用(data type vnd.android.cursor.item/vnd.google.note), 就像之前的VIEW和EDIT action一樣. 然而, 這裡activity顯示筆記數據中包含的標題, 而不是內容.
除了支持DEFAULT category之外,title編輯器還支持了另外兩個category: ALTERNATIVE 和SELECTED_ALTERNATIVE. 這些category標志著activity可以在選項菜單中呈現給用戶(就像LAUNCHER category表示activity可以在程序啟動器中一樣). 注意filter還提供了一個顯示標簽(android:label="@string/resolve_title")來更好的控制用戶在選項菜單中看到的內容.
有了這些能力, 以下的intent就可以被TitleEditor接受:
action: com.android.notepad.action.EDIT_TITLE
data: content://com.google.provider.NotePad/notes/ID
要求activity顯示給定筆記ID的標題, 並允許用戶編輯該標題.
最近因為因緣際會,看了好些與創新理論相關的書籍。其中創新理論權威、哈佛大學商學院教授克裡斯汀生所著《創新者的解答》一書,我個人認為頗有意思,尤其對於開放系統與封閉系
Android操作系統平台很容易跟Google其他應用如Google地圖的整合。在Android應用中,如果能在其中加入Google地圖,則會為你的應用增添強大的功能,
在游戲開發中,往往要提供選關的頁面,選擇關卡可以簡單地使用listVIEw,如果想效果好一點,可以選擇 用gallery控件。Gallery控件的使用在api demo