2009年8月20日

What is the Intent

在一個Android應用中,主要是由四種組件組成的,這四種組件是 Activitty, service, boardcase receiver,content provider 。 而這四種組件是獨立的,它們之間可以互相調用,協調工作,最終組成一個真正的Android應用。在這些組件之間的通訊中,主要是由Intent協助完成 的。Intent負責對應用中一次操作的動作、動作涉及數據、附加數據進行描述,Android則根據此Intent的描述,負責找到對應的組件,將 Intent傳遞給調用的組件,並完成組件的調用。因此,Intent在這裡起著一個媒體中介的作用,專門提供組件互相調用的相關信息,實現調用者與被調 用者之間的解耦。
例如,在一個聯繫人維護的應用中,當我們在一個聯繫人列表屏幕(假設對應的Activity為listActivity)上,點擊某個聯繫人後,希望能夠 跳出此聯繫人的詳細信息屏幕(假設對應的Activity為detailActivity),為了實現這個目的,listActivity需要構造一個 Intent,這個Intent用於告訴系統,我們要做「查看」動作,此動作對應的查看對象是「某聯繫人」,然後調用startActivity (Intent intent),將構造的Intent傳入,系統會根據此Intent中的描述,到ManiFest中找到滿足此Intent要求的Activity,系 統會調用找到的Activity,即為detailActivity,最終傳入Intent,detailActivity則會根據此Intent中的描 述,執行相應的操作。

一、抽象描述要描述什麼
在Android參考文檔中,對Intent的定義是執行某操作的一個抽象描述(確實很抽象)。我們先來看看這裡的抽象描述,到底描述了什麼。
首先,是要執行的動作(action)的一個簡要描述,如VIEW_ACTION(查看)、EDIT_ACTION(修改)等,Android為我們定義了一套標準動作:
  • MAIN_ACTION
  • VIEW_ACTION
  • EDIT_ACTION
  • PICK_ACTION
  • GET_CONTENT_ACTION
  • DIAL_ACTION
  • CALL_ACTION
  • SENDTO_ACTION
  • ANSWER_ACTION
  • INSERT_ACTION
  • DELETE_ACTION
  • RUN_ACTION
  • LOGIN_ACTION
  • CLEAR_CREDENTIALS_ACTION
  • SYNC_ACTION
  • PICK_ACTIVITY_ACTION
  • WEB_SEARCH_ACTION
此外,我們還可以根據應用的需要,定義我們自己的動作,並可定義相應的Activity來處理我們的自定義動作。

其次,是執行動作要操作的數據 (data),Android中 採用指向數據的一個URI來表示,如在聯繫人應用中,一個指向某聯繫人的URI可能為:content://contacts/1。這種URI表示,通過 ContentURI這個類來描述,具體可以參考android.net.ContentURI類的文檔。
以聯繫人應用為例,以下是一些action / data對,及其它們要表達的意圖:
  • VIEW_ACTION content://contacts/1 -- 顯示標識符為"1"的聯繫人的詳細信息
  • EDIT_ACTION content://contacts/1 -- 編輯標識符為"1"的聯繫人的詳細信息
  • VIEW_ACTION content://contacts/ -- 顯示所有聯繫人的列表
  • PICK_ACTION content://contacts/ -- 顯示所有聯繫人的列表,並且允許用戶在列表中選擇一個聯繫人,然後把這個聯繫人返回給父activity。例如:電子郵件客戶端可以使用這個Intent,要求用戶在聯繫人列表中選擇一個聯繫人

另外,除了action和data這兩個重要屬性外,還有一些附加屬性:
  • category(類別),被執行動作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者應該在Launcher中作為頂級應用出現;而ALTERNATIVE_CATEGORY表示當前的Intent是一系列的可選動作中的一個,這 些動作可以在同一塊數據上執行。
  • type(數據類型),顯式指定Intent的數據類型(MIME)。一般Intent的數據類型能夠根據數據本身進行判定,但是通過設置這個屬性,可以強制採用顯式指定的類型而不再進行推導。
  • component(組件),指定Intent的的目標組件的類名稱。通常 Android會根據Intent 中包含的其它屬性的信息,比如action、data/type、category進行查找,最終找到一個與之匹配的目標組件。但是,如果 component這個屬性有指定的話,將直接使用它指定的組件,而不再執行上述查找過程。指定了這個屬性以後,Intent的其它所有屬性都是可選的。
  • extras(附加信息),是其它所有附加信息的集合。使用extras可以為組件提供擴展信息,比如,如果要執行「發送電子郵件」這個動作,可以將電子郵件的標題、正文等保存在extras裡,傳給電子郵件發送組件。

總之,action、 data/type、category和extras 一起形成了一種語言。這種語言使系統能夠理解諸如「查看某聯繫人的詳細信息」之類的短語。隨著應用不斷的加入到系統中,它們可以添加新的action、 data/type、category來擴展這種語言。應用也可以提供自己的Activity來處理已經存在的這樣的「短語」,從而改變這些「短語」的行 為。

二、Android如何解析Intent
在應用中,我們可以以兩種形式來使用Intent:
  • 直接Intent:指定了component屬性的Intent(調用setComponent(ComponentName)或者setClass(Context, Class)來指定)。通過指定具體的組件類,通知應用啟動對應的組件。
  • 間接Intent:沒有指定comonent屬性的Intent。這些Intent需要包含足夠的信息,這樣系統才能根據這些信息,在在所有的可用組件中,確定滿足此Intent的組件。
對於直接Intent,Android不需要去做解析,因為目標組件已經很明確,Android需要解析的是那些間接Intent,通過解析,將 Intent映射給可以處理此Intent的Activity、IntentReceiver或Service。
Intent解析機制主要是通過查找已註冊在AndroidManifest.xml中的所有IntentFilter及其中定義的Intent,最終找 到匹配的Intent。在這個解析過程中,Android是通過Intent的action、type、category這三個屬性來進行判斷的,判斷方 法如下:
  • 如果Intent指明定了action,則目標組件的IntentFilter的action列表中就必須包含有這個action,否則不能匹配;
  • 如果Intent沒有提供type,系統將從data中得到數據類型。和action一樣,目標組件的數據類型列表中必須包含Intent的數據類型,否則不能匹配。
  • 如果Intent中的數據不是content: 類型的URI,而且Intent也沒有明確指定它的type,將根據Intent中數據的scheme (比如 http: 或者 mailto: ) 進行匹配。同上,Intent 的scheme必須出現在目標組件的scheme列表中。
  • 如果Intent指定了一個或多個category,這些類別必須全部出現在組建的類別列表中。比如Intent中包含了兩個類別:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析得到的目標組件必須至少包含這兩個類別。

2009年8月13日

Convert int to char

大部分的方式是使用itoa()這個function, 用法如下:
char * itoa ( int value, char * str, int base );
ex:
int
i=3;
char
buffer [10];
itoa (i,buffer,10);
其中 i 是要轉成char的integer, buffer是要存的char, 而10表示轉成十進位.

但是itoa()在某些Linux底下就是無法被使用, 簡單說就是無法被系統reference到. 此時可以使用另外一種方式sprintf(), 用法如下:
int sprintf ( char * str, const char * format, ... );
ex:
char
buffer [50];
int n, a=5, b=3;
n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);
其中 buffer 裡就是"引號"中的字元(char), 而 n 則是"引號"的位元大小(int).

2009年8月10日

Android Process Lifecycle

Android Process Lifecycle

Android系統記憶體不足時, 就需要把舊的或不需要用的應用程式移除. 如同之前的Activity生命週期所介紹, 這個移除的決定是由應用程式所處的狀態來判斷. 一般來說,當需要移除應用程式時, 系統將會做排序, 然後從最不重要的開始移除, 以下是移除時的考量順序:



1. 最早被移除的是 Empty Process(空行程):
Empty process 是指那些沒有跟Activity綁定, 也沒有跟任何的應用程式元件(比如Service或IntentReceiver)綁定在一起的process, 這些空行程一定是最早被系統考慮移除的.


2. 第2順位考慮被移除的是 Background Activity.
Background Activity指這個activity是無法被使用者看到的的情況, 表示Activity已處於stop的狀態, 系統移除這些 Activity 是安全的. 通常有多個 Background Activity同時運行, 這些Activity被存放在一個 LRU (least recent used) list中, 系統可以根據 LRU list 判斷哪些 Activity可以被移除, 哪一個應該是最先被移除的.

3. 第3順位被移除的是 Service Process.
在 Android 應用程式裡, 有一種沒有 UI 的類別(android.app.Service), 稱之為 Service. Service Process 通常是由startService()方式啟動. 簡單來說,Service 屬於 background(背景)程序, 透過背景程序, 我們可以製作一些不需要 UI 的功能, 例如: 在背景撥放音樂, 上傳或下載文件等. 系統通常會保護它, 除非真的沒有記憶體可用.

4. 接著輪到 Visible Activity / Visible Process:
Visible Process是一個可被Visible的, 但是沒有顯示在最上端 (onPause被使用時). 舉例來說, 當一個新的對話框Activity出現時, 原來的Activity仍然visible, 仍然被系統認為是重要的, 通常不會被移除. 但若不得不移除時, 由於屬於 Paused狀態, 相對來說, 它已經處於一個比較安全的位置.

5. 最後被移除的是 Foreground Activity:
Foreground是一個在螢幕最上端與使用者做互動的Activity, 它的優先權最高. 原則上會是最後一個被移除的程式, 除非這個Activity所需要的記憶體大小已經超出系統所能給的. 系統之所以會移除這些程序, 是為了不讓使用者介面停止回應.

由於Android應用程式的lifecycle並不是由程式本身直接控制的, 而是由系統平台進行管理. 所以對於開發者而言, 許要瞭解不同元件 Activity, Serivce 和 IntentReceiveer的Lifecycle. 要切記: 如果元件使用不當, 雖然正在進行重要的Process, 仍有可能被系統主動移除.

Android Activity生命週期簡介

Android Activity生命週期簡介

前面有提到何謂Activity: 最簡單的就是把Activity看成一個User Interface Program. 它會提供使用者一個互動式的介面功能. 當然一個activity通常不只一個UI, 所有的Activity在系統裏由Activity stack 所管理, 當一個新的Activity被執行後,它將會被放置到stack的最頂端,並且變成"running activity", 而之前的Activity原則上還是存在stack中,但不會是在foreground(前景)的情況.

一個Activity基本上有四個狀態 Active, Paused, Stopped, Dead:
Activity 處在Paused狀態時, 使用者無法與原來的 Activity 互動.


Dead/Inactive (已回收或未啟動)
Dead狀態是 Activity 尚未被啟動, 已經被手動終止, 或已經被系統回收的狀態.
要手動終止 Activity, 可以在程式中呼叫 finish 函式.
如果是被系統回收, 可能是因為記憶體不足, 系統根據記憶體不足時的回收規則, 將處於Stopped狀態的 Activity 所佔用的記憶體回收.


下面的流程圖說明一個Activity運行的情況, 長方形代表callback methods(回呼函式), 可以做出想要處理的事情, 有顏色的部份就是實際Activity會處於的狀態.






上圖有三個主要 lifetime :

1. Entire lifetime: 一個Activity的Entire lifetime是由onCreate()開始, 一直到onDestroy()結束.
一個Activity可以把所有的資源設定寫在onCreate中, 一直到onDestroy()時再釋放出來.

2. Visible lifetime: 一個Activity的Visible lifetime是指在onStart()到onStop()之間.
在這段時間內,使用者可以在螢幕上看見Activity, 要注意這個"Visible"是個形容, Activity不見得一定在foreground(前景)跟使用者直接互動.

3. Foreground lifetime: 一個Foreground lifetime 指 onResume() 到 onPause() 之間. 這個時期的Activity是在其他的Activity的前面, 且可以直接跟使用者進行互動. 所以這段時期指的就是圖中的Activity is running.


簡單的總結幾個動作:
onCreate()用來做程式的初使化動作;
onDestory()通常都拿來把onCreate()時的資料做釋放的動作;
onPause()時把需要保存的資料保存;
onResume()把保存的資料拿回來使用.


onCreate -> onStart -> onResume
啟動一個 Activity 的基本流程是: 分配資源給這個 Activity(onCreate), 然後將 Activity 內容顯示到螢幕上(onStart), 在一切就緒後, 取得螢幕的控制權(onResume), 使用者可以開始使用這個程式。

onPause(1) -> onCreate(2) -> onStart(2) - onResume(2) -> onStop(1)
先凍結原本的 Activity, 再交出直接存取螢幕能力(onPause )的過程. 直到 Activity 2 完成一般啟動流程後, Activity 1 才會被停止.

onPause(2) -> onRestart(1) -> onStart(1) -> onResume(1) -> onStop(2) -> onDestroy(2)
按 Back鍵可以回到原本的 Activity。

onPause -> onStop -> onDestroy
如果程式中有直接呼叫 finish 函式來關閉 Activity的話, 系統會暫停(Pause), 停止(Stop)然後銷毀(Destroy)。

onCreate -> onStart -> onResume
被回收掉的 Activity 一旦又重新被呼叫時,會像一般啟動一樣再次呼叫 Activity 的 onCreate 函式.

Android 的名詞觀念

Android 的名詞觀念

在真正進入 Android 程式設計前,必須先了解以下幾個名詞觀念。

1. Android Package (.apk):
包含應用程式本身,以及相關的資源檔案。將 apk 套件下載到 Android 手機後,即可安裝至手機上。Android Development Kit 可自動將 apk 套件下載至模擬器或實體手機。
記得前面我們在 Eclipse 中若要檢視HelloWorld程式時, 是利用 Package Explorer 來查看整個程式的結構的.

2. Task
Task 為"工作"的意思, 可以看成 Application (應用程式)本身. 也就是手機上的應用程式的圖示,使用者可點擊圖示啟動 task。從開發者的角度來看

3. Process
Process 的定義上,指的是"執行中的程式",在 Android 的Application 環境中,代表低階的執行程式,屬於 Kernel 部份。一個 package 的所有程式,都是在一個 process 中執行。
在一般情況下, Android 應用程式都有一個自已的 Process. 在 Android 系統裡, Process 的生命週期(life cycle) 並不是直接由 Android 應用程式本身來決定, 而是由系統來決定.
Android 的 process 有五種類型:foreground process、visible process、service process、background process 與 empty process。

4. Activity
Activity是Android開發中非常重要的一個基礎類。就字面上來說, Activity 就是"活動"的意思. 可以簡單的解釋為, Activity 是一個與使用者互動的物件(object)。
舉例來說:一個EMail程式,就可能包含三個activity: 有列出郵件的 Activity 1, 顯示郵件內容的activity 2, 及 撰寫郵件 activity3.
Activity 大概可以分成四種生命狀態:
一個Activity在螢幕的最上層時(堆疊的最頂端),它就是屬於activerunning的狀態
如果一個Activity失去focus(焦點)但還看得到它的畫面(例如:一個Activity畫面是被蓋掉部份畫面或一個半透明的情況), 這個Activity則處在 paused的狀態。這個失去焦點的Activity它還是完全活著的, 並沒有消失。(活著的意思是指,Activity本身所有的狀態及資料都還是存在,與管理程式保持連繫). 但這種paused的activity, 會在某些情況下消失, 例如當系統的記憶體不夠用時, 系統會自動判斷, 把不重要的activity移除.

如果一個Activity被其它的Activity完全的遮住時, 這個被遮的Activity處於stop的狀態, 但它仍然保有全部的狀態及資料. 由於它已不被使用者看見,所以它的畫面是被隱藏起來的, 當系統記憶體不足時,這種stop狀態的activity是最先被系統考慮移除以釋放記憶體.

當一個Activity處於pause或stop的狀態時, 系統可以要求Activity結束(finish)或移除(kill)它. 當它需要再度呈現在使用者面前時, 它必需要能完整的重新啟動(restart)及回復(resume)先前的狀態。

5. View
簡單來說,android.app.View 類別就是手機的 User Interface. View 負責繪製UI與 event (處理事件). Android 利用 View 建立所謂的 Widgets(元件), 利用 Widget 就可以製作互動式的使用者介面(interactive GUI).