iii
作者序
為什麼要選擇手機程式的開發
記得前陣子,在某個聚會中和一些資訊界的前輩們談到之前遊戲軟體的創業點滴,
除了軟體設計之外,產品的設計、包裝、行銷,甚至通路等等,每位前輩都有許多 不為人知的生意經。雖然說各有各自的竅門,但大家都能同意在那個時代,一個產 品的成功,除了軟體本身無形的價值,還有其他許多外在有形的條件一樣缺一不 可,由於還有庫存與運送的壓力,當時的軟體因而有著大者恆大的趨勢。小公司要
生存,除了要找對利基市場之外,通常也需要某種程度的運氣才能成功。
然而,這樣的生態因為手機移動市場而開始有了一些改變,不管是Apple、Google
或是Microsoft的作業系統,藉著手持系統客製化的特性,讓軟體先天上有了一個自
然的通路可以發佈與販賣。再加上這些手持式設備的商店也整合了金流,因此,特
別對於個人和小型公司來說,降低了不少營運門檻,這感覺就像是將軟體開發之外 的流程全部都「外包」給這些系統供應商。因此,不管公司規模大小,能在這些手 持設備的線上商店被使用者青睞的機會都是均等的,重點在於你的創意是否能夠符 合使用者的預期和需求,一個應用程式便可以在很短時間內就匯集很大的人氣,比
較於盒裝軟體的市場,這是一種直接b2C(在此用小寫b來代表小公司)的形式,處 處是利基,人人有機會。也因為看到這個銳不可擋的潮流,讓筆者在2010年毅然全 力投身於移動產業之中。
為何要寫這樣一本書
由於Internet的普及,對於各式資訊幾乎都能夠在網路上找到的開發者而言,如何寫
出一本除了資訊充足且能夠有實質幫助的書,著實讓我傷透了腦筋。憑藉著實際參
與多項Android開發專案,以及和一些現役的開發人員討論,最後與悅知文化總編
輯確認,我們希望能夠出版這樣一本書:
iv
■在一些重要的議題上,這本書可以帶給開發者具體的觀念,從一些基本的應用開 始,並舉些較一般更完整的例子。希望讀者們在看完後能夠舉一反三,將這些技 巧和觀念運用在適合的情境,並知道採用適合的方式來解決問題。
■在介紹Android的框架與應用程式介面時,能夠專注在這個應用程式的介面,並儘
量減少其他無關的議題,而重要議題則留到專章進行完整的說明,如此一來,當 讀者想要了解某個特定議題,便能夠儘量在最短時間就能夠了解並加以運用。
由於筆者從事軟體開發工作十餘年,也是現役軟體開發人員,非常能夠體會軟體人
員就算一天有240小時也不夠用的心情,綜合以上數項,我著實希望這是一本能夠 節省讀者盲目摸索的開發手冊,我所設定的目標是──如果這本書能夠給一年前的 自己閱讀,而我能有:「啊,早知道就這麼做了...」的感歎!因此,如果你是剛入
門的Android新手,希望在看完了本書之後,你可以更快的上手實作,並且能知道
方法如何在Android SDK與眾多其他文件中找到更詳細的說明。
如果你是想閱讀本書並且希望在某個章節的內容上找到答案,就算本書內容沒有涵 蓋到,也希望至少能夠幫助你更加了解問題本身,並進一步去縮小尋找答案的範
圍。如果你想要一邊閱讀本書、一邊架構某個你自己的應用程式,希望本書也能可 以提供一個好的鳥瞰,以方便你了解如何對現有的元件進行妥善的運用。
由於工作的關係,筆者曾經有幸在每年到瑞士參加某跨國機構的雲端計算研發工 作。除了對於歐洲的風土民情有了不同的認知之外,最大感觸就是歐洲人對於工作
的態度。如果比較兩者在工作上的努力,台灣一個人真的是歐洲兩個人的工作量, 或許是傳統的關係,歐洲的團隊分工以及對專業的尊重,使得他們能在不太長的工 作時數下,除了能夠準確的完成工作之外,還能夠發揮創意讓產品的附加價值提 升。也為了能夠增加工作效率,總是會在事前一起激盪並收集各種可用資源,就如
v
十多年前,筆者踏入軟體開發領域,從最早的Visual C++、Java、N-tier J2EE 到
Unix/Linux C++ 系統程式,一直到現在這個移動運算的世代,參考文獻也經歷了很
多變革。從向國外訂閱紙本文件,到就近至台北重慶南路的天瓏書局搬回整櫃的
Microsoft Press系列叢書,到需要查閱完整的離線開發文件,一路到了現在,幾乎是
只要用正確的方法,都可以在網路上找到相關的討論。我向來深信天底下沒有新鮮 事,當我們遇到了某個問題,這個問題可能早在某個時間點已被其他人遇到並且解
決了。
我們並不打算出版一本「完全使用手冊」,將Android的各種內容包山包海的容納 進來,因為我相信每位Android開發者一定都會去下載SDK和原始碼,並且也都 很擅長使用Google來查詢資料。我們期許這本書,如同之前在設定這個產品的邏
輯,希望開發人員可以無痛的學習,在“儘量”不遇到太大挫折的情況下,了解
Android軟體框架的運作方式。為此,我們使用了很多的圖例、並搭配一些現成並
且免費(Eclipse)工具,希望就算你原本不是很清楚書中所討論的議題,也能夠在
很短的時間,甚至是站在書局翻閱的片刻,就可以有「啊!原來如此∼」的想法。
我們從Android的開發框架中挑選出十多個最基本的元件,將它組織在書中,希望
在你開始上手時能夠加快速度,幫助你在移動商機中尋找到專屬於你自己的機會。
關於
Android
由於合作伙伴的需要,筆者個人有過多種平台的開發經驗,對每一個平台都抱持著 高度的熱忱。然而,Android由於是基於Java和Linux,如果你像筆者一樣擁有Java
和Linux程式設計的基礎,一開始要了解Android的基本架構與運作機制或許需要一
點時間,但是在上手之後將會發現,Java和Linux執行程序的基礎是可以無縫接軌到
vi
我們都知道,這個世界不會因為某人寫了某本書而停止運轉。在寫這本書的同時,
Google出了Android新機Nexus S,內建了俗稱薑餅人的Android 2.3作業系統,而
Android 3.0的SDK甚至也出了預覽版。雖然說其開發介面還不是最後定稿的版本,
但是你可以看到UI變得更簡捷有型了,並且也重新設計了虛擬鍵盤,讓使用者輸入 更便利。同時,在一些內建的軟體如瀏覽器、相機、聯絡人和 email方面,都有了 更新、更強大的使用者介面,也強化了一些2D和3D的視覺運算與多核心的支援。
這些新增的功能都不斷地讓Android愈來愈受到使用者和開發者的青睞。
希望本書能夠作為你眾多入門磚中的一塊(而且是最硬、最紮實的一塊),引領你 的創意具體成為Android應用程式,並在Market上成功販售。
誌謝
一本書的完成除了作者之外一定還需要很多人的協助。因此,即使沒有在這裡列出 的幕後工作人員,我還是要表達深深的敬意和謝意,這本書要特別感謝悅知文化
「花さん」的力挺與支持,以及台灣大學電機工程研究所王勝德教授在忙碌的研究 工作之餘,願意抽空指導本書。
希望大家都可以快樂的閱讀、快樂的開發,快樂的在Android市集中找到自己。
何孟翰
2011-Jan-28
vii
導讀
這
是一本定位在Android入門學習的手冊,但並不是一本程式開發的入門手 冊。因此,我們不會在書中介紹如何使用Java語言去定義變數或迴圈這些流程控制的基本實務,我們認定你或多或少有些Java的開發經驗。如果你對Java的語 法不是太熟悉,建議先去找一本J2SE語言實務書來輔助參考。此外,由於Android 有很大一部份是使用XML檔案來定義的,如果你需要最基本的XML知識,可以參 考以下網址的內容:
http://www.w3schools.com/xml/default.asp
由於Android的開發與環境和網路習習相關,所以在開發時經常會有網路存取的需
求,雖然並非絕對必要,但請儘量在有網路的環境下進行開發。
書中我們專注於如何使用Eclipse為工具來開發Android的應用程式,希望能夠藉由
Eclipse的功能幫助你在開發過程中提昇開發效能與減少錯誤的發生。因此,在討論
Android開發的同時,也在許多章節裡融合了一些Eclipse常用的小技巧,希望你在了
解它們之後可以活用於其他方面。
本書內容由16章主題搭配2附錄所組成。我們用一個主要專案的開發搭配一些功能 小專案來架構全書,如果你是Android的開發新手,或是想要有一全面性的了解, 建議你由第1章跟著我們一起建立基礎,並探索Android多樣化的功能。由於本書 將大量使用Eclipse的功能,所以我們在第2章中會花些篇幅來討論Eclipse的基本功
能,如果你已經是Eclipse的老手,或許可以省略第2章而直接往後去閱讀。此外, 雖然章節的前後安排是有關聯性的,我們希望能夠由淺入深、由簡入繁、由內而外 地探討這些Android相關議題,但我們也儘量做到每章內容可以各自獨立,如果你 真的對某個議題感到興趣,儘量可以閱讀該章節就能了解其全貌。
雖然我們預設你具有Java開發經驗,但由於本書專注在Android的功能實作,所以並 不會特別強調複雜的Java語法,而會儘量使用簡單易懂的方式,讓你可以專注在所 有講解的議題上。你不需要具備足夠的Java、甚至J2ME的開發經驗,只要能夠理解 基本語法,大致上就應該可以跟著我們一起探索Android的框架,並且試著應用於
viii
導讀
由於本書很單純地專注在程式開發,所以我們並沒有花太多篇幅講述Android的市 場佔有率或是其背後的商業機會,身處於台灣的我們,對於這些常識應該時常可以
從產業新聞中攝取。
第一章開始,我們先介紹了Android的元件設計與整個系統概念,希望你能夠在撰
寫任何Android程式碼之前,先對Android的架構有正確的認知,如此開發出來的元
件才能夠發揮Android系統框架最大的功用。在第2章我們講解了必要的Eclipse知
識,以幫助你在往後章節使用它來開發Android時能更加得心應手。
從第3章開始,正式進入了Android的程式開發,直到第7章為止,我們會從使用者 介面定義開始,到與程式相關的除錯程序與操作各式各樣的視覺元件,例如:各種
輸入元件、按鈕、控制項與各式的表單。並且會儘量使用Eclipse所提供的功能,讓 你可以儘量在規範之下開發Android的基本元件。
第8章和第9章,我們則會開始提供資料存取的方式,如:使用者偏好、內部外部的 檔案存取、資料提供者(content provider)與SQL Lite ──一種內建於Android框
架中的嵌入式資料庫等方式,讓你的Android應用程式能夠將使用者狀態藉由各種 不同的方式儲存下來。
從第10章開始我們將討論個別的議題,雖然不一定是你開發的應用程式都需要的功 能,但卻都是一些實用的主題。例如,在第10章我們會討論Android的通訊功能,
藉由email、簡訊和網頁的存取,應用程式會使用各式各樣的方式與外界通訊。
Android SDK 2.3新增的下載管理也會在本章中被仔細討論,以方便你透過網路存取
日益增大的資料/媒體檔。
在第11章我們討論了地理位置和地圖的實作,手持式通訊會因為行動而有所不同,
在本章我們將充份的轉化地理位置變成地理資訊,以方便應用程式可以提供正確的 地理資訊與相關的POI(Point of Interest)景點資訊給你的使用者。
在第12章和第13章中,我們則討論更接近使用者介面的幾個議題,除了觸控的使用 與更多的繪圖元件之外,也講解了除了一般應用程式之外更多樣化的應用程式表
ix
由於Android的風行,愈來愈多的企業用戶也開始考慮以Android做為企業級應用程
式,因此,在第14章中我們討論了Android應用程式的安全控管與資料的備份與回
存。
在第15章我們將討論Google在Android上的訊息推播服務,它就像是簡訊傳送般的 由伺服器主動推播訊息到客戶端,並提供程式操作介面,讓訊息的主動推播(push
notify)比起簡訊更具彈性,且不會因為頻繁的程式操作而浪費過多的耗電量。
最後一章我們討論了與Android硬體相關的議題,在Android硬體規格愈來愈好的當 今,從相機的使用到各式各樣的感應器(sensor)操作都會加以介紹。雖然是最後 一章,但並不因此而代表其重要性是排在最後的。
在附錄A中,我們談到了Google的網頁服務,它可以讓你透過網頁來開發Android應 用程式,並且是使用像樂高積木般的組合方式,將應用程式以視覺化的方式呈現。 雖然這在現階段仍不是非常實用,但在可預見的將來,其能力將愈來愈強大。在附 錄B中,我們則討論了付費Android的新式版權服務,以幫助你在架構付費應用程式
時,可以更容易地將Google版權服務放進你的應用程式藍圖之中。
由於本書著重於基本觀念的養成,如果你看完之後希望有具體的範例,非常建議 你可以參考悅知出版的《Google Android SDK 開發範例大全》。此外,如果你有一 些特別實作的問題,建議你連上stackoverflow.com。若有機會的話,不妨也多參與
Google的研討會,相信對於了解Android的未來方向會很有幫助。
■本書所有範例程式請至悅知網站下載:
前進 Android Market!Google Android SDK 實戰演練 720
在本章中我們將開始討論Android的特別功能。首先是雲端備份,能讓你的
Android應用程式運用Google的雲端服務將資料備份至雲端,並在應用程式重裝
時,再自動部署到你的手機。其次會談到資料安全這個重要的議題,隨著Android
的應用軟/硬體愈來愈普及,許多企業也開始選擇Android作為企業應用,如何做
好資料安全的管理便成為很重要的課題。
14-01
雲端備份
讓我們從雲端備份開始。為了要提供一組回復點,並能夠回溯應用程式的資料和
設定,Android的備份服務允許你將資料複製到雲端的儲存空間。好處是不論使用
者因為升級firmware、遇到嚴重的當機而必須回復到出廠設定、或是更換新手機
時,系統都可以自動將這個應用程式的資料及設定在應用程式重新安裝時自動載
入。這樣一來,使用者就不需要再藉由其他方式生成這些資料。
或許你也會採用一些其他的方法,例如將資料Gmail給自己,或使用外部儲存空
間進行儲存。但請注意,本章所提的這種雲端備份對使用者來說是完全沒有任何
影響的,也不會影響到應用程式的功能。
資料的備份和回存是一體兩面。在備份時,Android的備份管理員(Backup
Manager)會查詢目前應用程式的狀態,決定哪些資料要備份,並將這些資料備
份到資料運輸員。而當回存時,備份管理員會從資料運輸員將資料傳送回應用程
式,所以應用程式就會把這些資料安裝到使用者的裝置上。上述這些步驟都會在
程式重新安裝時自動完成,所以基本上使用者是不需要手動進行任何動作的,雖
說你還是可以自行手動要求資料回存,但其實是完全多餘的。
備份與回存過程中所使用到的資料運輸員是一個由裝置製造商和系統提供者所共
同客製化的客戶端元件,因此,不同的裝置可能會有不同的資料運輸員;但對開
發應用程式來說,由於備份管理員的API已將這些資料運輸員的邏輯和應用程式
都隔離開了,所以我們並不需要理會底層資料運輸員的細節。
備份管理員是從Android API level 8之後才開始提供,也就是至少要在Android
SDK 2.2之後版本才可以正常運作,且並不保證在所有裝置上都可以運作。不
CHAPTER 14 雲端備份與資料安全 721 10
15 11
13
16 14
A 12
B
14-01
雲
端
備
份
Ⅳ
用者享受到好處,即可實作這個元件。如果使用者的新裝置可以使用這個功能,
則它會在背景中不受影響地執行。反之,就算使用者的新裝置沒有這個元件,它
還是可以依照原本的程式邏輯運行,不會因為沒有這個備份管理員而不正常的終
止,也就是說,對使用者來說原本的運行是不受影響的。
14-1-1
建立雲端備份用的專案
❙
為了簡化問題,在此用一個新專案來展示雲端備份的功能。請按下Eclipse的
新增一個專案,在「Project Name」欄輸入「CloudBackup」、「Build Taret 」選
擇「Android 2.2」、「Application name」請輸入「CloudBackup」、在「Package
n a m e」 欄 位 輸 入 「c o m .
delightPress.CloudBackup」、
「C r e a t e A c t i v i t y」 輸 入
「I n i t」 、 在 「M i n S D K
Version」輸入「8」,對照你
的結果與圖14-1是否相同,
之後按下「Finish」。
圖14-1:新增一個CloudBackup的專案,記得要使用
前進 Android Market!Google Android SDK 實戰演練 724
圖14-6:在Attribute for Meta Data底下輸入備份服務的key值
為了確認輸入結果,請看一下原始碼,確認在<application>的區塊中是否產生和
你傳回的網頁相同的結果。
14-1-2
建立備份的情境
❙
前面我們曾提過要保存應用程式的狀態可以使用許多方式,如利用使用者偏好、
內部檔案、外部檔案、資料庫等各種資源。而雲端備份可以協助我們處理的則是
使用者偏好和內部檔案兩種,且能夠做到幾近無縫地幫助使用者將資料平順地移
轉到新的Android裝置或重新安裝該軟體。其中又以使用者偏好的程式邏輯較為簡
單。接下來,我們先來建立一個備份的情境,再分別討論如何備份使用者偏好和
內部檔案。
我們設計的情境是在應用程式中加入兩個計數器,你可以把它想像成是兩個號碼
牌,一個是使用使用者偏好來實作,另一個則是使用內部檔案來實作,整個情境
如圖14-7所示。
使用者
更新使用者偏好檔案
更新內部檔案 更新使用者介面
增加內部檔案計數器的值 增加使用者偏好的計數器的值
CHAPTER 14 雲端備份與資料安全 725 10 15 11 13 16 14 A 12 B 14-01
雲
端
備
份
Ⅳ
整個應用程式可以簡化為兩個按鈕,分別按下去後會增加兩個計數器的數值,再
試著使用雲端備份來檢查是否可以正確地將資料在應用程式重新安裝時,還原回
來。首先準備好使用者介面中的字串資源,請打開strings.xml並加上以下幾個字
串:
<?xml version="1.0" encoding="utf-8"?> <resources>
<!-- 預設的標題 -->
<string name="hello">雲端備份測試</string> <!-- 應用程式顯示的名稱 -->
<string name="app_name">CloudBackup</string> <!-- 按鈕的資源 -->
<string name="add_pref">在使用者偏好檔加1</string> <string name="add_file">在程式內部檔加1</string> <!-- 尚未初始化計數器的字串 -->
<string name="pref_initial">使用者偏好未建立</string> <string name="file_initial">使用者檔案未建立</string> <!-- 初始化計數器的字串 -->
<string name="pref_message">使用者偏好Counter%1$d</string> <string name="file_message">檔案Counter%1$d</string> </resources>
設定使用者介面,請參考下列程式碼修改main.xml。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello"
android:textSize="20dip" /> <!-- 與使用者偏好相關的介面 -->
<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content"> <Button android:id="@+id/add_pref" android:text="@string/add_pref"
android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/pref_message" android:text="@string/pref_initial"
前進 Android Market!Google Android SDK 實戰演練 726
<!-- 與內部檔案存取相關的使用者介面 -->
<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content"> <Button android:id="@+id/add_file" android:text="@string/add_file"
android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/file_message" android:text="@string/file_initial"
android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
</LinearLayout>
切換至「Graphical Layout」標籤,看到的畫面應如圖14-8所示。
圖14-8: main.xml所設定的使用者介面
接著就可以在Init.java中依照兩個按鈕分別從使用者偏好和自訂的內部檔案中讀取
現在的計數器的值,如果使用者按下按鈕,則會加1之後再寫進去。請先定義這
兩個檔案的名稱:
// 使用者偏好的檔案名稱是 cloud_backup
private static final String PREF_FILENAME = "cloud_backup"; // 內部檔案的名稱是 int_counter_file
private static final String INTERNAL_FILE = "int_counter_file";