2009年7月13日 星期一

Android 原始碼徹底研究系列 - 鬧鐘程式, AnalogClock (1)

Android Source Code Internals - Alarm Clock, AnalogClock (1)

鬧鐘的原始程式碼在 這裡

PS: 請不要向我要原始碼,所有Android原始碼都可已自行下載,詳情請見 https://source.android.com/source/building.html

一執行這個鬧鐘程式,畫面上第一眼看到的,就是一個大大的時鐘。因此我們今天,就先從這個時鐘下手。讓我們一探究竟,看他是如何實現的。

要了解這個時鐘,是用什麼元件做出來的。有兩個方法,第一個就是用 SDK 內自帶的 Hierarchy Viewer 工具;另一個,就是直接觀察 res/layout 中的畫面設計檔。這次,我們直接用第二個方法。

翻開 AlarmClock/res/layout 目錄的內容,你會發現有好幾個 clock_xxx.xml 的檔案。打開其中的 clock_droid2.xml 檔。內容如下所示:

嗯,看起來,這個時鐘就是用 android.widget.AnalogClock 這個元件直接實現的。只要透過 android:dial, android:hand_hour, android:hand_minute 這三個 XML 屬性,指定鐘面,時針與分針的圖檔,一個完整的時鐘,就會顯現出來。最上方的圖片,就是這個時鐘顯示的樣子。

都不需要任何額外的設定,這個時鐘元件就會自己依照目前的時間,將時、分針顯示在正確的位置,那他是如何定時更新時、分針位置?另外,注意到了嗎,時、分針的圖檔,只有一份。從這就猜到,這個時鐘還會自動將時、分針圖旋轉至正確的角度,貼在螢幕上。讓我們來看看,這個 AnalogClock 元件是如何實現這些功能的。

打開 AnalogClock 元件原始碼,扣掉最前面的註解不算,整個原始碼也才不到 230 行。這麼少的程式碼,卻能將這個時鐘功能做得這麼完整。這也是我常最推薦,一定要看的元件原始碼之ㄧ。

這次,我們要看的重點有兩個。

  1. 在元件程式中,要如何隨時都知道時間的改變?
  2. 在 Android 中,要如何將圖片做任意角度的旋轉,並貼在螢幕上?

在元件程式中,要如何隨時都知道時間的改變?

原來在 onAttachedToWindow() 中,AnalogClock 透過 registerReceiver() 註冊了三個由系統發出的 Actions,ACTION_TIME_TICK, ACTION_TIME_CHANGEDACTION_TIMEZONE_CHANGED

在 Android 中,系統會透過 Intent 傳送某些系統通知訊息,這些通知訊息又稱為 Action。在 Intent 類別的說明中,你可以找到所有的 Action 定義。

在你的程式中,想要收到這些系統通知訊息,有兩個方法。第一個方法就是在 AndroidManifest.xml 中定義 receiver 的類別,這個方法在日後的介紹中會提到。第二種方法就是利用 registerReceiver(),向系統註冊接收的類別。由於 AnaloClock 是以元件的方式存在,如果每次使用這個元件,都還要在 AndroidManifest.xml 中定義,那就太麻煩了。因此, AnaloClock 採用的是第二種方法。

其中,ACTION_TIME_TICK,就是由系統在每分整,傳送出來的 Action。ACTION_TIME_CHANGED 則是當使用者更改系統時間時,所送出的 Action。當你的手機跨越時區,系統則會送出 ACTION_TIMEZONE_CHANGED 給有註冊的程式。

一但這些 Actions 發生時,他會呼叫在程式最後 new 出來的 BroadcastReceiver 物件, mIntentReceiver,中的 onReceive() 回呼函式。

首先,在 onReceive() 中,先檢查如果是時區有改變的話,當然你要重新設定 mCalendar 變數。

onTimeChanged() 函式,只是重新抓出最新的時、分資料。

在 onReceive() 的最後,再呼叫 View.invalidate()。這個動作,會觸發 View.onDraw() 函式的呼叫,並在螢幕上畫上最新的時,分針。

在 Android 中,要如何將圖片做任意角度的旋轉,並貼在螢幕上?

Android 的 2D 繪圖功能,其實是很強的,尤其是 matrix 這部份。透過 matrix,你就可以輕易地,控制整個繪圖座標體系的位移、旋轉、傾斜,放大等功能。舉個例子來說,如果你要將圖片旋轉 30 度後,再貼在螢幕上。傳統的作法,都是直接先將圖片的內容,逐點旋轉 30 度。但是在 Android 平台上,你不用這麼麻煩。你只要將整個座標系統轉個 30 度,之後不管你是畫線,還是貼圖,最後呈現在螢幕上的都是轉 30 度的效果。

想要了解 AnalogClock 是如何選轉時、分針圖片,那看 onDraw() 這個函式就對了。我將 onDraw() 中,和這部份選轉時、分針圖片相關的,列在下面。其中的 canvas.rotate() 是關鍵,這個函式就是在將座標系統轉個角度。看完這個例子,有沒有發覺要在 Android 上旋轉、放大或縮小圖片,其實都是只要兩三行程式,就可搞定的事。

AnalogClock 就剩 constructors,與其他 onMeasure(), onSizeChanged(), onDetachedFromWindow() 等函式還沒提到,我想這部份就留給你自己去發掘。

38 則留言:

匿名 提到...

老師,請問一下。
我使用eclipse來開發android ap,在debug時,都可以很順利使用中斷點來查程式。但是BoardcaseReceiver裏面為什麼中斷點無法停止?這是eclipse的問題嗎?還是哪裏要設定?不然我就只能繼續用Toast來debug了.. 0_0

(只上老師一天的課,就不要命參加2009通訊大賽的人~)

samlu 提到...

我建議你用 Log.d() debug 會比 Toast 來的好用。
關於 breakpoint 的問題,我要先試試看才能回你。

匿名 提到...

請問我從 Android Open Source Code 上面所抓下來的 Project , 我要怎麼Import到Eclipse?
謝謝

Michael 提到...

File -> Import...

匿名 提到...

我是大陆的读者,很高兴能看到您的文章,期待新作!

ericosur 提到...

請問一下,這個 alarm clock裡面有好些東西都找不到,像是 android.provider.Calendar、mContext 等等... 請問是怎麼 build 起來的呀?

匿名 提到...

老師您好 再請問一下
我最近使用dialog寫程式,不管是自訂的dialog或是alertdialog。有些資料我希望在dialog結束後能傳回給activity。例如:在dialog上點選,或修改的資訊。...那我該怎麼直接傳回來給activity呢?目前我都是用Preference/sqllite的方式。但有沒有比較直接一點的方式呢?

ysl 提到...

嗯,好像沒這類的方法。

一般都是將 Dialog 或 AlertDialog 都寫在 Activity class 內。這樣你就可以在 Dialog 的 callback function 中,直接存取 Activity 所屬的 functions or variables.

匿名 提到...

如果畫面上有10個物體要旋轉,就要對canvas 旋轉and回復 10次....

Chris Ho 提到...

老師您好,
sdk 1.0時,有個好用的AbsouluteLayout,搭配layour_x屬性就可以隨意擺放元件的位置,不過用sdk 1.5編下去,居然說deprecated,要我用framelayout或是releatelayout, 但這二樣好像無法達成預期的效果,怎麼做比較好呢? thanks

samlu 提到...

用 FrameLayout 一樣可以達到 AbsoluteLayout 的效果。關鍵在,要配合 layout_marginTop & layout_marhinLeft

匿名 提到...

請問老師,Android的2D繪圖有沒有鏡射(mirror)這種效果?

匿名 提到...

請問怎麼下載原始程式碼阿?

samlu 提到...

爬文一下,有一篇就教你如何下載原始碼的。

匿名 提到...

請問老師或各位高手, 從Android source code網站check out下來的AlarmClock source code能直接丟到Eclipse編譯然後在模擬器執行嗎? 小弟試了好幾次總是出現很多語法錯誤. 看了summary應該是有針對Android SDK 2.1修改, 但不知道為什麼就是無法編譯....

samlu 提到...

AlarmClock 不能直接在你的 Eclipse 中編譯,應為他用了一些內部 APIs, 你一定要在 Android source code 的環境中編譯。

匿名 提到...

請問老師或各位高手,如果要編譯source code底下的application,應該要怎麼編譯,能否有人可以告知詳細的步驟

謝謝

公子乖 提到...

官方網站 http://android.git.kernel.org/p=platform/packages/apps/AlarmClock.git;a=summary
把 AlarmClock 移除了。

要下載的話要在 git 指定多加參數來指定版本

git clone git://android.git.kernel.org/platform/packages/apps/AlarmClock.git -b froyo

匿名 提到...

請問原始碼要怎麼觀看呀?
到這裡之後
http://android.git.kernel.org/?p=platform/packages/apps/AlarmClock.git;a=tree;h=refs/heads/cupcake;hb=refs/heads/cupcake

小鰻 提到...

樓上的,
建議你直接Git回來看會比較快=.=

匿名 提到...

最近看到大大的文章
讓我學到很多東西,
我想要近一步了解這個程式
但是原始碼的連結,好像壞了
可否麻煩板大檢查一下呢??

謝謝!!

匿名 提到...

Git回來是什麼意思??

匿名 提到...

不好意思 最近在學習android的鬧鐘
對於你的教學很感興趣
但用GIT下載
git clone git://android.git.kernel.org/platform/packages/apps/AlarmClock.git -b froyo

出現no such file or directory的訊息

請問是否有可以解決或其他載點

KVNS 提到...

您好,我無法進入GOOGLE 原始碼的網頁。

也沒辦法GIT(會有錯誤)

可能因為我在宿網。

很想要這枝原始碼,請問還有其它路徑可以拿道嗎

瘋狂理查 提到...

在網路上尋找android開發相關的文章
找到您這裡,想學習這個alarm clock的程式
但連結好像壞了
不知道還有沒有辦法跟您拿這個程式碼作研究呢
我的mail是a1251chu@gmail.com
謝謝

darven 提到...
作者已經移除這則留言。
匿名 提到...

老師您好, 原始碼的連結好像壞了, 請問方便和你拿程式碼研究看看嗎?謝謝

E-mail: ggkk753861924@gmail.com

Terry Lai 提到...

老師您好 我最近也在做類似的東西 想要這個project的source code 方便給我研究研究嗎?

E-mail terrylai14@gmail.com

晶晶 提到...

不好意思 最近在研究android的鬧鐘程式
想和你拿程式碼來研究
由於上面的原始碼連結打不開
可以麻煩您寄給我嗎?
以下是我的信箱 感恩
gings0803@gmail.com

匿名 提到...

可以用android SDK manager下載sources for android SDK
analogclock就放在 SDK資料夾/sources/android-xx/android/widget/

Paul 提到...

您好 最近在研究ANDROID的鬧鐘提醒程式 想要拿您的原始碼來研究 可以麻煩你寄給我嗎??

E-mail:bnm9876542002@yahoo.com.tw
感謝

匿名 提到...

剛學APP程式,想要程式碼來學習會更了解 可以寄給我嗎
r41105@yahoo.com.tw

minghan Li 提到...

想要寫一個鬧鐘程式,但是又沒方向,能不能跟老師,想說能不能拿個程式碼來學習這樣會更了解~
可以寄給我嗎? 感恩您!

E-mail: oo7680485@gmail.com

黃敏瑄 提到...

剛開始想寫一個時鐘(鬧鐘),希望可以在固定時間跳出提醒(螢幕關著的情況下,或是使用其他程式時),希望能提供程式碼給予學習!
可以麻煩您寄給我嗎? 謝謝THX!!
E-mail :autumm20@gmail.com

余政襄 提到...

版主您好 剛好開始因為專題寫一個時鐘(鬧鐘),希望可以讓使用者定時完後 可以使在背景下運作 等到時間到就發出提醒跟鎖螢幕,希望能提供相關程式碼給予學習!
可以麻煩您寄給我嗎? 謝謝^ ^
E-mail :a510286@yahoo.com.tw\a510286@gmail.com

HappyNicoleChou 提到...

作者先生您好,最近正在研究鬧鐘相關APP程式,希望版主能借我相關程式碼及檔案做為參考及研究,獻上十二萬分謝意!
E-mail : tukust94332@yahoo.com.tw

samlu 提到...

請不要向我要原始碼,所有Android原始碼都可已自行下載,詳情請見 https://source.android.com/source/building.html。

林靖 提到...

AI2可以做出鬧鐘提醒嗎?
最近在研究原始碼中

張貼留言