https://github.com/zytc2009/BigTeam_learning
分类: Java
2010-10-19 13:37:07
什麼是Intent(意圖)?
強大的事件處理「Intent」(意圖)是Android很強大的一種機制。
在 Android 應用程式框架中,有一個非常聰明的事件處理機制,稱之為「Intent」。Intent(意圖)的作用與事件(event)很像,但與傳統的事件處理仍然 有些差異。傳統的事件處理,講求的是「處理者(handler)的觸發」,當一事件發生時,便callback讓事件的處理者,或是直接將該事件轉送 (forward)給應用程式,由應用程式決定處理方式。
在「Intent」這樣的事件處理觀念裡,Android 試圖將事件解釋為「應用程式的意圖」或是「使用者的意圖」,並試著去解釋該意圖的目的,若 Android 系統本身能理解應用程式的意圖,便會「自行」去處理該意圖所應執行的工作。
Android的做法是,讓每個意圖(Intent)都帶有一個動作(action),並根據不同的動作去行動。
關於前述教學提到的Intent
在前面的教學裡,我們用到二次Intent如下:
1. 自行定義一個Intent、設定Service可接收此Intent,並透過「送出Intent給框架」的方式,請框架啟動該Service
2. 使用Android內部定義的動作「ACTION_VIEW」,來「檢視」(view)一個「URL」資料,當框架看到內部定義的ACTION_VIEW 動作時,便「自行」處理該Intent;處理的方式是啟動WebView並連上網站
以前述的教學為例,使用內建的動作“ACTION_VIEW”就可以很容易做出一個「啟動瀏覽器(WebView類別)上網」的應用程式。
透過這二個例子我們知道,Intent的動作可以是自行定義與框架內部定義二種。Android框架的Intent有很多方便實用的「內建動作」, 以下我們說明Android內建Intent的美麗之處。
Android內建的Intent Action
Android的框架確實是讓每個Intent都包含了一個動作,就稱為action。
為了讓大家更容易了解Intent的基本觀念,我們採用「體驗」的方式來說明如何使用內建的Action。現在,我們列舉以下三個情境,並分別實作 其範例:
HelloIntentDialer: 啟動撥號器(dialer)並撥號
HelloIntentMusic: 使用者按下「Select Music」後,可以由音樂清單裡選擇音樂並撥放
HelloIntentWallpaper: 啟動Android內建的「背景圖選擇器」,讓使用者更換背景
第二個範例”HelloIntentMusic”其實是ApiDemo裡的範例,而且是很容易能了解Intent內涵的好程式。
除了action外,Intent還可以包含另外一項資訊「data」。
Intent的action指定這個Intent的「動作」是什麼,框架會依指定的動作進行處理;有些action可以附帶一筆資料,這個資料是以 Uri的格式撰寫,在HelloIntentDialer的範例會再做說明。
內建的Intent有哪些呢?請參考Android Reference Guide中的Intent類別說明。上述三個範例分別使用以下三個action:
1. ACTION_CALL: 撥號
2. ACTION_GET_CONTENT: 啟動內容選取器
3. ACTION_SET_WALLPAPER: 設定Wallpaper
在進行範例講解前,可以先行閱讀Intent類別的說明。ACTION_CALL是一個內建的action,我們只要產生一個Intent物件,並 定義其「action」為ACTION_CALL即可通知框架「打電話」。
Android內建的action是相當實用的應用開發機制,同時也是Android OS最具代表性的機制之一。Android內建的Intent action分為二種:
1. Activity Action: 啟動Activity的action
2. Broadcast Action: 透過廣撥器處理的action
第一種action是activity action,用途是通知框架啟動Activity,這裡提出的三個範例,都是使用activity action。Broadcast action將在Broadcast的教學裡再做說明。
HelloIntentDialer是一個自動撥號程式,執行時會自動撥號到指定的 電話。這樣的程式要怎麼寫呢?先看到HelloIntentDialer.java的完整程式如下:
package com.moko.hellointentdialer;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
public class HelloIntentDialer extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent dial = new Intent();
dial.setAction("android.intent.action.CALL");
dial.setData(Uri.parse("tel:119"));
startActivity(dial);
}
}
因為permission的關係,所以也要在AndroidManifest.xml裡加上「CALL_PHONE」的權限。 AndroidManifest.xml的完整內容如下:
package="com.moko.hellointentdialer" >
android:versionCode="1"
android:versionName="1.0">
android:label="@string/app_name">
這個範例相當簡單,但足以說明Intent的核心精神了。程式說明:
1. 先產生一個Intent物件:
Intent dial = new Intent();
2. 設定Intent的action為「android.intent.action.CALL」,這是一個內建的action:
dial.setAction("android.intent.action.CALL");
內建action「CALL」需要附帶一筆資料,而資料的寫法是使用URI格式:
dial.setData(Uri.parse("tel:119"));
4. 「CALL」是一個activity action,所以呼叫startActivity()向Intent送給框架:
startActivity(dial);
這個範例的概念並不難,「送出一個帶有內建action的Intent給框架,因為action為CALL,所以框架會去啟動撥號activity 並打電話。」
上一篇教學提到如何利用Intent實作「自動撥放」程式。而另外一個較具代表性的Intent應用就是「內容選擇器」。例如,要怎麼實作一個音樂 撥放機呢?先說明音樂撥放器HelloIntentSelect範例的使用情境如下:
1. 執行HelloIntentSelect後,出現一個「撥放音樂」的按鈕
2. 按下按鈕後,選擇一個音樂檔撥放
實作「選擇音樂檔」的做法是使用Intent的「chooser」觀念。程式做法如下:
1. 建立action為ACTION_GET_CONTENT的Intent:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
2.設定Intent的mime type,例如:設定Intent的mime type為聲音檔案:
intent.setType("audio/*");
3.建立內容選擇器並送出Intent:
startActivity(Intent.createChooser(intent, "Select music"));
以上的程式是根據Android的Reference Guide寫出來的。當Intent action為ACTION_GET_CONTENT時,表示要根據mime type來「取得內容」(get content),因此呼叫setType()方法,來定義內容的mime type。
定義好mime type後,再呼叫createChooser()方法來產生能取得此mime type內容的「選擇器」,簡單說,就是一個「檔案選取程式」。
利用Android的Intent觀念,我們以不到十行的程式碼實作了一個音樂撥放器。
Action的屬性寫法與常數寫法
Intent的action寫法有二種。第一種寫法是屬性(attribute)寫法,例如第一個HelloIntentDialer範例:
dial.setAction("android.intent.action.CALL");
在「android.intent.action」套件(package)裡,定義了action的屬性。第二種寫法是常數寫法,例如第二個 HelloIntentSelect範例:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
在「Intent」類別(class)裡,定義了action的常數。在記憶的技巧上,可以用「xxx對於到ACTION_xxx」的方式記。例 如:
CALL(android.intent.action.CALL)就是ACTION_CALL(Intent.ACTION_CALL)。
又如,所以當我們講「GET_CONTENT」時,指的就是android.intent.action.GET_CONTENT;同理,講 ACTON_GET_CONTENT時,就是代表Intent.ACTION_GET_CONTNET。所以「GET_CONTENT」與 「ACTION_GET_CONTNET」代表相同的Intent。
圖1: HelloIntentSelect主程式
Android提供「SET_WALLPAPER」的內建Intent,當框架收到 這個Intent時,就會啟動「背景圖選擇器」,讓我們選取新的背景圖。送出SET_WALLPAPER intent的程式寫法如下:
Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
startActivity(Intent.createChooser(intent, "Select Wallpaper"));
根據Reference Guide的說明,SET_WALLPAPER會啟動一個內容選擇器,所以同時地,我們先呼叫createChooser()方法建立一個內容選擇器後, 再送出Intent。
完整程式碼: HelloIntentWallpaper.java
package com.moko.hellointentwallaper;
import com.moko.hellointentwallaper.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class HelloIntentWallpaper extends Activity implements View.OnClickListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button)findViewById(R.id.set_wallpaper);
button.setOnClickListener(this);
}
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
startActivity(Intent.createChooser(intent, "Select Wallpaper"));
}
}
UI設計: layout/main.xml
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
執行結果
圖1: HelloIntentWallpaper主程式
圖2: 「背景圖」選擇器
什麼是NinePatch圖檔
NinePatch是一種「可延展」的PNG圖檔。NinePatch圖檔的用途是製作「可隨文字大小縮放」的圖片,如圖1。
圖1: 文字背景可隨著文字大小縮放
NinePatch是很有用的圖片格式,可做為widget的「背景圖」。如圖1的範例,其應用程式的設計如下:
首先,第一個工作就是「製作NinePatch圖檔」,方式如下。
Step 1. 準備一張原始的PNG圖檔,如圖2。
圖2: 原始PNG圖檔(arrow.png)
Step 2. 啟動Android提供的draw9patch工具,直接執行Android SDK tools/目錄下的draw9patch執行檔即可,如圖3。
圖3: Android SDK提供的draw9patch工具(點擊看原圖)
Step 3. 開啟原始PNG圖檔,編輯圖檔,如圖4。
如何編輯NinePatch圖檔
NinePatch圖檔的製作方式是「繪製二條線」,分別在原始圖檔的上方與左方繪出二條「黑線」,黑線所交集的區域即為「可延展」區域。如下圖的 粉紅色區域。
圖5: 定義延展區
「可延展區」是Android框架用來擺放文字的區域,換句話說,文字(TextView)只會被放置在粉紅色區域,並且擺放的原
則是「對準粉紅區域的中心點」,即上下置中、左右也置中。非「可延展區」,即綠色部份,並不會隨著文字的大小縮放延
展。所以:
1. 綠色區域是固定大小區域
2. 粉紅色區域是可延展區域、文字擺放於此
圖中的「二條黑線」是怎麼畫出來的呢?方式如下。
Step 4. 移動「Zoom」調整圖檔比例,讓「斑馬線」的大小能適中,如圖6。
圖6: 調整比例
Step 7: 畫黑線
斑馬線是用來畫黑線的區域,怎麼畫黑線呢?用滑鼠點斑馬線就可以了。要怎麼刪除黑線上?按住「Shift」再點斑馬線即可。斑馬線很不好點,所以如 果不是要特意訓練操作滑鼠的技巧以及考驗眼力,善用「Zoom」功能可以幫助黑線的繪製。
勾選「Show patches」選項,即可顯示粉紅色區域,如圖7。
圖7: 即時顯示可延展區
在draw9patch的右邊也會有縮放的展示圖。
Step 8: 完成NinePatch圖檔
儲存完成的NinePatch圖檔,draw9patch會自動將圖檔的副檔名儲存為*.9.png。完成NinePatch圖檔後,就可以開始寫 程式了。
* Update: 2009/9/20 - Android擺放文字於NinePatch圖檔上的原則「並非對準粉紅區域的中心點」,已刪除此句。