169
BӜ GIÁO DӨC VÀ ÀO TҤO TRѬӠNG ҤI HӐC MӒ ӎA CHҨT BÀI GIҦNG PHÁT TRIӆN ӬNG DӨNG CHO THIӂT Bӎ DI ӜNG Tên hӑc phn : Lp trình mobile Trình đӝ đào tҥo : ҥi hc chính quy Dùng cho SV ngành : Công nghthông tin Ngѭӡi soҥn : HThӏ Thҧo Trang Hà Nӝi 11-2013

Lập trình Androi

Embed Size (px)

Citation preview

Page 1: Lập trình Androi

B浦 GIÁO D影C VÀ ĐÀO T萎O

TR姶云NG Đ萎I H窺C M碓 Đ卯A CH遺T

BÀI GI 謂NG

PHÁT TRI 韻N 永NG D影NG CHO THI 蔭T B卯 DI Đ浦NG

Tên h丑c phần : Lập trình mobile

Trình đ瓜 đào t衣o : Đ衣i học chính quy

Dùng cho SV ngành : Công nghệ thông tin

Ng逢運i so衣n : Hồ Th鵜 Th違o Trang

Hà N瓜i 11-2013

Page 2: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

2

Mục lục

Chương 1. Những ki院n th泳c cơ b違n v隠 thi院t b鵜 di đ瓜ng và lập trình cho thi院t b鵜 di đ瓜ng .................................................................................................................................................5

1.1. Các thi院t b鵜 di đ瓜ng .............................................................................................................5

Phân lo衣i các thiết b鵜 di đ瓜ng ..................................................................................................5

Các hệ điều hành thiết b鵜 di đ瓜ng thông minh .........................................................................6

Xu h逢噂ng di đ瓜ng hóa ...........................................................................................................11

1.2. Tổng quan v隠 lập trình cho thi院t b鵜 di đ瓜ng ...................................................................13

Chương 2. Nhập môn lập trình Android .......................................................................15

2.1. Thi院t b鵜 Android - hệ đi隠u hành và máy 違o Dalvik ........................................................15

Giao diện và 泳ng d映ng ..........................................................................................................16

Phát triển ................................................................................................................................19

B違o mật và tính riêng t逢 ........................................................................................................22

Máy 違o Dalvik .......................................................................................................................24

2.2. Lập trình cho thi院t b鵜 Android ........................................................................................28

B瓜 phát triển phần mềm Android (Android SDK) ................................................................28

Môi tr逢運ng phát triển ............................................................................................................31

Hello Android (Android “Hello world”) ...............................................................................38

Chương 3. Các Activity, Fragment và Intent ................................................................50

3.1. Activity ...............................................................................................................................50

Vòng đ運i c栄a Activity ...........................................................................................................50

Cửa sổ h瓜p tho衣i (Dialog) .....................................................................................................53

3.2. Intent và việc tương tác giữa các Activity .......................................................................56

Sử d映ng Intent .......................................................................................................................56

Gi違i quyết “xung đ瓜t Intent” .................................................................................................58

L医y kết qu違 tr違 về từ Activity thông qua Intent .....................................................................59

Truyền dữ liệu giữa các Activity v噂i Intent ..........................................................................62

Sử d映ng Intent để g丑i các 泳ng d映ng sẵn có c栄a hệ điều hành ...............................................63

Đối t逢嬰ng Intent ....................................................................................................................66

3.3. Fragment............................................................................................................................67

Thêm fragment trong th運i gian thực thi (không khai báo trong layout): ...............................71

Vòng đ運i c栄a Fragment .........................................................................................................73

T逢ơng tác giữa các fragment .................................................................................................75

Page 3: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

3

Chương 4. Giao diện người dùng c栄a 泳ng d映ng Android ...........................................77

4.1. View và ViewGroup ..........................................................................................................77

LinearLayout .........................................................................................................................78

AbsoluteLayout .....................................................................................................................83

TableLayout ...........................................................................................................................83

RelativeLayout ......................................................................................................................84

FrameLayout .........................................................................................................................86

ScrollView .............................................................................................................................87

4.2. Bố c映c giao diện thích nghi với hướng màn hình (ngang|dọc) ................................88

Neo các view con theo các c衣nh màn hình ............................................................................89

Thay đổi kích th逢噂c và v鵜 trí .................................................................................................90

Điều khiển h逢噂ng c栄a màn hình ............................................................................................92

4.3. Sử d映ng trình đơn (Menu) .........................................................................................93

Trình đơn chính .....................................................................................................................95

Trình đơn ngữ c違nh ...............................................................................................................96

4.4. Sử d映ng thanh tác v映 (Action Bar) ...........................................................................97

4.5. Xử lý sự kiện tương tác với các thành phần đồ họa ...............................................100

N衣p chồng hàm xử lý sự kiện c栄a Activity .........................................................................100

Đăng ký sự kiện cho từng View ..........................................................................................101

Chương 5. Thi院t k院 giao diện người dùng với các View cơ b違n ................................102

5.1. Sử d映ng các View cơ b違n trong Android ......................................................................102

TextView .............................................................................................................................102

Button và ImageButton........................................................................................................102

EditText ...............................................................................................................................103

CheckBox ............................................................................................................................103

RadioButton và RadioGroup ...............................................................................................103

ToggleButton .......................................................................................................................103

ProgressBar .........................................................................................................................106

5.2. TimePicker và DatePicker .......................................................................................108

TimePicker ..........................................................................................................................108

DatePicker ...........................................................................................................................111

5.3. Hi吋n th鵜 違nh với ImageView và Gallery ..................................................................113

5.4. Sử d映ng ListView đ吋 hi吋n th鵜 danh sách dài ..........................................................118

ListView ..............................................................................................................................118

Page 4: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

4

SpinnerView ........................................................................................................................121

5.5. Hi吋n th鵜 n瓜i dung trang web với WebView ............................................................123

Chương 6. Lưu trữ dữ liệu ............................................................................................127

6.1. Lưu trữ dữ liệu cố đ鵜nh với shared preferences ...........................................................127

6.2. Lưu trữ dữ liệu với file trên b瓜 nhớ trong và b瓜 nhớ ngoài ........................................132

Làm việc v噂i file trong b瓜 nh噂 trong ...................................................................................132

Làm việc v噂i file trong b瓜 nh噂 ngoài ..................................................................................136

6.3. CSDL SQLite trong 泳ng d映ng Android ........................................................................137

T衣o l噂p DBAdapter .............................................................................................................137

Chương 7. Lập trình m衣ng với Android .....................................................................142

7.1. Sử d映ng web services thông qua giao th泳c HTTP .......................................................142

7.2. T違i dữ liệu nh鵜 phân thông qua HTTP ..........................................................................144

7.3. T違i dữ liệu d衣ng text thông qua HTTP .........................................................................146

7.4. Web service với dữ liệu XML ........................................................................................148

7.5. Web service với dữ liệu JSON .......................................................................................152

Chương 8. Google Play Store và việc phân phối 泳ng d映ng .......................................156

8.1. Chuẩn b鵜 泳ng d映ng trước khi phân phối ................................................................156

Đánh số phiên b違n phần mềm .............................................................................................156

Ch泳ng thực số cho 泳ng d映ng Android ................................................................................157

8.2. Phân phối 泳ng d映ng ..................................................................................................162

Sử d映ng công c映 adb ...........................................................................................................162

Phân phối trên web server ...................................................................................................162

Phân phối trên Google Play Store........................................................................................163

Page 5: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

5

Chươngà ヱ. Những kiến thứIà Iơà Hản về thiết bị dià động và lập

trình cho thiết bị diàđộng

1.1. Các thiết bị diàđộng

Phân loại các thiết bị diàđộng

Các thiết b鵜 di đ瓜ng đư tr違i qua r医t nhiều năm phát triển v噂i r医t nhiều lo衣i thiết b鵜 khác nhau, có thể kể đến nh逢 máy nhắn tin di đ瓜ng, điện tho衣i di đ瓜ng, thiết b鵜 tr嬰 giúp cá nhân (PDA, Palm...), điện tho衣i thông minh, máy tính b違ng... Các thiết b鵜 nghe nhìn khác nh逢 máy 違nh, máy quay kỹ thuật số, máy nghe nh衣c... cũng có thể đ逢嬰c xếp vào "thiết b鵜 di đ瓜ng". Tuy nhiên giáo trình sẽ b臼 qua các thiết b鵜 mang tính ch医t l鵜ch sử (đư không còn hoặc gần nh逢 không còn) và các thiết b鵜 nghe nhìn mà ch雨 đề cập đến các lo衣i thiết b鵜 điện toán cầm tay hiện đang phổ biến trên th鵜 tr逢運ng tiêu dùng. Các thiết b鵜 này th逢運ng đ逢嬰c phân theo các lo衣i nh逢 sau:

Điện tho衣i di đ瓜ng cơ b違n (basic phone và featured phones) - là các điện tho衣i di đ瓜ng v噂i các tính năng cơ b違n nh逢 nghe, g丑i, danh b衣... và m瓜t số 泳ng d映ng dựng sẵn đơn gi違n. Các thiết b鵜 này th逢運ng có kích th逢噂c nh臼, màn hình đ瓜 phân gi違i th医p, có hoặc không có bàn phím, pin dùng đ逢嬰c lâu, ít kết nối và kh違 năng phát triển thêm phần mềm c栄a nhà phát triển (gần nh逢) không có.

Điện tho衣i di đ瓜ng thông minh (smart phones) - là các điện tho衣i đ逢嬰c trang b鵜 c医u hình tốt hơn, ch衣y hệ điều hành thông minh v噂i SDK cho phép lập trình viên phát triển đa d衣ng các 泳ng d映ng ph映c v映 m丑i m映c đích c栄a cu瓜c sống. Các thiết b鵜 này th逢運ng có kích th逢噂c và màn hình l噂n hơn nhiều so v噂i featured phones, c医u hình phần c泳ng (CPU, RAM, GPU, camera...) cao, đa d衣ng các kết nối (Wifi, Bluetooth, 3G/4G, GPS, Glonass, NFC...), có thể có hoặc không nhiều lo衣i c違m biến (c違m biến gia tốc, la bàn, c違m biến tiệm cận, c違m biến ánh sáng, con quay hồi chuyển...). V噂i ngần trang b鵜, dù th逢運ng đ逢嬰c trang b鵜 th臼i pin l噂n hơn featured phones, th運i l逢嬰ng pin c栄a điện tho衣i thông mình th逢運ng r医t h衣n chế so v噂i featured phones.

Máy tính b違ng - là các thiết b鵜 thông minh, t逢ơng tự nh逢 smart phones nh逢ng có kích th逢噂c màn hình l噂n hơn r医t nhiều (thông th逢運ng từ 7"-13"), có thể có hoặc không có h厩 tr嬰 khe cắm SIM-card (ph映c v映 việc nhắn tin, g丑i điện hoặc truy cập internet qua WiFi/3G)

Điện tho衣i thông minh lai máy tính b違ng (phablet) - là lo衣i thiết b鵜 lai giữa smartphone và máy tính b違ng, về tính năng nó là m瓜t smart phone, nh逢ng đ逢嬰c trang b鵜 màn hình cỡ l噂n hơn smart phone thông th逢運ng và nh臼 hơn kích th逢噂c phổ biến c栄a màn hình tablet. Màn hình c栄a phablet th逢運ng có kích th逢噂c 5.0"-6.9". Trong lập trình, các phablet th逢運ng đ逢嬰c xếp g瓜p chung vào smart phones.

Do kh違 năng lập trình các điện tho衣i cơ b違n r医t h衣n chế (th逢運ng ph違i làm việc v噂i l噂p th医p hơn, không có b瓜 công c映 phát triển tiện d映ng) nên mặc dù điện tho衣i cơ b違n vẫn chiếm th鵜 phần ch栄 yếu, n瓜i dung giáo trình "Phát triển 泳ng d映ng di đ瓜ng" ch雨 tập trung nhắm đến các thiết b鵜 thông minh (điện tho衣i thông minh, máy tính b違ng và điện tho衣i lai). Về mặt phần mềm, các thiết b鵜 này hầu nh逢 t逢ơng đ逢ơng, vì vậy giáo trình có thể đ逢嬰c g丑i là "Lập trình cho điện tho衣i thông minh".

Page 6: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

6

Biểu đồ d逢噂i đây thể hiện tỷ lệ th鵜 phần giữa Smart Phones và Featured Phones trong 3 năm gần đây, dữ liệu kh違o sát trên tập ng逢運i tr逢荏ng thành t衣i Hoa Kỳ (theo số liệu c栄a PewSearchCenter, tháng 6 năm 2013):

Các hệ điều hành thiết bị diàđộng thông minh

Các hệ điều hành thiết b鵜 di đ瓜ng hiện đ衣i tổng h嬰p r医t nhiều tính năng c栄a máy tính cá nhân truyền thống cũng nh逢 h厩 tr嬰 các tính năng đặc tr逢ng cho thiết b鵜 di đ瓜ng nh逢 màn hình c違m 泳ng, sóng di đ瓜ng (GSM/CDMA), 3G/4G, Bluetooth, WiFi, GPS, Glonass, ch映p 違nh, quay phim, nhận d衣ng gi丑ng nói, ghi âm, trình chơi nh衣c, NFC, b瓜 phát hồng ngo衣i...

Những hệ điều hành di đ瓜ng phổ biến nh医t hiện nay gồm có:

Android

Android là hệ điều hành miễn phí, mã nguồn m荏, phát triển b荏i "gã khổng lồ" Google. Android dựa trên nền t違ng Linux đ逢嬰c thiết kế dành cho các thiết b鵜 di đ瓜ng có màn hình c違m 泳ng nh逢 điện tho衣i thông minh và máy tính b違ng. Ban đầu, Android đ逢嬰c phát triển b荏i Tổng công ty Android, v噂i sự h厩 tr嬰 tài chính từ Google và sau này đ逢嬰c chính Google mua l衣i vào năm 2005. Android ra mắt vào năm 2007 cùng v噂i tuyên bố thành lập Liên minh thiết b鵜 cầm tay m荏: m瓜t hiệp h瓜i gồm các công ty phần c泳ng, phần mềm, và viễn thông v噂i m映c tiêu đẩy m衣nh các tiêu chuẩn m荏 cho các thiết b鵜 di đ瓜ng. Chiếc điện tho衣i đầu tiên ch衣y Android đ逢嬰c bán vào tháng 10 năm 2008.

Android có mã nguồn m荏 và Google phát hành mã nguồn theo Gi医y phép Apache. Chính mã nguồn m荏 cùng v噂i m瓜t gi医y phép không có nhiều ràng bu瓜c đư cho phép các nhà phát triển thiết b鵜, m衣ng di đ瓜ng và các lập trình viên nhiệt huyết đ逢嬰c điều ch雨nh và phân phối Android

Page 7: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

7

m瓜t cách tự do. Ngoài ra, Android còn có m瓜t c瓜ng đồng lập trình viên đông đ違o chuyên viết các 泳ng d映ng để m荏 r瓜ng ch泳c năng c栄a thiết b鵜, bằng m瓜t lo衣i ngôn ngữ lập trình Java có sửa đổi. Vào tháng 10 năm 2012, có kho違ng 700.000 泳ng d映ng trên Android, và số l逢嬰t t違i 泳ng d映ng từ Google Play, cửa hàng 泳ng d映ng chính c栄a Android, 逢噂c tính kho違ng 25 tỷ l逢嬰t.

Những yếu tố này đư giúp Android tr荏 thành nền t違ng điện tho衣i thông minh phổ biến nh医t thế gi噂i, v逢嬰t qua Symbian vào quý 4 năm 2010, và đ逢嬰c các công ty công nghệ lựa ch丑n khi h丑 cần m瓜t hệ điều hành không nặng nề, có kh違 năng tinh ch雨nh, và giá rẻ ch衣y trên các thiết b鵜 công nghệ cao thay vì t衣o dựng từ đầu. Kết qu違 là mặc dù đ逢嬰c thiết kế để ch衣y trên điện tho衣i và máy tính b違ng, Android đư xu医t hiện trên TV, máy chơi game và các thiết b鵜 điện tử khác. B違n ch医t m荏 c栄a Android cũng khích lệ m瓜t đ瓜i ngũ đông đ違o lập trình viên và những ng逢運i đam mê sử d映ng mã nguồn m荏 để t衣o ra những dự án do c瓜ng đồng qu違n lý. Những dự án này bổ sung các tính năng cao c医p cho những ng逢運i dùng thích tìm tòi hoặc đ逢a Android vào các thiết b鵜 ban đầu ch衣y hệ điều hành khác.

Android chiếm 75% th鵜 phần điện tho衣i thông minh trên toàn thế gi噂i vào th運i điểm quý 3 năm 2012, v噂i tổng c瓜ng 500 triệu thiết b鵜 đư đ逢嬰c kích ho衣t và 1,3 triệu l逢嬰t kích ho衣t m厩i ngày. Sự thành công c栄a hệ điều hành cũng khiến nó tr荏 thành m映c tiêu trong các v映 kiện liên quan đến bằng phát minh, góp mặt trong cái g丑i là "cu瓜c chiến điện tho衣i thông minh" giữa các công ty công nghệ.

iOS

iOS là hệ điều hành trên các thiết b鵜 di đ瓜ng c栄a Apple. Ban đầu hệ điều hành này ch雨 đ逢嬰c phát triển để ch衣y trên iPhone (g丑i là iPhone OS), nh逢ng sau đó nó đư đ逢嬰c m荏 r瓜ng để ch衣y trên các thiết b鵜 c栄a Apple nh逢 iPod touch, iPad và Apple TV. Ngày 31 tháng 5, 2011, App Store c栄a Apple ch泳a kho違ng 500 000 泳ng d映ng iOS, và đ逢嬰c t違i về tổng c瓜ng kho違ng 15 tỷ lần. Trong quý 4 năm 2010, có kho違ng 26% điện tho衣i thông minh ch衣y hệ điều hành iOS, sau hệ điều hành Android c栄a Google và Symbian c栄a Nokia.

Giao diện ng逢運i dùng c栄a iOS dựa trên cơ s荏 thao tác bằng tay. Ng逢運i dùng có thể t逢ơng tác v噂i hệ điều hành này thông qua r医t nhiều đ瓜ng tác bằng tay trên màn hình c違m 泳ng c栄a các thiết b鵜 c栄a Apple.

Phiên b違n m噂i nh医t là: 6.1.4 (ra ngày 2/5/2013) dành riêng cho iPhone 5 và 6.1.3 (ra ngày 19/3/2013) cho các thiết b鵜 iOS còn l衣i.

Blackberry

BlackBerry OS là nền t違ng phần mềm t逢 hữu do RIM (Research In Motion) phát triển cho dòng s違n phẩm cầm tay BlackBerry. BlackBerry OS cung c医p kh違 năng đa nhiệm, và đ逢嬰c thiết kế cho các thiết b鵜 sử d映ng ph逢ơng pháp nhập đặc biệt, th逢運ng là trackball hoặc màn hình c違m 泳ng. Hệ điều hành đ逢嬰c h厩 tr嬰 MIDP 1.0 và WAP 1.2. Các phiên b違n tr逢噂c đó cho phép đồng b瓜 hóa không dây th逢 điện tử và l鵜ch v噂i Microsoft Exchange Server , và v噂i c違 Lotus Domino. Phiên b違n OS 4 hiện t衣i h厩 tr嬰 MIDP 2.0, có kh違 năng kích ho衣t không dây hoàn toàn và đồng b瓜 th逢 điện tử, l鵜ch, công việc, ghi chú và danh b衣 v噂i Exchange, và kh違 năng h厩 tr嬰 Novell GroupWise, Lotus Notes khi kết h嬰p v噂i BlackBerry Enterprise Server.

Page 8: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

8

Các b違n cập nhật cho BlackBerry OS có thể có nếu nhà m衣ng cung c医p thông qua d鵜ch v映 BlackBerry OTASL.

Các bên th泳 ba có thể phát triển 泳ng d映ng dùng các API t逢 hữu c栄a BlackBerry, nh逢ng b医t kỳ 泳ng d映ng nào sử d映ng các ch泳c năng gi噂i h衣n đều cần ph違i ch泳ng thực tr逢噂c khi cài đặt. Việc ch泳ng thực này xác nhận tác gi違 c栄a ch逢ơng trình, nh逢ng không b違o đ違m tính an toàn và b違o mật c栄a 泳ng d映ng.

BlackBerry 10

Là thế hệ tiếp theo c栄a hệ điều hành BlackBerry OS, đ逢嬰c phát triển b荏i BlackBerry Limited (Research In Motion đổi tên), dành cho c違 điện tho衣i lẫn máy tính b違ng. Thiết b鵜 gần đây nh医t sử d映ng hệ điều hành là smartphone cao c医p BlackBerry Q10

Windows phone

Windows Phone là hệ điều hành c栄a Microsoft dành cho smartphone kế t映c nền t違ng Windows Mobile, mặc dù chúng không t逢ơng thích v噂i nhau. Khác v噂i Windows Mobile, Windows Phone tập trung vào sự phát triển c栄a Marketplace - n噂i các nhà phát triển có thể cung c医p s違n phẩm (miễn phí hoặc có phí) t噂i ng逢運i dùng. Windows Phone đ逢嬰c bán vào tháng 10 năm 2010 và đầu năm 2011 t衣i Châu Á.

Phiên b違n m噂i nh医t hiện tài là Windows Phone 8. Microsoft còn đang phát triển b違n Windows Phone Apollo Plus, và trong t逢ơng lai có thể còn có Windows Blue (hay có thể là Windows 9) giúp t逢ơng thích v噂i hệ điều hành Windows trên máy tính. V噂i Windows Phone , Microsoft đư phát triển giao diện ng逢運i dùng m噂i mang tên Modern (tr逢噂c đây tên là Metro) - tích h嬰p kh違 năng liên kết v噂i các phần c泳ng và phần mềm c栄a hãng th泳 ba m瓜t cách dễ dàng.

Ngày 11 tháng 2 năm 2011, tr逢噂c mặt báo gi噂i, CEO Microsoft Steve Balmer và CEO Nokia Stephen Elop công bố tr荏 thành đối tác c栄a nhau, đồng nghĩa v噂i việc Windows Phone tr荏 thành hệ điều hành chính c栄a Nokia, thay thế Symbian đư già c厩i. Sự kiện này cũng đánh d医u m瓜t mốc quan tr丑ng trong cu瓜c chiến v噂i Android và iOS, đ逢嬰c ví nh逢 là "cu瓜c đua giữa 3 con ngựa". Theo đó, công ty này sẽ h嬰p tác v噂i Microsoft trong việc s違n xu医t những điện tho衣i Windows Phone 7 (hiện t衣i là Windows Phone 8). Nokia h泳a hẹn sẽ:

Tập trung vào Windows Phone 7/8

Đ逢a ra những thiết kế m噂i, bổ sung những gói ngôn ngữ và phổ biến chúng nhiều hơn cho ng逢運i tiêu dùng thông qua những thiết kế m噂i về phần c泳ng, nhiều phân khúc giá và th鵜 tr逢運ng hơn

H嬰p tác trong lĩnh vực marketing, phát triển phần mềm cho điện tho衣i di đ瓜ng

Bing sẽ tr荏 thành nền t違ng tìm kiếm trong các thiết b鵜 và d鵜ch v映 c栄a Nokia

Kho 泳ng d映ng riêng c栄a Nokia sẽ đ逢嬰c tích h嬰p chung v噂i Marketplace.

Ngoài các hệ điều hành trên, trên th鵜 tr逢運ng hiện t衣i còn có thiết b鵜 ch衣y các hệ điều hành khác v噂i th鵜 phần không đáng kể nh逢: Bada (c栄a Samsung), BlackBerry Tablet OS (cho máy tính b違ng BlackBerry PlayBook), GridOS (do Fusion Garage phát triển dựa trên Android), Linux, Brew (c栄a Qualcomm), webOS (c栄a Palm, sau HP mua l衣i, rồi l衣i bán l衣i cho LG hồi tháng 2 năm 2013), Tizen (do Samsung và Intel phối h嬰p h厩 tr嬰, dựa trên LiMo - Linux for Mobile), Windows RT (c栄a Microsoft cho các thiết b鵜 sử d映ng chip kiến trúc ARM).

Page 9: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

9

M瓜t số tổ ch泳c, công ty cũng đang n厩 lực phát triển các hệ điều hành di đ瓜ng m噂i, đ逢嬰c nhắc đến nhiều nh医t trong số đó có thể kể đến:

Al iyun OS

Al iyun OS ra đ運i tháng 7 năm 2011, là hệ điều hành dựa trên Linux, đ逢嬰c phát triển b荏i AliClound, m瓜t công ty con c栄a Alibaba Group, Trung Quốc. ụ t逢荏ng chung c栄a hệ điều hành Aliyun là "đám mây hóa" các tính năng c栄a thiết b鵜 di đ瓜ng (clound functionality).

Theo Google đây là Aliyun đ逢嬰c phát triển từ hệ điều hành mã nguồn m荏 Android c栄a mình, Alibaba thì ph栄 nhận điều này, tuy nhiên hệ điều hành này có thể ch衣y đ逢嬰c hầu hết các 泳ng d映ng c栄a Android. Trên ch嬰 泳ng d映ng c栄a Aliyun thậm chí còn ch泳a r医t nhiều 泳ng d映ng Android vi ph衣m b違n quyền.

Thiết b鵜 đầu tiên ch衣y hệ điều hành này là điện tho衣i K-Touch W700

FireFox OS

Là hệ điều hành cho điện tho衣i di đ瓜ng và máy tính b違ng, phát triển trên nền Linux, đ逢嬰c phát triển b荏i tổ ch泳c phi l嬰i nhuận Mozilla Foundation (tổ ch泳c làm ra trình duyệt FireFox nổi tiếng). Đ逢嬰c thiết kế để cung c医p m瓜t hệ thống toàn diện cho thiết b鵜 di đ瓜ng, sử d映ng các công nghệ m荏 và phổ biến nh逢 HTML5, Javascript, web API... v噂i kh違 năng truy cập trực tiếp vào phần c泳ng thiết b鵜, FireFox OS nhắm đến c衣nh tranh v噂i các ông l噂n khác nh逢 Apple's iOS, Google's Android, Microsoft's Windows Phone, cũng nh逢 các hệ điều hành m噂i xu医t hiện nh逢 Ubuntu Touch OS.

FireFox OS đ逢嬰c gi噂i thiệu tháng 2 năm 2012 trên vài điện tho衣i ch衣y Android, và trên b瓜 kit Raspberry Pi vào năm 2013. Tháng 1 năm 2013, t衣i triển lãm thiết b鵜 điện tử tiêu dùng quốc tế CES 2013, hãng ZTE xác nhận sẽ s違n xu医t điện tho衣i ch衣y hệ điều hành này và đến 2 tháng 7 năm 2013, Telefónica chính th泳c gi噂i thiệu điện tho衣i th逢ơng m衣i đầu tiên ch衣y FireFox OS t衣i Tây Ban Nha: điện tho衣i ZTE Open.

Ubuntu Touch OS

Là giao diện di đ瓜ng c栄a hệ điều hành mã nguồn m荏 nổi tiếng - Ubuntu c栄a Canonical Ltd., đ逢嬰c thiết kế dành cho các thiết b鵜 di đ瓜ng v噂i màn hình cám 泳ng nh逢 điện tho衣i thông minh và máy tính b違ng. Điểm m衣nh c栄a Ubuntu Touch là việc dựa trên cùng m瓜t công nghệ lõi nh逢 hệ điều hành Ubuntu cho máy tính, giúp các 泳ng d映ng dành cho Ubuntu và Ubuntu Touch có thể ch衣y lẫn nhau mà không cần phát triển l衣i phiên b違n riêng. Ngoài ra thiết b鵜 ch衣y Ubuntu Touch có thể biến thành Ubuntu b違n cho máy tính v噂i đầy đ栄 tính năng c栄a máy tính cá nhân khi kết nối vào màn hình ngoài hoặc kết nối qua b瓜 đế (dock).

V噂i sự phổ biến c栄a hệ điều hành Ubuntu và kh違 năng t逢ơng thích c栄a Ubuntu Touch, đây có thể sẽ tr荏 thành m瓜t trong những hệ điều hành phổ biến trong t逢ơng lai.

B違ng d逢噂i đây thể hiện t逢ơng quan th鵜 phần giữa các hệ điều hành di đ瓜ng thông minh phổ biến từ năm 2012-2013, theo số liệu ngày 16/05/2013 c栄a IDC Worldwide Quarterly Mobile Phone Tracker, May 2013 (đơn v鵜: tri ệu thiết b鵜)

HĐH Số lư嬰ng Q1-

2013 Th鵜 phần Q1-

2013 Số lư嬰ng Q1-

2012 Th鵜 phần Q1-

2012 Tỷ lệ tăng

trưởng

Page 10: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

10

Android 162.1 75.0% 90.3 59.1% 79.5%

iOS 37.4 17.3% 35.1 23.0% 6.6%

Windows Phone 7.0 3.2% 3.0 2.0% 133.3%

BlackBerry OS 6.3 2.9% 9.7 6.4% -35.1%

Linux 2.1 1.0% 3.6 2.4% -41.7%

Symbian 1.2 0.6% 10.4 6.8% -88.5%

Others 0.1 0.0% 0.6 0.4% -83.3%

Total 216.2 100.0% 152.7 100.0% 41.6%

Biểu đồ d逢噂i đây cho th医y sự thay đổi về s違n l逢嬰ng cũng nh逢 th鵜 phần c栄a các hệ điều hành di đ瓜ng từ năm 2007 đến nay (nguồn wikipedia.org)

Page 11: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

11

Xuàhướngàdiàđộng hóa

Page 12: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

12

Theo số liệu thống kê của Cisco – Mobile Global, 2012

1 EB = 1 million terabytes = 1 billion gigabytes

T衣i Vi ệt Nam:

• Thuê bao di đ瓜ng: 120 triệu.

• Thuê bao 3G: 20 triệu.

• Tỷ lệ ng逢運i dùng smartphone: 21%.

0.60 EB

1.3 EB

2.4 EB

4.2 EB

6.9 EB

10.8 EB

0.00

2.00

4.00

6.00

8.00

10.00

12.00

2011 2012 2013 2014 2015 2016

Tốc đ瓜 tăng trưởng Mobile Data Internet Exabytes/month

Page 13: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

13

Thói quen sử d映ng thiết b鵜 truy cập Internet

Cimigo netcitizens report 2012

1.2. Tổng quan về lập trình cho thiết bị diàđộng

Ng逢運i lập trình 泳ng d映ng cho thiết b鵜 di đ瓜ng truyền thống luôn luôn ph違i nh噂 trong đầu nguyên tắc "tiết kiệm tối đa tài nguyên" c栄a thiết b鵜, dùng m丑i cách để tôi 逢u hóa đ瓜 ph泳c t衣p tnhs toán cũng nh逢 l逢嬰ng b瓜 nh噂 cần sử d映ng. Tuy nhiên cùng v噂i sự phát triển nhanh chóng c栄a phần c泳ng, các thiết b鵜 di đ瓜ng hiện đ衣i th逢運ng có c医u hình r医t tốt, v噂i chip xử lý m衣nh mẽ, b瓜 nh噂 (RAM) l 噂n, khiến việc lập trình cho thiết b鵜 di d瓜ng tr荏 nên dễ dàng hơn bao gi運 hết. Các b瓜 kit phát triển c栄a các hãng s違n xu医t hệ điều hành di đ瓜ng hiện hành cũng th逢運ng làm trong suốt hầu hết các tác v映 liên quan đến qu違n lý b瓜 nh噂, qu違n lý tiến trình... Lập trình viên có thể ít quan tâm hơn đến việc tối 逢u hóa sử d映ng tài nguyên và tập trung vào việc "lập trình", phát triển tính năng cho 泳ng d映ng nh逢 khi lập trình cho máy tính cá nhân.

Tuy nhiên, đặc tr逢ng di đ瓜ng c栄a các thiết b鵜 này cũng đem đến nhiều v医n đề mà ng逢運i lập trình cần ph違i quan tâm nh逢: kết nối m衣ng c栄a thiết b鵜 di đ瓜ng th逢運ng không ổn đ鵜nh (tùy thu瓜c vào v鵜 trí, tốc đ瓜 di truyển, h衣 tầng m衣ng…), việc qu違n lý tài nguyên để tối 逢u hóa l逢嬰ng điện năng tiêu th映 (tiết kiệm pin). Ngoài việc việc phân m違nh (quá nhiều lo衣i thiết b鵜, nhiều kích th逢噂c và đ瓜 phân d違i màn hình, nhiều c医u hình phần c泳ng khác nhau..) c栄a các thiết b鵜 di đ瓜ng khiến việc kiểm thử 泳ng d映ng r医t khó khăn.

Ngoài ra các hãng phát triển hệ điều hành di đ瓜ng đều làm ra b瓜 kit phát triển (SDK) và môi tr逢運ng phát triển tích h嬰p (IDE) r医t thuận tiện cho việc viết code, biên d鵜ch, gỡ r厩i, kiểm thử cũng nh逢 xu医t b違n phần mềm.

So v噂i máy tính cá nhân, các thiết b鵜 di đ瓜ng hiện đ衣i đ逢嬰c trang b鵜 thêm r医t nhiều tính năng giúp việc t逢ơng tác v噂i ng逢運i dùng tr荏 nên thuận tiện (màn hình c違m 泳ng đa điểm, t逢ơng tác gi丑ng nói, cử ch雨...), các lo衣i kết nối đa d衣ng (NFC, GPS, 3G, 4G, bluetooth, IR...), các c違m biến phong phú giúp tr違i nghiệm r医t đa d衣ng (c違m biến ánh sáng, c違m biến tiệm cận, la bàn, cám biến chuyển đ瓜ng, gia tốc kế...). Ng逢運i lập trình, tùy thu瓜c vào 泳ng d映ng c映 thể, có thể sử d映ng đến các tính năng đặc tr逢ng này để đem đến cho ng逢運i dùng tr違i nghiệm tốt nh医t trên thiết b鵜 di đ瓜ng c栄a mình.

Xét theo th鵜 phần trên th鵜 tr逢運ng, 3 hệ điều hành phổ biến nh医t cho thiết b鵜 hiện nay là Google's Android, Apple's iOS và Microsoft's Windows Phone. M厩i 泳ng d映ng thành công th逢運ng đ逢嬰c phát triển cho c違 3 hệ nền này. M厩i hệ nền đều có m瓜t ch嬰 泳ng d映ng chính hãng (Google có Google Play Store, Apple có Apple AppStore, Microsoft có Windows Phone Store)

Page 14: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

14

v噂i r医t nhiều khách hàng tiềm năng, giúp ng逢運i phát triển có thể xu医t b違n 泳ng d映ng miễn phí hoặc m医t phí v噂i chi phí nh医t đ鵜nh.

B違ng d逢噂i đây liệt kê các hệ điều hành v噂i ngôn ngữ và IDE phổ biến nh医t c栄a nó.

HĐH Ngôn ngữ lập trình IDE

Android Java IBM's Eclipse v噂i Google's ADT plugins

iOS Objective-C Apple' Xcode

Windows Phone C# Microsoft's Visual Studio cho Windows phone

Ngoài việc phát triển 泳ng d映ng cho từng hệ điều hành nh逢 kể trên, lập trình viên có thể lựa ch丑n các th逢 viện lập trình đa nền, để phát triển 泳ng d映ng, phổ biến nh医t trong các 泳ng d映ng đa nền là các 泳ng d映ng viết bằng ngôn ngữ web (HTML, CSS & Javascript). Trình duyệt web c栄a các thiết b鵜 di đ瓜ng đ逢ơng th運i có đầy đ栄 tính năng lẫn hiệu năng năng ch衣y tốt các 泳ng d映ng web hiện đ衣i, m瓜t 泳ng d映ng web có thể đ逢嬰c đặt trên máy ch栄 hoặc đ逢嬰c đóng gói thành native app (泳ng d映ng cho từng hệ điều hành) qua m瓜t số công c映 đóng gói c栄a các hãng th泳 ba.

Công c映 đóng gói 泳ng d映ng Web cho thiết b鵜 di đ瓜ng phổ biến nh医t hiện nay là PhoneGap, đ逢嬰c phát triển b荏i Nitobi, sau đ逢嬰c Adobe mua l衣i. PhoneGap cho phép lập trình viên phát triển 泳ng d映ng di đ瓜ng sử d映ng ngôn ngữ web phổ biến (HTML5, CSS3 và Javascript), v噂i các tính năng bổ sung, cho phép 泳ng d映ng truy cập vào l噂p phần c泳ng c栄a thiết b鵜 nh逢 gia tốc kế, máy 違nh, GPS... và đóng gói thành 泳ng d映ng cho nhiều hệ điều hành khác nhau, bao gồm Android, iOS, Blackberry, BlackBerry 10, Windows Phone, Windows 8, Tizen, Bada. Tuy nhiên, nh逢嬰c điểm c栄a các 泳ng d映ng lo衣i này là có hiệu su医t th医p (ch衣y không đ逢嬰c "m逢嬰t mà" nh逢 泳ng d映ng native) và không đồng nh医t v噂i t医t c違 các trình duyệt web di đ瓜ng (có thể ch衣y hoặc hiển th鵜 khác nhau trên các hệ điều hành v噂i các trình duyệt khác nhau).

Việc ch丑n hệ điều hành/th逢 viện nào để phát triển tùy thu瓜c vào nhiều yếu tố khác nhau nh逢 m映c đích c栄a 泳ng d映ng, đối t逢嬰ng sử d映ng, tiềm năng c栄a hệ điều hành, các yêu cầu kỹ thuật c映 thể cũng nh逢 thói quen và kỹ năng c栄a lập trình viên. Trong khuôn khổ có h衣n, giáo trình ch雨 tập trung đi sâu vào việc phát triển 泳ng d映ng cho hệ điều hành di đ瓜ng phổ biến nh医t hiện nay - Google's Android.

Page 15: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

15

Chươngàヲ. Nhập môn lập trình Android

2.1. Thiết bị Android - hệ điều hành và máy ảo Dalvik

Ngày 5 tháng 11 năm 2007, Liên minh thiết b鵜 cầm tay m荏 (Open Handset Alliance), m瓜t hiệp h瓜i bao gồm nhiều công ty trong đó có Texas Instruments, Tập đoàn Broadcom, Google, HTC, Intel, LG, Tập đoàn Marvell Technology, Motorola, Nvidia, Qualcomm, Samsung Electronics, Sprint Nextel và T-Mobile đ逢嬰c thành lập v噂i m映c đích phát triển các tiêu chuẩn m荏 cho thiết b鵜 di đ瓜ng. Cùng ngày, Android cũng đ逢嬰c ra mắt v噂i vai trò là s違n phẩm đầu tiên c栄a Liên minh, m瓜t nền t違ng thiết b鵜 di đ瓜ng đ逢嬰c xây dựng trên nhân Linux phiên b違n 2.6. Chiếc điện tho衣i ch衣y Android đầu tiên đ逢嬰c bán ra là HTC Dream, phát hành ngày 22 tháng 10 năm 2008. Biểu tr逢ng c栄a hệ điều hành Android m噂i là m瓜t con rôbốt màu xanh lá cây do hãng thiết kế Irina Blok t衣i California vẽ.

Từ năm 2008, Android đư tr違i qua nhiều lần cập nhật để dần dần c違i tiến hệ điều hành, bổ sung các tính năng m噂i và sửa các l厩i trong những lần phát hành tr逢噂c. M厩i b違n nâng c医p đ逢嬰c đặt tên lần l逢嬰t theo th泳 tự b違ng chữ cái, theo tên c栄a m瓜t món ăn tráng miệng; ví d映 nh逢 phiên b違n 1.5 Cupcake (bánh bông lan nh臼 có kem) tiếp nối bằng phiên b違n 1.6 Donut (bánh vòng). Phiên b違n m噂i nh医t là 4.3 Jelly Bean (kẹo dẻo). Vào năm 2010, Google ra mắt lo衣t thiết b鵜 Nexus—m瓜t dòng s違n phẩm bao gồm điện tho衣i thông minh và máy tính b違ng ch衣y hệ điều hành Android, do các đối tác phần c泳ng s違n xu医t. HTC đư h嬰p tác v噂i Google trong chiếc điện tho衣i thông minh Nexus đầu tiên, Nexus One. Kể từ đó nhiều thiết b鵜 m噂i hơn đư gia nhập vào dòng s違n phẩm này, nh逢 điện tho衣i Nexus 4 và máy tính b違ng Nexus 10, lần l逢嬰t do LG và Samsung s違n xu医t. Google xem điện tho衣i và máy tính b違ng Nexus là những thiết b鵜 Android ch栄 lực c栄a mình, v噂i những tính năng phần c泳ng và phần mềm m噂i nh医t c栄a Android.

B違ng d逢噂i đây thể hiện tỷ lệ sử d映ng các phiên b違n Android tính đến ngày 01/08/2013

Phiên b違n Tên mã Ngày phát hành Phiên b違n API Tỷ lệ

4.3 Jelly Bean July 24, 2013 18 0.0%

4.2.x Jelly Bean November 13, 2012 17 6.5%

4.1.x Jelly Bean July 9, 2012 16 34.0%

4.0.3–4.0.4 Ice Cream Sandwich December 16, 2011 15 22.5%

3.2 Honeycomb July 15, 2011 13 0.1%

3.1 Honeycomb May 10, 2011 12 0.0%

2.3.3–2.3.7 Gingerbread February 9, 2011 10 33.0%

2.3–2.3.2 Gingerbread December 6, 2010 9 0.1%

2.2 Froyo May 20, 2010 8 2.5%

2.0–2.1 Eclair October 26, 2009 7 1.2%

1.6 Donut September 15, 2009 4 0.1%

1.5 Cupcake April 30, 2009 3 0%

Page 16: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

16

Giao diện và ứng dụng

Giao diện

Giao diện ng逢運i dùng c栄a Android dựa trên nguyên tắc tác đ瓜ng trực tiếp, sử d映ng c違m 泳ng ch衣m t逢ơng tự nh逢 những đ瓜ng tác ngoài đ運i thực nh逢 vuốt, ch衣m, kéo dãn và thu l衣i để xử lý các đối t逢嬰ng trên màn hình. Sự ph違n 泳ng v噂i tác đ瓜ng c栄a ng逢運i dùng diễn ra gần nh逢 ngay lập t泳c, nhằm t衣o ra giao diện c違m 泳ng m逢嬰t mà, th逢運ng dùng tính năng rung c栄a thiết b鵜 để t衣o ph違n hồi rung cho ng逢運i dùng. Những thiết b鵜 phần c泳ng bên trong nh逢 gia tốc kế, con quay hồi chuyển và c違m biến kho違ng cách đ逢嬰c m瓜t số 泳ng d映ng sử d映ng để ph違n hồi m瓜t số hành đ瓜ng khác c栄a ng逢運i dùng, ví d映 nh逢 điều ch雨nh màn hình từ chế đ瓜 hiển th鵜 d丑c sang chế đ瓜 hiển th鵜 ngang tùy theo v鵜 trí c栄a thiết b鵜, hoặc cho phép ng逢運i dùng lái xe đua bằng xoay thiết b鵜, giống nh逢 đang điều khiển vô-lăng.

Các thiết b鵜 Android sau khi kh荏i đ瓜ng sẽ hiển th鵜 màn hình chính, điểm kh荏i đầu v噂i các thông tin chính trên thiết b鵜, t逢ơng tự nh逢 khái niệm desktop (bàn làm việc) trên máy tính để bàn. Màn hính chính Android th逢運ng gồm nhiều biểu t逢嬰ng (icon) và tiện ích (widget); biểu t逢嬰ng 泳ng d映ng sẽ m荏 泳ng d映ng t逢ơng 泳ng, còn tiện ích hiển th鵜 những n瓜i dung sống đ瓜ng, cập nhật tự đ瓜ng nh逢 dự báo th運i tiết, h瓜p th逢 c栄a ng逢運i dùng, hoặc những mẩu tin th運i sự ngay trên màn hình chính. Màn hình chính có thể gồm nhiều trang xem đ逢嬰c bằng cách vuốt ra tr逢噂c hoặc sau, mặc dù giao diện màn hình chính c栄a Android có thể tùy ch雨nh 荏 m泳c cao, cho phép ng逢運i dùng tự do sắp đặt hình dáng cũng nh逢 hành vi c栄a thiết b鵜 theo s荏 thích. Những 泳ng d映ng do các hãng th泳 ba có trên Google Play và các kho 泳ng d映ng khác còn cho phép ng逢運i dùng thay đổi "ch栄 đề" c栄a màn hình chính, thậm chí bắt ch逢噂c hình dáng c栄a hệ điều hành khác nh逢 Windows Phone chẳng h衣n. Phần l噂n những nhà s違n xu医t, và m瓜t số nhà m衣ng, thực hiện thay đổi hình dáng và hành vi c栄a các thiết b鵜 Android c栄a h丑 để phân biệt v噂i các hãng c衣nh tranh.

Page 17: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

17

Hình . Màn hình chính v噂i các biểu t逢嬰ng (icon) và tiện ích (widget)

雲 phía trên cùng màn hình là thanh tr衣ng thái, hiển th鵜 thông tin về thiết b鵜 và tình tr衣ng kết nối. Thanh tr衣ng thái này có thể "kéo" xuống để xem màn hình thông báo gồm thông tin quan tr丑ng hoặc cập nhật c栄a các 泳ng d映ng, nh逢 email hay tin nhắn SMS m噂i nhận, mà không làm gián đo衣n hoặc khiến ng逢運i dùng c違m th医y b医t tiện. Trong các phiên b違n đ運i đầu, ng逢運i dùng có thể nh医n vào thông báo để m荏 ra 泳ng d映ng t逢ơng 泳ng, về sau này các thông tin cập nhật đ逢嬰c bổ sung theo tính năng, nh逢 có kh違 năng lập t泳c g丑i ng逢嬰c l衣i khi có cu瓜c g丑i nhỡ mà không cần ph違i m荏 泳ng d映ng g丑i điện ra. Thông báo sẽ luôn nằm đó cho đến khi ng逢運i dùng đư đ丑c hoặc xóa nó đi.

Page 18: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

18

Hình . Thanh tr衣ng thái đang đ逢嬰c "kéo" xuống v噂i các thông báo bên trong

M瓜t điểm m衣nh c栄a hệ điều hành Android là cho phép ng逢運i d映ng ch衣y nhiều 泳ng d映ng cùng lúc (đa nhiệm - multi-tasking). Việc chuyển qua chuyển l衣i giữa các 泳ng d映ng đ逢嬰c thực hiện m瓜t cách dễ dàng bằng cách b医m và giữ phím Home để hiển th鵜 danh sách 泳ng d映ng đang ch衣y.

Hình . Danh sách 泳ng d映ng đang ch衣y trên thiêt b鵜 (đa nhiệm)

永ng d映ng

Android có l逢嬰ng 泳ng d映ng c栄a bên th泳 ba ngày càng nhiều, đ逢嬰c ch丑n l丑c và đặt trên m瓜t cửa hàng 泳ng d映ng nh逢 Google Play hay Amazon Appstore để ng逢運i dùng l医y về, hoặc bằng cách t違i xuống rồi cài đặt tập tin APK từ trang web khác. Các 泳ng d映ng trên Cửa hàng Play cho phép ng逢運i dùng duyệt, t違i về và cập nhật các 泳ng d映ng do Google và các nhà phát triển th泳 ba phát hành. Cửa hàng Play đ逢嬰c cài đặt sẵn trên các thiết b鵜 th臼a mưn điều kiện t逢ơng thích c栄a Google. 永ng d映ng sẽ tự đ瓜ng l丑c ra m瓜t danh sách các 泳ng d映ng t逢ơng thích v噂i thiết b鵜 c栄a ng逢運i dùng, và nhà phát triển có thể gi噂i h衣n 泳ng d映ng c栄a h丑 ch雨 dành cho những nhà m衣ng cố đ鵜nh hoặc những quốc gia cố đ鵜nh vì lý do kinh doanh. Nếu ng逢運i dùng mua m瓜t 泳ng d映ng mà h丑 c違m th医y không thích, h丑 đ逢嬰c hoàn tr違 tiền sau 15 phút kể từ lúc t違i về, và m瓜t vài nhà m衣ng còn có kh違 năng mua giúp các 泳ng d映ng trên Google Play, sau đó tính tiền vào trong hóa đơn sử d映ng hàng tháng c栄a ng逢運i dùng. Tính đến tháng 8 năm 2013, có hơn 975.000 泳ng d映ng dành cho Android trên cửa hàng Google Play, và số l逢嬰ng 泳ng d映ng t違i về từ Cửa hàng Play 逢噂c tính đ衣t gần 30 tỷ.

Page 19: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

19

Hình . Giao diện cửa hàng Play trên điện tho衣i Google Nexus 4

Các 泳ng d映ng cho Android đ逢嬰c phát triển bằng ngôn ngữ Java sử d映ng B瓜 phát triển phần mềm Android (SDK). SDK bao gồm m瓜t b瓜 đầy đ栄 các công c映 dùng để phát triển, gồm có công c映 gỡ l厩i, th逢 viện phần mềm, b瓜 gi違 lập điện tho衣i dựa trên QEMU, tài liệu h逢噂ng dẫn, mã nguồn mẫu, và h逢噂ng dẫn từng b逢噂c. Môi tr逢運ng phát triển tích h嬰p (IDE) đ逢嬰c h厩 tr嬰 chính th泳c là Eclipse sử d映ng phần bổ sung Android Development Tools (ADT). Các công c映 phát triển khác cũng có sẵn, gồm có B瓜 phát triển gốc dành cho các 泳ng d映ng hoặc phần m荏 r瓜ng viết bằng C hoặc C++, Google App Inventor, m瓜t môi tr逢運ng đồ h丑a cho những nhà lập trình m噂i bắt đầu, và nhiều nền t違ng 泳ng d映ng web di đ瓜ng đa nền t違ng phong phú.

Phát triển

Android đ逢嬰c Google tự phát triển riêng cho đến khi những thay đổi và cập nhật đư hoàn thiện, khi đó mư nguồn m噂i đ逢嬰c công khai. Mã nguồn này, nếu không sửa đổi, ch雨 ch衣y trên

Page 20: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

20

m瓜t số thiết b鵜, th逢運ng là thiết b鵜 thu瓜c dòng Nexus. Có nhiều thiết b鵜 có ch泳a những thành phần đ逢嬰c giữ b違n quyền do nhà s違n xu医t đặt vào thiết b鵜 Android c栄a h丑.

H衣t nhân Linux

Android có m瓜t h衣t nhân dựa trên nhân Linux phiên b違n 2.6, kể từ Android 4.0 Ice Cream Sandwich (bánh ng丑t kẹp kem) tr荏 về sau, là phiên b違n 3.x, v噂i middleware, th逢 viện và API viết bằng C, còn phần mềm 泳ng d映ng ch衣y trên m瓜t nền t違ng 泳ng d映ng gồm các th逢 viện t逢ơng thích v噂i Java dựa trên Apache Harmony.

Android sử d映ng máy 違o Dalvik v噂i m瓜t trình biên d鵜ch đ瓜ng để ch衣y 'mã dex' (Dalvik Executable) c栄a Dalvik, th逢運ng đ逢嬰c biên d鵜ch sang Java bytecode. Nền t違ng phần c泳ng chính c栄a Android là kiến trúc ARM. Ng逢運i ta cũng h厩 tr嬰 x86 thông qua dự án Android x86 (chip Intel Atom), và Google TV cũng sử d映ng m瓜t phiên b違n x86 đặc biệt c栄a Android.

Nhân Linux dùng cho Android đư đ逢嬰c Google thực hiện nhiều thay đổi về kiến trúc so v噂i nhân Linux gốc. Android không có sẵn X Window System cũng không h厩 tr嬰 các th逢 viện GNU chuẩn, nên việc chuyển các 泳ng d映ng hoặc th逢 viện Linux có sẵn sang Android r医t khó khăn. Các 泳ng d映ng C đơn gi違n và SDL cũng đ逢嬰c h厩 tr嬰 bằng cách chèn những đo衣n shim Java và sử d映ng t逢ơng tự JNI, nh逢 khi ng逢運i ta chuyển Jagged Alliance 2 sang Android.

M瓜t số tính năng cũng đ逢嬰c Google đóng góp ng逢嬰c vào nhân Linux, đáng chú ý là tính năng qu違n lý nguồn điện có tên wakelock, nh逢ng b鵜 những ng逢運i lập trình chính cho nhân từ chối vì h丑 c違m th医y Google không có đ鵜nh sẽ tiếp t映c b違o trì đo衣n mã do h丑 viết. Google thông báo vào tháng 4 năm 2010 rằng h丑 sẽ thuê hai nhân viên để làm việc v噂i c瓜ng đồng nhân Linux, nh逢ng Greg Kroah-Hartman, ng逢運i b違o trì nhân Linux hiện t衣i c栄a nhánh ổn đ鵜nh, đư nói vào tháng 12 năm 2010 rằng ông ta lo ng衣i rằng Google không còn muốn đ逢a những thay đổi c栄a mình vào Linux dòng chính nữa. M瓜t số lập trình viên Android c栄a Google t臼 ý rằng "nhóm Android th医y chán v噂i quy trình đó," vì nhóm h丑 không có nhiều ng逢運i và có nhiều việc khẩn c医p cần làm v噂i Android hơn.

Vào tháng 8 năm 2011, Linus Torvalds phát biểu rằng "rốt cu瓜c thì Android và Linux cũng sẽ tr荏 l衣i v噂i m瓜t b瓜 nhân chung, nh逢ng điều đó có thể sẽ không x違y ra trong 4 hoặc 5 năm nữa". Vào tháng 12 năm 2011, Greg Kroah-Hartman thông báo kích ho衣t Dự án Dòng chính Android, nhắm t噂i việc đ逢a m瓜t số driver, b違n vá và tính năng c栄a Android ng逢嬰c vào nhân Linux, bắt đầu từ Linux 3.3. Linux cũng đ逢a tính năng autosleep (tự ngh雨 ho衣t đ瓜ng) và wakelocks vào nhân 3.5, sau nhiều n厩 lực phối tr瓜n tr逢噂c đó. T逢ơng tác thì vẫn vậy nh逢ng b違n hiện thực trên Linux dòng chính cho phép hai chế đ瓜 ngh雨: b瓜 nh噂 (d衣ng ngh雨 truyền thống mà Android sử d映ng), và đĩa (là ng栄 đông trên máy tính để bàn). Việc tr瓜n sẽ hoàn t医t kể từ nhân 3.8, Google đư công khai kho mư nguồn trong đó có những đo衣n thử nghiệm đ逢a Android về l衣i nhân 3.8.

B瓜 l逢u trữ flash trên các thiết b鵜 Android đ逢嬰c chia thành nhiều phân vùng, nh逢 "/system" dành cho hệ điều hành và "/data" dành cho dữ liệu ng逢運i dùng và cài đặt 泳ng d映ng. Khác v噂i các b違n phân phối Linux cho máy tính để bàn, ng逢運i s荏 hữu thiết b鵜 Android không đ逢嬰c trao quyền truy cập root vào hệ điều hành và các phân vùng nh衣y c違m nh逢 /system đ逢嬰c thiêt lập ch雨 đ丑c. Tuy nhiên, quyền truy cập root có thể chiếm đ逢嬰c bằng cách tận d映ng những l厩

Page 21: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

21

hổng b違o mật trong Android, điều mà c瓜ng đồng mã nguồn m荏 th逢運ng xuyên sử d映ng để nâng cao tính năng thiết b鵜 c栄a h丑, kể c違 b鵜 những ng逢運i ác ý sử d映ng để cài virus và phần mềm ác ý.

Việc Android có đ逢嬰c xem là m瓜t b違n phân phối Linux hay không vẫn còn là v医n đề gây tranh cưi, tuy đ逢嬰c Linux Foundation và Chris DiBona, tr逢荏ng nhóm mã nguồn m荏 Google, 栄ng h瓜. M瓜t số khác, nh逢 linux-magazine.com thì không đồng ý, do Android không không h厩 tr嬰 nhiều công c映 GNU, trong đó có glibc.

Qu違n lý b瓜 nhớ

Vì các thiết b鵜 Android ch栄 yếu ch衣y bằng pin, nên Android đ逢嬰c thiết kế để qu違n lý b瓜 nh噂 (RAM) để gi違m tối đa tiêu th鵜 điện năng, trái v噂i hệ điều hành máy tính để bàn luôn cho rằng máy tính sẽ có nguồn điện không gi噂i h衣n. Khi m瓜t 泳ng d映ng Android không còn đ逢嬰c sử d映ng, hệ thống sẽ tự đ瓜ng ng逢ng nó trong b瓜 nh噂 - trong khi 泳ng d映ng về mặt kỹ thuật vẫn "m荏", những 泳ng d映ng này sẽ không tiêu th映 b医t c泳 tài nguyên nào (nh逢 năng l逢嬰ng pin hay năng l逢嬰ng xử lý) và nằm đó cho đến khi nó đ逢嬰c cần đến. Cách làm nh逢 vậy có l嬰i kép là vừa làm tăng kh違 năng ph違n hồi nói chung c栄a thiết b鵜 Android, vì 泳ng d映ng không nh医t thiết ph違i đóng rồi m荏 l衣i từ đầu, vừa đ違m b違o các 泳ng d映ng nền không làm tiêu hao năng l逢嬰ng m瓜t cách không cần thiết.

Android qu違n lý các 泳ng d映ng trong b瓜 nh噂 m瓜t cách tự đ瓜ng: khi b瓜 nh噂 th医p, hệ thống sẽ bắt đầu diệt 泳ng d映ng và tiến trình không ho衣t đ瓜ng đ逢嬰c m瓜t th運i gian, sắp theo th運i điểm cuối mà chúng đ逢嬰c sử d映ng (t泳c là cũ nh医t sẽ b鵜 tắt tr逢噂c). Tiến trình này đ逢嬰c thiết kế ẩn đi v噂i ng逢運i dùng, để ng逢運i dùng không cần ph違i qu違n lý b瓜 nh噂 hoặc tự tay tắt các 泳ng d映ng. Tuy nhiên, sự che gi医u này c栄a hệ thống qu違n lý b瓜 nh噂 Android đư dẫn đến sự th鵜nh hành c栄a các 泳ng d映ng tắt ch逢ơng trình c栄a bên th泳 ba trên cửa hàng Google Play; những 泳ng d映ng kiểu nh逢 vậy đ逢嬰c cho là có h衣i nhiều hơn có l嬰i.

C瓜ng đồng mã nguồn mở

Android có m瓜t c瓜ng đồng các lập trình viên và những ng逢運i đam mê r医t năng đ瓜ng. H丑 sử d映ng mã nguồn Android để phát triển và phân phối những phiên b違n ch雨nh sửa c栄a hệ điều hành. Các b違n Android do c瓜ng đồng phát triển th逢運ng đem những tính năng và cập nhật m噂i vào nhanh hơn các kênh chính th泳c c栄a nhà s違n xu医t/nhà m衣ng, tuy không đ逢嬰c kiểm thử kỹ l逢ỡng cũng nh逢 không có đ違m b違o ch医t l逢嬰ng; cung c医p sự h厩 tr嬰 liên t映c cho các thiết b鵜 cũ không còn nhận đ逢嬰c b違n cập nhật chính th泳c; hoặc mang Android vào những thiết b鵜 ban đầu ch衣y m瓜t hệ điều hành khác, nh逢 HP Touchpad. Các b違n Android c栄a c瓜ng đồng th逢運ng đ逢嬰c root sẵn và có những điều ch雨nh không phù h嬰p v噂i những ng逢運i dùng không rành rẽ, nh逢 kh違 năng ép xung hoặc tăng/gi違m áp b瓜 xử lý c栄a thiết b鵜. CyanogenMod là firmware c栄a c瓜ng đồng đ逢嬰c sử d映ng phổ biến nh医t, và là cơ s荏 cho r医t nhiều firmware khác phát triển dựa trên b違n firmware này.

Tr逢噂c đây, nhà s違n xu医t thiết b鵜 và nhà m衣ng t臼 ra thiếu thiện chí v噂i việc phát triển firmware c栄a bên th泳 ba. Những nhà s違n xu医t còn thể hiện lo ng衣i rằng các thiết b鵜 ch衣y phần mềm không chính th泳c sẽ ho衣t đ瓜ng không tốt và dẫn đến tốn tiền h厩 tr嬰. Hơn nữa, các firmware đư thay đổi nh逢 CyanogenMod đôi khi còn cung c医p những tính năng, nh逢 truyền t違i m衣ng (tethering), mà ng逢運i dùng bình th逢運ng ph違i tr違 tiền nhà m衣ng m噂i đ逢嬰c sử d映ng. Kết qu違 là nhiều thiết b鵜 bắt đầu đặt ra hàng rào kỹ thuật nh逢 khóa bootloader hay h衣n chế quyền truy cập

Page 22: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

22

root. Tuy nhiên, khi phần mềm do c瓜ng đồng phát triển ngày càng tr荏 nên phổ biến, và sau m瓜t thông cáo c栄a Th逢 viện Quốc h瓜i Hoa Kỳ cho phép "jailbreak" (v逢嬰t ng映c) thiết b鵜 di đ瓜ng, các nhà s違n xu医t và nhà m衣ng đư t臼 ra mềm m臼ng hơn v噂i các nhà phát triển th泳 ba, thậm chí m瓜t số hưng nh逢 HTC, Motorola, Samsung và Sony, còn h厩 tr嬰 và khuyến khích phát triển. Kết qu違 c栄a việc này là dần dần nhu cầu tìm ra các h衣n chế phần c泳ng để cài đặt đ逢嬰c firmware không chính th泳c đư b噂t đi do ngày càng nhiều thiết b鵜 đ逢嬰c phát hành v噂i bootloader đư m荏 khóa sẵn hoặc có thể m荏 khóa, t逢ơng tự nh逢 điện tho衣i dòng Nexus, tuy rằng thông th逢運ng h丑 sẽ yêu cầu ng逢運i dùng từ b臼 chế đ瓜 b違o hành nếu h丑 làm nh逢 vậy. Tuy nhiên, tuy đ逢嬰c sự ch医p thuận c栄a nhà s違n xu医t, m瓜t số nhà m衣ng t衣i Mỹ vẫn bắt bu瓜c điện tho衣i ph違i b鵜 khóa.

Bảo mật ┗<àtケnhàriêngàtư

Các 泳ng d映ng Android ch衣y trong m瓜t "h瓜p cát" (sandboxed applications), là m瓜t khu vực riêng rẽ v噂i hệ thống và không đ逢嬰c tiếp cận đến phần còn l衣i c栄a tài nguyên hệ thống, trừ khi nó đ逢嬰c ng逢運i dùng trao quyền truy cập m瓜t cách công khai khi cài đặt. Tr逢噂c khi cài đặt 泳ng d映ng, Cửa hàng Play sẽ hiển th鵜 t医t c違 các quyền mà 泳ng d映ng đòi h臼i: ví d映 nh逢 m瓜t trò chơi cần ph違i kích ho衣t b瓜 rung hoặc l逢u dữ liệu vào thẻ nh噂 SD, nh逢ng nó không nên cần quyền đ丑c tin nhắn SMS hoặc tiếp cận danh b衣 điện tho衣i. Sau khi xem xét các quyền này, ng逢運i dùng có thể ch丑n đồng ý hoặc từ chối chúng, 泳ng d映ng ch雨 đ逢嬰c cài đặt khi ng逢運i dùng đồng ý.

Page 23: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

23

Hình . Yêu cầu ch医p nhận các quyền 泳ng d映ng đ逢嬰c phép sử d映ng tr逢噂c khi cài đặt

Hệ thống h瓜p cát và h臼i quyền làm gi違m b噂t 違nh h逢荏ng c栄a l厩i b違o mật hoặc l厩i ch逢ơng trình có trong 泳ng d映ng, nh逢ng sự thiếu kinh nghiệm c栄a lập trình viên và tài liệu h逢噂ng dẫn còn h衣n chế đư dẫn t噂i những 泳ng d映ng hay đòi h臼i những quyền không cần thiết, do đó làm gi違m đi hiệu qu違 c栄a hệ thống này. M瓜t số công ty b違o mật, nh逢 Lookout Mobile Security, AVG Technologies, và McAfee, đư phát hành những phần mềm diệt virus cho các thiết b鵜 Android. Phần mềm này không có hiệu qu違 vì cơ chế h瓜p cát vẫn áp d映ng vào các 泳ng d映ng này, do vậy làm h衣n chế kh違 năng quét sâu vào hệ thống để tìm nguy cơ.

M瓜t nghiên c泳u c栄a công ty b違o mật Trend Micro đư liệt kê tình tr衣ng l衣m d映ng d鵜ch v映 tr違 tiền là hình th泳c phần mềm ác ý phổ biến nh医t trên Android, trong đó tin nhắn SMS sẽ b鵜 gửi đi từ điện tho衣i b鵜 nhiễm đến m瓜t số điện tho衣i tr違 tiền mà ng逢運i dùng không hề hay biết. Lo衣i phần mềm ác ý khác hiển th鵜 những qu違ng cáo không mong muốn và gây khó ch鵜u trên thiết b鵜, hoặc gửi thông tin cá nhân đến bên th泳 ba khi ch逢a đ逢嬰c phép. Đe d丑a b違o mật trên Android đ逢嬰c cho là tăng r医t nhanh theo c医p số mũ; tuy nhiên, các kỹ s逢 Google ph違n bác rằng hiểm h丑a

Page 24: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

24

từ phần mềm ác ý và virus đư b鵜 thổi phồng b荏i các công ty b違o mật nhằm m映c đích th逢ơng m衣i, và bu瓜c t瓜i ngành công nghiệp b違o mật đang l嬰i d映ng sự s嬰 hưi để bán phần mềm diệt virus cho ng逢運i dùng. Google vẫn giữ quan điểm rằng phần mềm ác ý thật sự nguy hiểm là cực kỳ hiếm, và m瓜t cu瓜c điều tra do F-Secure thực hiện cho th医y ch雨 có 0,5% số phần mềm ác ý Android là len vào đ逢嬰c cửa hàng Google Play.

Google hiện đang sử d映ng b瓜 quét phần mềm ác ý Google Bouncer để theo dõi và quét các 泳ng d映ng trên Cửa hàng Google Play. Nó sẽ đánh d医u các phần mềm b鵜 nghi ng運 và c違nh báo ng逢運i dùng về những v医n đề có thể x違y ra tr逢噂c khi h丑 t違i nó về máy. Android phiên b違n 4.2 Jelly Bean đ逢嬰c phát hành vào năm 2012 cùng v噂i các tính năng b違o mật đ逢嬰c c違i thiện, bao gồm m瓜t b瓜 quét phần mềm ác ý đ逢嬰c cài sẵn trong hệ thống, ho衣t đ瓜ng cùng v噂i Google Play nh逢ng cũng có thể quét các 泳ng d映ng đ逢嬰c cài đặt từ nguồn th泳 ba, và m瓜t hệ thống c違nh báo sẽ thông báo cho ng逢運i dùng khi m瓜t 泳ng d映ng cố gắng gửi m瓜t tin nhắn vào số tính tiền, chặn tin nhắn đó l衣i trừ khi ng逢運i dùng công khai cho phép nó.

Điện tho衣i thông minh Android có kh違 năng báo cáo v鵜 trí c栄a điểm truy cập Wi-Fi, phát hiện ra việc di chuyển c栄a ng逢運i dùng điện tho衣i, để xây dựng những cơ s荏 dữ liệu có ch泳a v鵜 trí c栄a hàng trăm triệu điểm truy cập. Những cơ s荏 dữ liệu này t衣o nên m瓜t b違n đồ điện tử để tìm v鵜 trí điện tho衣i thông minh, cho phép chúng ch衣y các 泳ng d映ng nh逢 Foursquare, Google Latitude, Facebook Places, và gửi những đo衣n qu違ng cáo dựa trên v鵜 trí. Phần mềm theo dõi c栄a bên th泳 ba nh逢 TaintDroid, m瓜t dự án nghiên c泳u trong tr逢運ng đ衣i h丑c, đôi khi có thể biết đ逢嬰c khi nào thông tin cá nhân b鵜 gửi đi từ 泳ng d映ng đến các máy ch栄 đặt 荏 xa.

Máy ảo Dalvik

Java đ逢嬰c biết đến v噂i khẩu hiệu "viết m瓜t lần, ch衣y m丑i nơi" (write once, run anywhere). Tính năng này c栄a hệ sinh thái Java có đ逢嬰c nh運 m瓜t l噂p máy 違o đ泳ng giữa l噂p 泳ng d映ng (viết bằng Java) và l噂p hệ điều hành (nhiều lo衣i khác nhau), g丑i là máy 違o Java - JVM (Java Virtual Machine). Máy 違o Java ch衣y r医t ổn đ鵜nh và đồng nh医t trên các môi tr逢運ng máy tính cá nhân (JSE) và máy ch栄 (JEE), tuy nhiên trong môi tr逢運ng di đ瓜ng (JME) thì máy 違o Java b鵜 phân m違nh t逢ơng đối nhiều v噂i các gói (pakages), c医u hình (configurations) và các mẫu (profiles) khác nhau.

Google đư ch丑n Java làm ngôn ngữ phát triển 泳ng d映ng cho hệ điều hành Android, tuy nhiên l衣i từ b臼 c違 phiên b違n Java di đ瓜ng (JME) lẫn máy 違o Java (JVM) để phát triển m瓜t máy 違o riêng - máy 違o Dalvik và tập th逢 viện Java chuẩn đ逢嬰c viết l衣i và thu g丑n hơn.

永ng d映ng Android đ逢嬰c phát triển bằng ngôn ngữ Java, sau đó đ逢嬰c biên d鵜ch thành d衣ng mã nh鵜 phân Java (Java bytecode). Các file nh鵜 phân .class (t逢ơng thích v噂i JVM) này sẽ đ逢嬰c chuyển đổi thành 1 file nh鵜 phân dùng cho máy 違o Dalvik - .dex (Dalvik EXecutable) tr逢噂c khi đ逢嬰c cài lên thiết b鵜. Các tập tin .dex đ逢嬰c thiết kế để phù h嬰p hơn v噂i các thiết b鵜 h衣n chế về b瓜 nh噂 cũng nh逢 hiệu năng xử lý.

Page 25: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

25

Dalvik là m瓜t phần mềm mã nguồn m荏, ban đầu đ逢嬰c phát triển b荏i Dan Bornstein, và đ逢嬰c ông đặt tên theo tên ngôi làng Dalvík t衣i Eyjafjörður, Iceland, quê h逢ơng c栄a ông.

Ki 院n trúc

Hệ điều hành Android đ逢嬰c thiết kế h逢噂ng đến r医t nhiều các lo衣i thiết b鵜 khác nhau, từ những thiết b鵜 giá rẻ, c医u hình th医p (low-end) đến những siêu phẩm đắt tiền (high-end). Bên c衣nh đó các 泳ng d映ng Android ph違i đ逢嬰c ch衣y trong "h瓜p cát" v噂i đ瓜 b違o mật cao, hiệu năng tốt và ổn đ鵜nh, vì vậy việc sử d映ng m瓜t máy 違o làm môi tr逢運ng thực thi là điều t医t yếu. Tuy nhiên việc sử d映ng máy 違o th逢運ng sẽ làm gi違m hiệu năng c栄a hệ thống. Gi違i pháp máy 違o Dalvik c栄a Google đ逢嬰c đ逢a ra nhằm cân bằng giữa 2 điểm này:

- M厩i 泳ng d映ng Android đ逢嬰c ch衣y trong tiến trình riêng, v噂i m瓜t thực thể (instance) c栄a máy 違o Dalvik riêng. Dalvik đ逢嬰c thiết kế để hệ điều hành có thể ch衣y nhiều thực thể c栄a máy 違o m瓜t cách hiệu qu違 v噂i file thực thi Dalvik (.dek file) đ逢嬰c thiết kế để tối 逢u hóa b瓜 nh噂 cần sử d映ng. Máy 違o Dalvik là máy 違o dựa trên thanh ghi (register-based), khác v噂i máy 違o Java ch衣y dựa trên c医u trúc ngăn xếp (stack-based).

- Máy 違o Dalvik sử d映ng h衣t nhân Linux cho các việc liên quan đến lơp d逢噂i c栄a hệ thống nh逢 qu違n lý tiểu trình (threading), qu違n lý b瓜 nh噂 c医p th医p...

Do m厩i 泳ng d映ng ch衣y trên m瓜t thực thể máy 違o riêng, hệ thống Android không những cần tối 逢u việc ch衣y nhiều máy 違o và còn ph違i gi違m tối đa th運i gian kh荏i t衣o máy 違o m噂i. Phần d逢噂i đây sẽ xem xét 4 điểm chính trong thiết kế máy 違o mà Google đư ch丑n lựa để đ衣t đ逢嬰c hiệu năng và đ瓜 b違o mật cần thiết: c医u trúc file .dex, Zygote, c医u trúc dựa trên thanh ghi và b違o mật.

Đ鵜nh d衣ng file .dex

Trong môi tr逢運ng Java truyền thống, mã nguồn Java đ逢嬰c biên d鵜ch thành d衣ng bytecode, 荏 đó m厩i class trong mã nguồn đ逢嬰c biên d鵜ch thành m瓜t file .class riêng.

Trong hệ thống Android, mã nguồn Java cũng đ逢嬰c biên d鵜ch thành các file .class riêng. Tuy nhiên tr逢噂c khi có thể đ逢嬰c cài đặt lên thiết b鵜, các file này ph違i đ逢嬰c chuyển đổi thành file

Page 26: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

26

thực thi Dalvik (.dex) bằng công c映 "dx" có trong Android SDK. File thực thi Dalvik có thể ch泳a nhiều class bên trong và m厩i 泳ng d映ng Android ch雨 ch泳a m瓜t file .dex duy nh医t.

File thực thi Dalvik đ逢嬰c thiết kế nhắm đến tối 逢u b瓜 nh噂 trên cơ s荏 chia sẻ (dùng chung) dữ liệu. Biểu đồ d逢噂i đây phân biệt c医u trúc file .dex v噂i file .class truyền thống.

Hình . C医u trúc Java class file và file thực thi Dalvik

Cơ chế chính c栄a file .dex cho việc tiết kiệm b瓜 nh噂 là dùng chung các vùng nh噂 ch泳a hằng số cho t医t c違 các class. Các vùng nh噂 cho hằng số này đ逢嬰c chia theo từng lo衣i dữ liệu (hằng số chu厩i, tên tr逢運ng, tên class, tên method...). Trong mã lệnh c栄a các class bên d逢噂i sẽ không cần ghi l衣i các tên/hằng số này mà ch雨 ch泳a ch雨 số (số nguyên) c栄a nó trong vùng hằng số.

Đối v噂i các file .class truyền thống, m厩i class file ch泳a vùng nh噂 riêng cho các hằng số c栄a class đó. Vùng nh噂 này không đồng nh医t vì nó ch泳a t医t c違 các lo衣i hằng số, không phân biệt theo lo衣i nh逢 trong tr逢運ng h嬰p c栄a .dex file. Việc lặp l衣i khai báo các hằng số này 荏 nhiều file .class khiến tổng kích th逢噂c các file .class lơn hơn nhiều so v噂i file thực thi Dalvik.

Theo số liệu thống kế, trung bình trong m厩i file .class, 61% kích th逢噂c c栄a file là các hằng số (!!!), các mã c栄a các ph逢ơng th泳c (method) ch雨 ch泳a kho違ng 33%, còn l衣i 5% cho các phần khác c栄a class. Nh逢 vậy việc tiết kiệm vùng nh噂 cho hằng số dẫn đến tiết kiệm đáng kể

Page 27: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

27

k鵜ch th逢噂c file thực thi (thông th逢運ng là kho違ng 50%), từ đó tiết kiệm đ逢嬰c l逢嬰ng b瓜 nh噂 cần c医p phát lúc thực thi 泳ng d映ng.

Zygote

Các 泳ng d映ng Android đ逢嬰c ch衣y trong các thực thể máy 違o riêng, vì vậy máy 違o ph違i đ逢嬰c "kh荏i đ瓜ng" nhanh và sử d映ng tối thiểu b瓜 nh噂 cần thiết. Để đ衣t đ逢嬰c điều này, hệ thống Android đ逢a ra m瓜t cơ chế giúp các thực thể máy 違o có thể chia sẻ mã lệnh dùng chung và "kh荏i đ瓜ng" nhanh, g丑i là Zygote.

Hầu hết các 泳ng d映ng Android đều dùng chung m瓜t số th逢 viện lõi và c医u trúc b瓜 nh噂 heap kèm theo nó. Thêm vào đó, vùng nh噂 heap c栄a các th逢 viện lõi này th逢運ng ch雨 đ逢嬰c truy xu医t m瓜t chiều ch雨 đ丑c (read-only). L嬰i d映ng điểm này, Zygote, m瓜t tiến trình máy 違o Dalvik đ逢嬰c kh荏i ch衣y lúc kh荏i đ瓜ng thiết b鵜, n衣p sẵn các th逢 viện lõi c栄a hệ điều hành mà các 泳ng d映ng th逢運ng xuyên sử d映ng, để sẵn sàng cho các máy 違o sử d映ng. M厩i lần m瓜t 泳ng d映ng đ逢嬰c ch衣y, hệ thống sẽ kh荏i đ瓜ng m瓜t máy 違o m噂i, tuy nhiên máy 違o này sẽ không cần ch泳a những th逢 viện lõi, mà sử d映ng luông th逢 viện lõi trong Zygote, khiến th運i gian kh荏i t衣o máy 違o là tối thiểu.

Các th逢 viện lõi trong hầu hết các tr逢運ng h嬰p là "ch雨 đ丑c" ch泳 không b鵜 ghi đè b荏i 泳ng d映ng. Trong tr逢運ng h嬰p 泳ng d映ng có nhu cầu ghi vào vùng nh噂 heap c栄a các th逢 viện lõi này, m瓜t b違n sao c栄a vùng nh噂 Zygote sẽ đ逢嬰c t衣o ra riêng cho tiến trình c栄a 泳ng d映ng đó. Cơ chế "sao chép khi ghi" (copy-on-write) này giúp tối 逢u hóa việc sử d映ng chung mã lệnh c栄a th逢 viện lõi mà vẫn đ違m b違o tính b違o mật giữa các 泳ng d映ng: việc thay đổi dữ liệu trong b瓜 nh噂 c栄a 泳ng d映ng này không 違nh h逢荏ng đến các 泳ng d映ng khác.

Trong JVM truyền thống, m厩i thực thể c栄a máy 違o Java sẽ có m瓜t tập các th逢 viện lõi riêng cùng vùng nh噂 t逢ơng 泳ng cho chúng, không có sự chia sẻ b瓜 nh噂 giữa các thực thể c栄a máy 違o.

Ki 院n trúc máy 違o dựa trên thanh ghi

Theo truyền thống, các nhà phát triển máy 違o th逢運ng lựa ch丑n kiến trúc dựa trên ngăn xếp (stack-based architecture) hơn là kiến trúc dựa trên thanh ghi (register-based architecture) do việc thiết kế máy 違o và trình biên d鵜ch cho kiến trúc ngăn xếp đơn gi違n hơn so v噂i tr逢運ng h嬰p c栄a kiến trúc thanh ghi. Bù l衣i cho sự đơn gi違n là hiệu su医t gi違m đi.

Các nghiên c泳u đư ch雨 ra rằng, kiến trúc dựa trên thanh ghi th逢運ng đòi h臼i số l逢嬰ng mã lệnh thực thi cho 泳ng d映ng ít hơn trung bình là 47% so v噂i tr逢運ng h嬰p dùng ngăn xếp. Bù l衣i kích th逢噂c mã lệnh th逢運ng l噂n hơn kho違ng 25%. Tuy nhiên sự gia tăng về kích th逢噂c mã lệnh này ch雨 phát sinh thêm kho違ng 1.07% t違i c栄a CPU thật. Các trình đánh giá tiêu chuẩn cho th医y hiệu su医t tổng thể c栄a máy 違o dựa trên kiến trúc thanh ghi cao hơn kho違ng 32.3% so v噂i kiến trúc ngăn xếp.

V噂i yêu cầu ch衣y trên các thiết b鵜 v噂i hiệu năng tính toán th医p, việc máy 違o Dalvik lựa ch丑n kiến trúc thanh ghi là hoàn toàn h嬰p lý. Mặc dù kích th逢噂c mã lệnh l噂n hơn trung bình 25%, việc sử d映ng vùng nh噂 chung cho hằng số c栄a file .dex giúp kích th逢噂c mã lệnh gi違m đi đến 50% khiến file thực thi Dalvik vẫn hiệu qu違 hơn đáng kể về mặt b瓜 nh噂 so v噂i các file .class truyền thống.

Page 28: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

28

B違o mật

Mặc đ鵜nh theo kiến trúc b違o mật c栄a hệ điều hành Android, m厩i 泳ng d映ng không có quyền thực thi b医t c泳 thao tác nào 違nh h逢荏ng đến các 泳ng d映ng khác, đến hệ điều hành hay ng逢運i dùng, bao gồm: đ丑c/ghi dữ liệu cá nhân (nh逢 danh b衣, emails...), đ丑c/ghi file dữ liệu c栄a 泳ng d映ng khác, thực hiện kết nối m衣ng, giữ màn hình luôn sáng...

Tính năng này đ逢嬰c thực hiện từ l噂p hệ điều hành và l噂p khung 泳ng d映ng (application framework) ch泳 không ph違i bên trong máy 違o Dalvik. M厩i 泳ng d映ng đ逢嬰c ch衣y trong m瓜t máy 違o riêng, máy 違o này l衣i đ逢嬰c ch衣y trong m瓜t tiến trình riêng. M厩i tiến trình đ逢嬰c ch衣y d逢噂i m瓜t mư ng逢運i dùng (user ID) riêng, đ逢嬰c sinh ra lúc cài đặt và đ逢嬰c phân quyền ch雨 đ逢嬰c truy cập m瓜t sô tính năng nh医t đ鵜nh c栄a hệ điều hành và các tập tin riêng c栄a mình. Nếu 泳ng d映ng có các yêu cầu đặc biệt đến các tính năng khác c栄a hệ thống thì ph違i khai báo các quyền t逢ơng 泳ng trong file mô t違 泳ng d映ng (AndroidManifest.xml) và sẽ đ逢嬰c c医p các quyền này lúc cài đặt nếu đ逢嬰c sự đồng ý từ ng逢運i dùng.

2.2. Lập trình cho thiết bị Android

Bộ phát triển phần mềm Android (Android SDK)

Hệ sinh thái Android đ逢嬰c c医u thành từ 3 thành phần tổng quan nh逢 sau:

- Hệ điều hành mã nguồn m荏 cho thiết b鵜 nhúng

- B瓜 công c映 phát triển phần mềm (mã nguồn m荏) - Android SDK

- Các thiết b鵜 (ch栄 yếu là điện tho衣i thông minh) ch衣y hệ điều hành Android v噂i các 泳ng d映ng đ逢嬰c phát triển cho chúng

Trong đó Android SDK là b瓜 phát triển phần mềm Android đ逢嬰c Google đ逢a ra d逢噂i d衣ng mã nguồn m荏, giúp ng逢運i lập trình có thể dễ dàng truy xu医t vào các tính năng c栄a hệ điều hành nh逢:

- M衣ng điện tho衣i cho việc nghe g丑i/SMS cũng nh逢 truy cập Internet: GSM/GRPS, EGDE, 3G, 4G, LTE...

- Tập APIs cho các 泳ng d映ng h逢噂ng v鵜 trí (GPS, v鵜 trí dựa trên kết nối m衣ng)

- Tích h嬰p 泳ng d映ng b違n đồ thành 1 thành phần c栄a 泳ng d映ng

- Kết nối m衣ng WiFi và kết nối điểm-t噂i-điểm (peer-to-peer)

- Các 泳ng d映ng đa ph逢ơng tiện: ghi hình, ghi âm v噂i camera và microphone, phát nh衣c, phát video...

- Th逢 viện đa ph逢ơng tiện vơi kh違 năng thu và phát nhiều lo衣i audio và video, cũng nh逢 các 違nh tĩnh

- API truy cập đến các c違m biến: c違m biến gia tốc, tiệm cận, la bàn...

- Th逢 viện cho việc sử d映ng Bluetooth và NFC cho kết nối điểm-t噂i-điểm

- Chia sẻ dữ liệu và trao đổi dữ liệu giữa các 泳ng d映ng

- API cho các kho dữ liệu chia sẻ nh逢 danh b衣, l鵜ch, m衣ng xã h瓜i, đa ph逢ơng tiện...

Page 29: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

29

- Các 泳ng d映ng/tác v映 ch衣y ngầm

- Các tiện ích (widget) trên màn hình chính và hình nền đ瓜ng

- Tích h嬰p kh違 năng tìm kiếm c栄a 泳ng d映ng vào công c映 tìm kiếm c栄a hệ thống

- Trình duyệt HTML5 mã nguồn m荏, dựa trên Webkit

- B瓜 tăng tốc đồ h丑a bằng phần c泳ng (GPU) cho việc tối 逢u hiệu năng hiển th鵜, bao gồm nh逢ng không gi噂i h衣n 荏 đồ h丑a 2D và 3D v噂i OpenGL ES 2.0

- H厩 tr嬰 đa ngôn ngữ v噂i cơ chế cung c医p tài nguyên đặc tr逢ng

- Cơ chế sử d映ng l衣i các thành phần c栄a 泳ng d映ng cũng nh逢 thay thế các 泳ng d映ng sẵn có

- L逢u trữ và truy xu医t dữ liệu v噂i CSDL Sqlite 3.0

- Google Clound Message cho qu違n lý việc đẩy thống báo xuống thanh hệ thống

- ...

B瓜 SDK đầy đ栄 sau khi t違i về sẽ bao gồm t医t c違 các thành phần cần thiết cho việc viết code, gỡ rối, kiểm thử, biên d鵜ch và xu医t b違n phần mềm nh逢:

- Android API - là các th逢 viện lõi c栄a b瓜 SDK, giúp ng逢運i lập trình truy xu医t các thành phần c栄a hệ điều hành. Các 泳ng d映ng c栄a Google cài sẵn trên thiết b鵜 cũng đ逢嬰c phát triển dựa trên các API này.

- Công c映 phát triển: bao gồm các công c映 dùng cho việc biên d鵜ch và gỡ rối 泳ng d映ng

- B瓜 qu違n lý các thiết b鵜 違o và b瓜 gi違 lập thiết b鵜: cho phép ng逢運i lập trình ch衣y thử 泳ng d映ng trên m瓜t hoặc nhiều thiết b鵜 違o thông qua b瓜 gi違 lập trên máy tính cá nhân mà không cần thiết b鵜 di đ瓜ng thật.

- B瓜 tài liệu tra c泳u r医t chi tiết về mô t違 và cách sử d映ng cho t医t c違 các gói và các l噂p, cũng nh逢 các bài viết hữu ích khác.

- Các mã nguồn mẫu: b瓜 SDK cũng đi kèm v噂i những 泳ng d映ng mẫu, nhằm biểu diễn các tính năng c栄a Android v噂i các ví d映 chi tiết về việc sử d映ng các API

Đối v噂i những ng逢運i dùng Eclipse làm môi tr逢運ng phát triển tích h嬰p, Google cũng phát triển m瓜t trình cắm thêm cho IDE g丑i là Android Developer Tools (ADT) giúp việc phát triển 泳ng d映ng Android tr荏 nên dễ dàng hơn r医t nhiều. Ta sẽ làm quen v噂i trình cắm thêm ADT 荏 các phần sau c栄a tài liệu.

Các lớp phần m隠m Android (software stack)

Để đ違m b違o sự đơn gi違n, tính dùng chung và b違o mật trong các 泳ng d映ng trên hệ thống Android, các th逢 viện cho 泳ng d映ng Android đ逢嬰c chia ra thành các phân l噂p từ th医p đến cao, các thành phần 荏 l噂p trên ch栄 yếu sử d映ng các d鵜ch v映 do các l噂p ngay bên d逢噂i cung c医p mà ít khi ph違i dùng đến các API c栄a các l噂p th医p hơn. Kiến trúc này đ逢嬰c chia ra thành các tầng chính nh逢 trong hình vẽ d逢噂i đây.

Page 30: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

30

Hình . Các l噂p phần mềm trong Android

雲 đó:

H衣t nhân Linux (Linux kernel) - bao gồm các d鵜ch v映 lõi (trình điều khiển phần c泳ng, qu違n lý tiến trình, b瓜 nh噂, m衣ng, nguồn điện và b違o mật...). H衣t nhân này là l噂p trừu t逢嬰ng giữa phần c泳ng c栄a thiết b鵜 và các l噂p phía trên.

Các thư viện (libraries) - ch衣y bên trên l噂p h衣t nhân, bao gồm các các th逢 viện lõi viết bằng C/C++ nh逢 libc và SSL, cũng nh逢 các th逢 viện nh逢:

- Th逢 viện cho việc phát các lo衣i dữ liệu âm thanh và hình 違nh

- B瓜 qu違n lý bề mặt (surface manager) cho việc hiển th鵜 đồ h丑a trên màn hình

- Các th逢 viện đồ h丑a bao gồm SGL và OpenGL cho đồ h丑a 2D và 3D

- SQLite cho các 泳ng d映ng sử d映ng CSDL

- SSL và WebKit cho việc tích h嬰p trình duyệt và b違o mật Internet

B瓜 thực thi Android (Android runtime) - là môi tr逢運ng cho các 泳ng d映ng Android có thể ch衣y đ逢嬰c, bao gồm các th逢 viện lõi Android (gần nh逢 t逢ơng đồng v噂i các th逢 viện lõi c栄a

Page 31: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

31

ngôn ngữ Java), các th逢 viện dành riêng cho Android, và máy 違o Dalvik nh逢 đư mô t違 荏 phần tr逢噂c.

B瓜 khung 泳ng d映ng (Application framework) - cung c医p tập các class để phát triển 泳ng d映ng Android. L噂p này cung c医p kh違 năng giao tiếp v噂i phần c泳ng thông qua các l噂p bên d逢噂i cũng nh逢 qu違n lý giao diện và các tài nguyên c栄a 泳ng d映ng

Lớp 泳ng d映ng (Application layer) - hầu hết các 泳ng d映ng (bao gồm c違 泳ng d映ng cài sẵn trong hệ điều hành và các 泳ng d映ng c栄a các bên th泳 3) đều đ逢嬰c phát triển dựa trên l噂p này (dùng chung tập API). L噂p 泳ng d映ng đ逢嬰c ch衣y trong b瓜 thực thi Android (v噂i các th逢 viện lõi và máy 違o Dalvik), sử d映ng các l噂p và các d鵜ch v映 cung c医p b荏i l噂p Application Framework.

Môi trường phát triển

Để có thể bắt đầu lập trình 泳ng d映ng cho hệ điều hành Android, b衣n cần ít nh医t các th泳 sau:

B瓜 phát tri 吋n phần m隠m Android (Android SDK) nh逢 mô t違 荏 trên, bao gồm các công c映 phát triển do Google phát triển và các Android API (các API đ逢嬰c download riêng b荏i công c映

Môi trường phát tri吋n tích h嬰p (IDE) dùng cho việc viết mã nguồn v噂i các tính năng nh逢 tự đ瓜ng đ鵜nh d衣ng mã nguồn, tự đ瓜ng hoàn thiện mã nguồn (g嬰i ý)... Các môi tr逢運ng th逢運ng tự đ瓜ng kết nối đến Android SDK giúp các thao tác biên d鵜ch, gỡ rối, kiểm thử và xu医t b違n 泳ng d映ng tr荏 nên dễ dàng hơn r医t nhiều. Các IDE phổ biến cho lập trình Android có thể kể đến nh逢 Eclipse (v噂i plugin ADT c栄a Google), IntelliJ IDEA, Android Studio...

Thi院t b鵜 ch衣y Android , thông th逢運ng là điện tho衣i thông mình ch衣y hệ điều hành Android, dùng để ch衣y thử 泳ng d映ng trong quá trình phát triển. B衣n cũng có thể dùng trình gi違 lập thiết b鵜 (Android emulator ) đi kèm theo b瓜 kit phát triển nếu không có thiết b鵜 thật, tuy nhiên hiệu năng c栄a trình gi違 lập thiết b鵜 Android t逢ơng đối th医p, và m瓜t số tác v映 đặc biệt liên quan đến phần c泳ng nh逢 lập trình đa ph逢ơng tiện hay truy xu医t đến m瓜t số c違m biến sẽ không ch衣y đ逢嬰c trên trình gi違 lập. Hầu hết các ví d映 trong tài liệu này sẽ ch衣y đ逢嬰c tốt trên c違 thiết b鵜 thật lẫn trình gi違 lập, trong tr逢運ng h嬰p mã nguồn không ch衣y đ逢嬰c trên trình gi違 lập sẽ có chú thích riêng.

T違i và cài đặt môi trường SDK, IDE

Cách th泳c đơn gi違n nh医t để có đ逢嬰c b瓜 công c映 đầy đ栄, c医u hình sẵn sàng cho việc phát triển là t違i gói Eclipse có đóng gói sẵn trình cắm ADT (Android Developer Tool) c栄a Google t衣i đ鵜a ch雨 http://developer.android.com/sdk/index.html, ch丑n "Download the SDK (ADT Bundle for {OS})".

Page 32: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

32

Sau khi t違i xong Eclipse + ADT (b瓜 đóng gói sẵn c栄a Google), gỡ nén và ch衣y file eclipse.exe, giao diện màn hình đang kh荏i đ瓜ng c栄a IDE nh逢 sau:

Hình . Eclipse v噂i ADT đang kh荏i đ瓜ng

Page 33: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

33

Hình . Giao diện Eclipse v噂i ADT đư kh荏i đ瓜ng xong

T違i Android API

B瓜 đóng gói sẵn Eclipse + ADT trên đư kèm sẵn b瓜 phát triển Android SDK, tuy nhiên để có thể bắt đầu viết 泳ng d映ng Android, b衣n cần t違i thêm các Android API và t衣o các thiết b鵜 Android 違o để test.

Để t違i các Android API, từ trình đơn “Window” c栄a Eclipse, ch丑n “Android SDK Manager”. Cửa sổ Android SDK Manager sẽ hiện ra cho phép b衣n ch丑n các m泳c API cần thiết để download. M厩i phiên b違n hệ điều hành Android sẽ có m瓜t m泳c API (API level) t逢ơng 泳ng, để bắt đầu phát triển, b衣n ch雨 cần t違i m瓜t trong số các m泳c API đ逢嬰c liệt kê, trong hình vẽ d逢噂i đây, ta ch丑n m泳c API m噂i nh医t (Android 4.3 – API 18). Tuy nhiên để kiểm thử tính t逢ơng thích c栄a 泳ng d映ng viết ra v噂i các phiên b違n Android cũ hơn, b衣n nên t違i thêm các m泳c API th医p hơn, phổ biến nh医t là API 10 (Android 2.3.3).

Page 34: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

34

Hình . Ch丑n các m泳c API để t違i về

T衣o thi院t b鵜 Android 違o

Để t衣o các thiết b鵜 Android 違o, từ Eclipse, ch丑n Window > Android Virtual Deivce Manager, cửa sổ qu違n lý thiết b鵜 gi違 lập sẽ xu医t hiện nh逢 hình d逢噂i.

Page 35: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

35

Hình . Qu違n lý thiết b鵜 gi違 lập Android (thiết b鵜 違o)

Để t衣o thiết b鵜 m噂i, b医m “New…”, màn hình t衣o thiết b鵜 m噂i xu医t hiện nh逢 hình bên d逢噂i, b衣n cần lựa ch丑n các thông số kỹ thuật cho thiết b鵜 cần t衣o nh逢:

- Tên thiết b鵜 - Lo衣i thiết b鵜 thật t逢ơng 泳ng cần gi違 lập (泳ng v噂i đ瓜 phân gi違i màn hình c栄a thiết b鵜

thật này) - M泳c API - Các thông số khác nh逢: bàn phím, máy 違nh, RAM, heap, thẻ nh噂…

B医m OK để hoàn thành quá trình t衣o thiết b鵜 gi違 lập.

Page 36: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

36

Hình . T衣o thiết b鵜 gi違 lập Android m噂i

Sau khi thiết b鵜 違o đư đ逢嬰c t衣o, b衣n có thể kh荏i đ瓜ng thiết b鵜 bằng cách ch丑n thiết b鵜 t逢ơng 泳ng từ danh sách và b医m “Start…”. Màn hình ch丑n c医u hình kh荏i ch衣y thiết b鵜 xu医t hiện, cho phép b衣n ch丑n kích th逢噂c màn hình thật c栄a thiết b鵜 và ph逢ơng pháp kh荏i ch衣y. B衣n nên lựa ch丑n kh荏i đ瓜ng v噂i tr衣ng thái l逢u tr逢噂c đó (Launch from snapshot) để đ逢嬰c tốc đ瓜 nhanh nh医t. Nếu b衣n muốn l逢a l衣i tr衣ng thái c栄a l逢嬰t ch衣y này cho các lần sử d映ng máy 違o sau này thì ch丑n “Save to snapshot”. Cuối cùng, b医m “Launch” để bắt đầu kh荏i đ瓜ng thiết b鵜.

Page 37: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

37

Hình . Kh荏i đ瓜ng máy 違o Android

Máy 違o Android v噂i API 17 (Android 4.2) sau khi kh荏i đ瓜ng lần đầu sẽ có d衣ng nh逢 hình d逢噂i đây:

Page 38: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

38

Hình . Máy 違o Android 4.2 sau khi kh荏i đ瓜ng xong (lần đầu tiên)

Sau khi thiết lập đầy đ栄 môi tr逢運ng làm việc theo các b逢噂c trên, chúng ta đư có thể bắt tay vào viết 泳ng d映ng cho thiết b鵜 ch衣y Android. Theo truyền thống chúng ta sẽ bắt đầu v噂i 泳ng d映ng “Hello world”.

Hello Android (Android さHello worldざ)

Để t衣o dự án Android m噂i, chúng ta làm theo các b逢噂c sau:

1. Từ Eclipse, ch丑n File > New > Project

Page 39: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

39

2. Trong m映c Android, ch丑n “Android project”

3. Đặt tên cho dự án là “HelloWorld”

Page 40: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

40

4. Điền thông tin cho 泳ng d映ng cần t衣o: - Tên 泳ng d映ng (sẽ hiển th鵜 trên thiết b鵜 Android) - Package name: chu厩i đ鵜nh danh duy nh医t cho 泳ng d映ng, th逢運ng đ逢嬰c đặt có đ鵜nh

d衣ng giống v噂i đ鵜nh d衣ng package c栄a Java - Ch丑n “Create Activity” và đặt tên Activity mặc đ鵜nh c栄a 泳ng d映ng. Khái niệm

activity trong Android ta sẽ tìm hiểu trong ch逢ơng t噂i, 荏 đây t衣m hiểu activity là m瓜t “màn hình” hay “form” c栄a 泳ng d映ng

- Ch丑n SDK th医p nh医t mà 泳ng d映ng h厩 tr嬰 - Finish

Page 41: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

41

5. Sau khi t衣o xong, project m噂i sẽ xu医t hiện trong khung “Package Explorer” c栄a Android nh逢 hình d逢噂i:

Page 42: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

42

6. Trong th逢 m映c res/layout, ta th医y có file “main.xml”. Đây là file mô t違 giao diện c栄a

泳ng d映ng HelloWorld c栄a chúng ta, kích đúp vào file này, cửa sổ so衣n th違o giao diện sẽ đ逢嬰c m荏 ra nh逢 hình d逢噂i. Để thay đổi giao diện bằng tay (XML code), ta chuyển sang tab “main.xml”

Page 43: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

43

7. Thêm đo衣n code in đậm d逢噂i đây vào file main.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="This is my first Android Application!" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="And this is a clickable button!" />

</LinearLayout>

8. Ghi file (Ctrl+S) và ch衣y 泳ng d映ng lên thiết b鵜 違o bằng cách nháy ph違i chu瓜t vào project, ch丑n Run As > Android Application

Page 44: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

44

9. 永ng d映ng sau khi ch衣y sẽ có d衣ng nh逢 sau:

Page 45: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

45

/; 10. Click vào nút Home (biểu t逢嬰ng ngôi nhà trong các phím 違o 荏 bên ph違i màn hình

emulator) để ẩn 泳ng d映ng và hiển th鵜 màn hình ch栄 c栄a hệ điều hành Android, sau đó b医m nút danh sách 泳ng d映ng , ta sẽ th医y 泳ng d映ng HelloWorld c栄a chúng ta xu医t hiện trong danh sách 泳ng d映ng đ逢嬰c cài đặt:

Page 46: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

46

Nh逢 vậy 泳ng d映ng HelloWorld đư đ逢嬰c biên d鵜ch và ch衣y thành công trên thiết b鵜 違o (đối v噂i thiết b鵜 thật cũng vậy), để hiểu đ逢嬰c 泳ng d映ng ch衣y nh逢 thế nào, tr逢噂c tiên ta sẽ tìm hiểu c医u trúc c栄a m瓜t 泳ng d映ng Android và tìm hiểu các khái niệm cơ b違n sử d映ng trong dự án này.

Cấu trúc c栄a m瓜t dự án Android

M瓜t b瓜 mã nguồn c栄a 泳ng d映ng Android bao th逢運ng bao gồm các thành phần nh逢 sau:

- “src” – th逢 m映c ch泳a các file mã nguồn Java, các file mã nguồn này đ逢嬰c đặt trong các th逢 m映c con c栄a th逢 m映c “src”, t逢ơng 泳ng v噂i package ch泳a nó. Trong ví d映 荏 trên, ta ch雨 có 1 file mã nguồn là “HelloWorldActivity.java”, nằm trong package “net.learn2develop.HelloWorld”.

- “gen” – th逢 m映c ch泳a file R.java, file này đ逢嬰c trình biên d鵜ch tự đ瓜ng sinh ra, ch泳a tham chiếu đến t医t c違 các tài nguyên (違nh, chu厩i, màu sắc, kích th逢噂c, layout…) sử d映ng trong dự án. Đây là file tự sinh ra, b衣n không cần tự ch雨nh sửa file này trong m丑i tr逢運ng h嬰p.

- “Android x.x” – ch泳a file android.jar, bao gồm t医t c違 các l噂p trong th逢 viện Android cần thiết cho 泳ng d映ng, file này cũng tự đ瓜ng đ逢嬰c gắn vào dự án, tùy thu瓜c vào m泳c API b衣n ch丑n tr逢噂c đó.

- “assets” – th逢 m映c ch泳a các tài nguyên tĩnh khác đ逢嬰c sử d映ng trong 泳ng dung, nh逢 HTML, font, file CSDL…

- “bin” – ch泳a các file t衣m biên d鵜ch trong quá trình, trong đó có file .apk, là file nh鵜 phân c栄a 泳ng d映ng Android. File .apk là file đư đóng gói toàn b瓜 m丑i th泳 cần thiết để

Page 47: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

47

ch衣y 泳ng d映ng. N瓜i dung th逢 m映c này cũng do trình biên d鵜ch tự đ瓜ng sinh ra, b衣n không cần can thiệp bằng tay.

- “res” – th逢 m映c ch泳a t医t c違 các tài nguyên c栄a đ逢嬰c sử d映ng trong 泳ng d映ng nh逢: hình 違nh (drawable), bố c映c giao diện (layout), các ch厩i, màu sắc, kích th逢噂c… (values). Chúng ta sẽ xem chi tiết về các lo衣i tài nguyên này trong các ch逢ơng kế tiếp.

- AndroidManifest.xml – là file đặc t違 泳ng d映ng, m丑i 泳ng d映ng Android đều cần có file này, hệ thống sẽ đ丑c file này để lúc cài đặt để xác đ鵜nh các quyền cần c医p cho 泳ng d映ng, các activity có trong 泳ng d映ng, và nhiều tính năng khác. Chi tiết về file đặc t違 này sẽ đ逢嬰c đề cập đến 荏 phần d逢噂i.

Mã nguồn duy nh医t chúng ta sử d映ng trong dự án HelloWorld là class HelloWorldActivity.java, n瓜i dung file này nh逢 sau: package net.learn2develop.HelloWorld; import android.app.Activity; import android.os.Bundle; public class HelloWorldActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }

}

L噂p này kế thừa từ l噂p android.app.Activity v噂i cài đặt thêm hàm onCreate (hàm này đ逢嬰c g丑i khi Acticity đ逢嬰c kh荏i t衣o), trong thân hàm ngoài việc g丑i hàm dựng c栄a l噂p cha, ch雨 ch泳a m瓜t dòng duy nh医t setContentView(R.layout.main); đòng này ch雨 ra activity hiện t衣i sẽ sử d映ng bố c映c (giao diện) khai báo trong file main.xml nằm trong th逢 m映c res/layout. File này đư đ逢嬰c biên d鵜ch và tham chiều đến trong file R.java d逢噂i tên R.layout.main.

Để Activity này có thể sử d映ng và m荏 ra đầu tiên khi 泳ng d映ng đ逢嬰c ch衣y trên thiết b鵜, nó cần ph違i đ逢嬰c khai báo trong file AndroidManifest.xml nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="net.learn2develop.HelloWorld" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="13" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".HelloWorldActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>

Page 48: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

48

</manifest>

Các thành phần chính c栄a file AndroidManifest.xml:

- Khai báo package name – đ鵜nh danh duy nh医t c栄a 泳ng d映ng trên hệ thống Android

(“net.learn2develop.HelloWorld”) - Phiên c栄a 泳ng d映ng (tên mã và tên hiển th鵜 c栄a phiên b違n): android:versionCode,

android:versionName. Trong đó version code là số nguyên, đ逢嬰c sử d映ng cho hệ thống, nhắm xác đ鵜nh khi nào 泳ng d映ng co phiên b違n m噂i hơn, còn version name là chu厩i, ch泳a tên c栄a phiên b違n hiển th鵜 lên cho ng逢運i dùng.

- android:minSdkVersion – khai báo m泳c API th医p nh医t 泳ng d映ng cần để ch衣y, thiết b鵜 ch衣y Android v噂i phiên b違n th医p hơn m泳c API này sẽ không cài đặt đ逢嬰c 泳ng d映ng đang phát triển.

- android:icon="@drawable/ic_launcher" – khai báo sử d映ng file 違nh ic_launcher.png trong th逢 m映c res/drawable để làm biểu t逢嬰ng cho 泳ng d映ng

- android:label="@string/app_name" – khai báo sử d映ng chu厩i có tên là app_name trong file string.xml làm tên c栄a 泳ng d映ng (chu厩i này có giá tr鵜 là “HelloWorld”)

- File manifest này cũng khai báo các activity có trong 泳ng d映ng, trong ví d映 c栄a chúng

ta ch雨 có 1 activity là ".HelloWorldActivity”, d医u ch医m (.) 荏 đầu tên Activity ch雨 ra rằng activity này nằm trong package cùng tên v噂i package name c栄a 泳ng d映ng

(net.learn2develop.HelloWorld.HelloWorldActivity). Bên trong khai báo

Activity này có thêm m映c intent-filter v噂i <action android:name=

"android.intent.action.MAIN"/> ch雨 ra rằng đây là Activity cần m荏 ra đầu tiên

khi ch衣y 泳ng dung, và <category android:name=

"android.intent.category.LAUNCHER"/> ch雨 ra rằng Activity này sẽ đ逢嬰c t衣o biểu t逢嬰ng (shortcut) trên màn hình ch栄 c栄a Android.

File main.xml trong th逢 m映c res/layout (nh逢 đư mô t違 荏 trên) ch泳a mô t違 giao diện c栄a

activity HelloWorldActivity, bao gồm khai báo 2 đo衣n chữ (TextView) ("@string/hello" và

"This is my first Android Application!") và m瓜t nút b医m v噂i n瓜i dung "And this is a

clickable button!". Ba thành phần này đ逢嬰c sắp xếp th泳 tự từ trên xuống d逢噂i do chúng

đ逢嬰c đặt trong m瓜t LinearLayout v噂i tham số h逢噂ng d丑c

(android:orientation="vertical").

Ta có thể để ý th医y TextView th泳 2 đ逢嬰c khai báo n瓜i dung chữ t逢運ng minh ("This is

my first Android Application!"), trong khi TextView đầu tiên đ逢嬰c khai báo tên c栄a hằng số chu厩i nằm trong th逢 m映c tài nguyên c栄a 泳ng d映ng (res/values/string.xml) – xem hình d逢噂i. Đây là cách cung c医p tài nguyên phổ biến trong Android, giúp cho việc qu違n lý các hằng số m瓜t cách tập trung và dễ dàng cho việc đ鵜a ph逢ơng hóa các chu厩i (đa ngôn ngữ). Chúng ra sẽ tìm hiểu thêm về v医n đề này 荏 các ch逢ơng sau.

Page 49: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

49

Chúng ta kết thúc dự án HelloWorld 荏 đây, ch逢ơng tiếp theo sẽ tìm hiều sâu hơn về thành phần quan tr丑ng nh医t c栄a 泳ng d映ng Android là các Activity và m瓜t số khái niệm liên quan.

Page 50: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

50

Chươngà3. Các Activity, Fragment và Intent

Trong ch逢ơng tr逢噂c, chúng ta đư biết activity là m瓜t cửa sổ (hay màn hình, form) ch泳a giao diện c栄a 泳ng d映ng Android. Đây là thành phần phổ biến và quan tr丑ng nh医t trong m厩i 泳ng d映ng Android. Thông th逢運ng m厩i 泳ng d映ng có thể có ít nh医t m瓜t hoặc nhiều activity, là nơi ng逢運i dùng t逢ơng tác v噂i 泳ng d映ng (tuy nhiên có những 泳ng d映ng đặc biệt không ch泳a m瓜t activity nào, nh逢 những 泳ng d映ng ch衣y ngầm không có giao diện). Trong quá trình thực thi 泳ng d映ng, kể từ khi đ逢嬰c kh荏i t衣o đến lúc biến m医t kh臼i màn hình điện tho衣i, m厩i activity sẽ tr違i qua m瓜t số các tr衣ng thái nh医t đ鵜nh, g丑i là “vòng đ運i” c栄a Activity. M厩i lập trình viên Android cần ph違i nắm vững các tr衣ng thái trong vòng đ運i c栄a các Activity để có những xử lý phù h嬰p nh逢 l逢u l衣i tr衣ng thái dữ liệu tr逢噂c khi Activity biến m医t hay khôi ph映c l衣i tr衣ng thái dữ liệu khi Activity đ逢嬰c khôi ph映c…

Ngoài Activity, Android từ phiên b違n 3.0 (API level 11) tr荏 lên gi噂i thiệu thêm khái niệm “m違nh giao diện”, hay fragment. Fragment có thể đ逢嬰c hiểu nh逢 các “m違nh ghép” c栄a giao diện 泳ng d映ng – là m瓜t phần c栄a Activity. M厩i Activity có thể ch泳a m瓜t hoặc nhiều “m違nh ghép” này trong giao diện c栄a mình, và m厩i “m違nh ghép” l衣i có thể đ逢嬰c chèn vào nhiều Activity khác nhau. Điều này cho phép gi違m thiểu tối đa sự trùng lặp về mã nguồn cho việc t衣o giao diện 泳ng d映ng thích nghi đ逢嬰c v噂i nhiều lo衣i kích cỡ và h逢噂ng c栄a màn hình. Các 泳ng d映ng viết cho các phiên b違n hệ điều hành th医p hơn cũng có thể sử d映ng Fragment bằng cách sử d映ng “th逢 viện h厩 tr嬰” c栄a Android (Android Support Library). Th逢 viện này cung c医p các tính năng c栄a các m泳c API m噂i cho các 泳ng d映ng viết cho m泳c API th医p hơn, trong số đó Android Support Library v4 cho phép các 泳ng d映ng viết cho API 4 (Android 1.6) tr荏 lên sử d映ng đ逢嬰c Fragment và nhiều tính năng khác c栄a các API level cao hơn.

Chúng ta sẽ tìm hiểu kỹ hơn về Activity và Fragment trong phần tiếp theo c栄a ch逢ơng này. M瓜t khái niệm quan tr丑ng khác c栄a hệ điều hành Android là Intent. Intent hiểu m瓜t cách nôm na giống nh逢 “keo dán” giữa các thành phần c栄a hệ điều hành, giúp các activity c栄a cùng m瓜t 泳ng d映ng hoặc các 泳ng d映ng khác nhau có thể t逢ơng tác v噂i nhau để thực hiện công việc m瓜t cách trôi ch違y, giống nh逢 các activity đó cùng thu瓜c m瓜t 泳ng d映ng. Ng逢運i lập trình cũng có thể sử d映ng Intent để g丑i các 泳ng d映ng sẵn có c栄a hệ điều hành nh逢 trình duyệt, trình g丑i điện, gửi tin nhắn, b違n đồ…

3.1. Activity

Vòngàđời của Activity

M厩i activity là m瓜t class kế thừa từ class android.app.Activity hoặc các l噂p kế thừa từ nó, ta xem l衣i Activity trong ví d映 c栄a ch逢ơng tr逢噂c:

package net.learn2develop.HelloWorld; import android.app.Activity; import android.os.Bundle; public class HelloWorldActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) {

Page 51: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

51

super.onCreate(savedInstanceState); setContentView(R.layout.main); }

}

Activity này sử d映ng giao diện đ逢嬰c khai báo trong file bố c映c main.xml, trong th逢 m映c

res/layout bằng cách g丑i lênh: setContentView(R.layout.main);

Cũng nhắc l衣i là m厩i Activity cần đ逢嬰c khai báo trong file đặc t違 泳ng d映ng (AndroidManifest.xml) nh逢 trong ch逢ơng tr逢噂c đư mô t違.

Vòng đ運i c栄a m厩i Activity tr違i qua các tr衣ng thái nh医t đ鵜nh, t衣i m厩i tr衣ng thái sẽ có sự kiện t逢ơng 泳ng đ逢嬰c g丑i đến. Các sự kiện này đ逢嬰c khai báo trong l噂p cơ s荏 (android.app.Activity), b衣n có thể n衣p chồng các sự kiện này để theo dõi vòng đ運i c栄a Activity và có những tác đ瓜ng thích h嬰p. Các sự kiện nh逢 vậy bao gồm:

- onCreate() – đ逢嬰c g丑i khi Activity đ逢嬰c kh荏i t衣o - onStart() – đ逢嬰c g丑i khi Activity bắt đầu đ逢嬰c hiện ra (ng逢運i bắt đầu nhìn th医y giao

diện) - onResume() – bắt đầu nhận các t逢ơng tác v噂i ng逢運i dùng - onPause() – g丑i khi activity bi dừng l衣i để chuyển qua activity khác - onStop() – g丑i khi activity biến m医t kh臼i màn hình - onDestroy() – khi activity b鵜 h栄y (h栄y ch栄 đ瓜ng hoặc b鵜 h栄y b荏i hệ thống trong

tr逢運ng h嬰p hệ điều hành xác nhận thiếu RAM) - onRestart() – khi activity đ逢嬰c kh荏i đ瓜ng l衣i sau khi đư b鵜 dừng l衣i

Mặc đ鵜nh, Eclipse sẽ t衣o sẵn cho b衣n hàm onCreate() cho m厩i Activity m噂i đ逢嬰c t衣o ra. Thông th逢運ng ng逢運i lập trình sẽ viết code liên quan đến kh荏i t衣o giao diện đồ h丑a trong thân hàm này.

Vòng đ運i c栄a m瓜t Activity đ逢嬰c mô t違 trong sơ đồ d逢噂i đây:

Page 52: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

52

Hình . Vòng đ運i c栄a m瓜t Activity

Để hiểu rõ hơn vòng đ運i c栄a m瓜t Activity, chúng ta viết m瓜t Activity đơn gi違n, n衣p chồng t医t c違 c違 các hàm sự kiện kể trên và ghi ra log t逢ơng 泳ng:

public class Activity101Activity extends Activity { String tag = "Lifecycle"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //---hides the title bar--- requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); Log.d(tag, "In the onCreate() event"); } public void onStart() { super.onStart(); Log.d(tag, "In the onStart() event"); }

Page 53: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

53

public void onRestart() { super.onRestart(); Log.d(tag, "In the onRestart() event"); } public void onResume() { super.onResume(); Log.d(tag, "In the onResume() event"); } public void onPause() { super.onPause(); Log.d(tag, "In the onPause() event"); } public void onStop() { super.onStop(); Log.d(tag, "In the onStop() event"); } public void onDestroy() { super.onDestroy(); Log.d(tag, "In the onDestroy() event"); }

}

Ch衣y 泳ng d映ng trên thiết b鵜 Android, thực hiện các thao tác b医m phím Home, Back, m荏 activity khác… và theo dõi th泳 tự c栄a các sự kiện trên trong cửa sổ LogCat sẽ cho b衣n khái niệm chắc chắn nh医t về vòng đ運i c栄a các Activity. Phần này coi nh逢 bài tập.

Cửa sổ hộp thoại (Dialog)

Trong r医t nhiều tr逢運ng h嬰p chúng ta cần hiển th鵜 thông báo, h臼i xác nhận c栄a ng逢運i dùng, hiển th鵜 tr衣ng thái ch運… 荏 d衣ng h瓜p tho衣i nhanh hiện lên trên Activity hiện t衣i, mà không cần m荏 ra Activity m噂i, khi đó ta cần n衣p chồng hàm onCreateDialog c栄a c栄a l噂p cơ s荏 android.app.Activity.

Ví d映 d逢噂i đây mô t違 cách t衣o m瓜t h瓜p tho衣i cơ b違n nh逢 vậy:

1. T衣o project m噂i trong Eclipse, đặt tên là Dialog 2. Thêm m瓜t nút b医m vào file main.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/btn_dialog" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Click to display a dialog" android:onClick="onClick" />

Page 54: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

54

</LinearLayout>

3. Để ý tham số android:onClick="onClick" c栄a nút b医m btn_dialog, tham số này ch雨 ra rằng b衣n cần khai váo m瓜t ph逢ơng th泳c tên là onClick trong Activity để xử lý sự kiện khi nút b医m này đ逢嬰c ch丑n.

4. Thêm code sau vào DialogActivity.java:

public class DialogActivity extends Activity { CharSequence[] items = { "Google", "Apple", "Microsoft" }; boolean[] itemsChecked = new boolean [items.length]; ProgressDialog progressDialog; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void onClick(View v) { showDialog(0); } @Override protected Dialog onCreateDialog(int id) { switch (id) { case 0: return new AlertDialog.Builder(this) .setIcon(R.drawable.ic_launcher) .setTitle("This is a dialog with some simple text...") .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { Toast.makeText(getBaseContext(), "OK clicked!", Toast.LENGTH_SHORT).show(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { Toast.makeText(getBaseContext(), "Cancel clicked!", Toast.LENGTH_SHORT).show(); } }) .setMultiChoiceItems(items, itemsChecked, new DialogInterface.OnMultiChoiceClickListener() { public void onClick(DialogInterface dialog, int which, boolean isChecked) { Toast.makeText(getBaseContext(), items[which] + (isChecked ? " checked!":" unchecked!"), Toast.LENGTH_SHORT).show(); } }).create(); } return null; }

}

Page 55: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

55

5. Ch衣y 泳ng d映ng và b医m vào nút “Click to display a dialog”, h瓜p tho衣i nh逢 hình bên d逢噂i sẽ hiện ra:

Hình . H瓜p tho衣i

Trong ví d映 trên ta đư n衣p chồng ph逢ơng th泳c onCreateDialog(int id) để hiển th鵜 h瓜p tho衣i thì có yêu cầu. Trong Activity có thể hiển th鵜 nhiều h瓜p tho衣i khác nhau tùy vào ngữ c違nh xử lý nh逢 h瓜p tho衣i thông báo, h瓜p tho衣i xác nhận, h瓜p tho衣i tiến trình…, tham số id trong ph逢ơng th泳c onCreateDialog là để phân biệt h瓜p tho衣i nào cần đ逢嬰c hiện lên.

Để kích ho衣t yêu cầu m荏 h瓜p tho衣i, ta g丑i ph逢ơng th泳c showDialog(0); ph逢ơng th泳c này

đ逢嬰c g丑i khi ta b医m vào nút b医m “Click to display a dialog”,

Trong hàm onCreateDialog, tùy thu瓜c vào id truyền vào mà ta hiển th鵜 h瓜p tho衣i t逢ơng 泳ng, trong ví d映 trên là h瓜p tho衣i có id = 0. Trong tr逢運ng h嬰p này ta sử d映ng lo衣i h瓜p tho衣i đơn gi違n nh医t là AlertDialog. Để t衣o ra m瓜t h瓜p tho衣i lo衣i này, ta t衣o ra m瓜t object c栄a class AlertDialog.Builder và g丑i ph逢ơng th泳c create() c栄a nó. Đo衣n code trên thiết lập 2 nút b医m cho

h瓜p tho衣i cho tr逢運ng h嬰p đồng ý (nút “OK” – setPositiveButton) và h栄y b臼 (nút “Cancel” –

setNegativeButton), cũng nh逢 thiết lập các ô checkbox (setMultiChoiceItems).

Page 56: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

56

Các hàm xử lý sự kiện trong Dialog trong ví d映 ch雨 đơn gi違n là hiển th鵜 lên màn hình dòng thông báo d衣ng text trong m瓜t kho違ng th運i gian ngắn. D衣ng thông báo này trong Android g丑i là Toast - là đo衣n chữ hiển th鵜 荏 giữa, phía d逢噂i màn hình trong kho違ng vài giây. Toast th逢運ng đ逢嬰c dùng để hiển th鵜 các lo衣i thông báo ngắn, ít quan tr丑ng nh逢 thông báo SMS đư đ逢嬰c gửi, thông báo m瓜t tiến trình ngầm đư hoàn thành…

Ta có thể m荏 t衣o thêm các nút b医m khác và hiển th鵜 các h瓜p tho衣i khác t逢ơng 泳ng bằng cách truyền id khác nhau cho hàm showDialog(), ví d映 nút b医m 1 – showDialog(0), nút b医m 2 – showDialog(1)… Có r医t nhiều các lo衣i h瓜p tho衣i khác nhau trong hệ điều hành Android nh逢 h瓜p tho衣i ch運 (v噂i biểu t逢嬰ng “quay quay”) hay h瓜p tho衣i thể hiện tiến trình (có thanh tiến trình theo %), thậm chí b衣n có thể t衣o riêng m瓜t bố c映c (layout) bằng file .xml cho h瓜p tho衣i. B衣n đ丑c tự tìm hiểu thêm coi nh逢 bài tập.

Đối tư嬰ng Context trong Android

Trong Android, r医t nhiều ph逢ơng th泳c l医y m瓜t trong những tham số là m瓜t đối t逢嬰ng c栄a l噂p Context. Trong ví d映 trên, hàm dựng c栄a l噂p AlertDialog.Builder và hàm Toast.makeText đều nhận tham số kiểu Context. Đối t逢嬰ng kiểu Context này th逢運ng dùng để ch雨 ra ph衣m vi, hay ngữ c違nh c栄a ph逢ơng th泳c đ逢嬰c g丑i và th逢運ng tr臼 đến 泳ng d映ng hoặc activity hiện t衣i.

雲 ví d映 trên ta th医y đối t逢嬰ng c栄a l噂p AlertDialog.Builder đ逢嬰c g丑i v噂i tham số this:

new AlertDialog.Builder(this). Đối t逢嬰ng this 荏 đây là Activity hiện t衣i (Activity cũng là l噂p con cháu c栄a l噂p Context), trong khi hàm Toast.makeText nhận tham số Context là

getBaseContext() ch泳 không đ逢嬰c dùng con tr臼 this nữa, b荏i vì ph逢ơng th泳c này đ逢嬰c g丑i

bên trong đối t逢嬰ng c栄a l噂p DialogInterface.OnClickListener(), con tr臼 this 荏 đây có kiểu OnClickListener ch泳 không ph違i Activity, nên không ph違i là Context. Vì vậy ta dùng

hàm getBaseContext() để l医y Context cơ s荏 c栄a đối t逢嬰ng hiện t衣i, m瓜t cách khác có thể sử

d映ng là dùng DialogActivity.this.

3.2. Intent và việc tươngàt=Iàgiữa các Activity

Nh逢 đư đề cập 荏 các phần trên, m厩i 泳ng d映ng Android có thể không có, có m瓜t hoặc nhiều Activity. Khi 泳ng d映ng có nhiều hơn m瓜t Activity thì việc điều h逢噂ng từ Activity này sang Activity khác và ng逢嬰c l衣i là việc r医t cần thiết và đ逢嬰c thực hiện r医t th逢運ng xuyên. Trong Android, việc điều h逢噂ng này đ逢嬰c thực hiện thông qua m瓜t cơ chế r医t đặc thù, g丑i là Intent.

Sử dụng Intent

Tr逢噂c tiên ta xem xét m瓜t ví d映 đơn gi違n nh医t trong việc sử d映ng Intent để m荏 m瓜t Activity khác từ Activity hiện t衣i. Để thực hiện điều này ta t衣o m瓜t project ch泳a 2 Activity, trong Activity th泳 nh医t có m瓜t nút b医m, khi b医m vào nút này ta sẽ m荏 Activity th泳 2. Các b逢噂c c映 thể nh逢 sau:

1. T衣o project UsingIntent và t衣o 2 Activity: UsingIntentActivity (Activity mặc đ鵜nh) và SencondActivity, 2 activity này đ逢嬰c khai báo trong AndroidManifest.xml nh逢 sau:

<activity android:label="@string/app_name" android:name=".UsingIntentActivity" > <intent-filter >

Page 57: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

57

<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:label="Second Activity" android:name=".SecondActivity" > <intent-filter > <action android:name="net.learn2develop.SecondActivity" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>

</activity>

2. T衣o layout riêng cho SecondActivity bằng cách copy file main.xml thành file secondactivity.xml và sửa n瓜i dung TextView nh逢 bên d逢噂i. Sau đó trong hàm onCreate c栄a SecondActivity, g丑i lệnh

setContentView(R.layout.secondactivity); để khai báo việc sử d映ng file layout này cho SecondActivity.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="This is the Second Activity!" /> </LinearLayout>

3. T衣o m瓜t nút b医m trong UsingIntentActivity và trong hàm xử lý sự kiện “onClick” c栄a nút b医m này, ta g丑i lệnh m荏 Activity th泳 2 nh逢 sau:

startActivity(new Intent("net.learn2develop.SecondActivity"));

4. Ch衣y 泳ng d映ng và b医m vào nút b医m duy nh医t trong UsingIntentActivity, ta sẽ th医y SecondActivity đ逢嬰c m荏 ra:

Page 58: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

58

Trong ví v映 trên, ta th医y dòng lệnh để m荏 ra Activity th泳 2 là startActivity(new

Intent("net.learn2develop.SecondActivity"));. Trong tham số c栄a hàm dựng Intent không hề ch雨 ra tên Class c栄a SecondActivity mà ch雨 ra “action” cần thực hiện, khi đó hệ điều hành sẽ quét toàn b瓜 các Activity c栄a toàn b瓜 các 泳ng d映ng đ逢嬰c cài đặt trên thiết b鵜 và l丑c ra

Activity có khai báo action t逢ơng 泳ng (net.learn2develop.SecondActivity) để m荏 nó. Trong tr逢運ng h嬰p c栄a chúng ta, SecondActivity đư đ逢嬰c khai báo action này trong phần intent-

filter c栄a activity đó trong AndroidManifest.xml (<action

android:name="net.learn2develop.SecondActivity" />) nên sẽ đ逢嬰c m荏 ra. Ngoài ra cũng ph違i chú ý là để activity có thể đ逢嬰c m荏 ra bằng ph逢ơng th泳c startActivity nh逢 trong ví d映, thì trong Manifest cũng ph違i khai báo thêm danh m映c (category)

android.intent.category.DEFAULT trong phần intent-filter (<category

android:name="android.intent.category.DEFAULT" />).

Trong tr逢運ng h嬰p Activity cần m荏 nằm trong cùng 泳ng d映ng v噂i Activity m荏 nó (nh逢 trong ví d映 trên c栄a ta), ta có thể g丑i startActivity v噂i Intent t逢運ng mình nh逢 sau:

startActivity(new Intent(this, SecondActivity.class));

Giải quyết さ┝ungàđột Intentざ

Trong ví d映 trên ta th医y để m荏 m瓜t Activity, ta ch雨 cần truyền vào action c栄a Activity đó. Hệ thống sẽ quét tìm kiếm Activity đ逢嬰c khai báo v噂i action nh逢 vậy để m荏 ra. Vậy điều gì sẽ x違y ra nếu có nhiều hơn 1 Activity khai báo v噂i cùng m瓜t action nh逢 vậy?

Chẳng h衣n ta khai báo thêm m瓜t Activity th泳 3 v噂i cùng intent-filter giống nh逢 c栄a SecondActivity:

Page 59: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

59

<activity android:label="Third Activity" android:name=".ThirdActivity" > <intent-filter > <action android:name="net.learn2develop.SecondActivity" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>

</activity>

Và giữ nguyên l運i g丑i Activity nh逢 cũ:

startActivity(new Intent("net.learn2develop.SecondActivity"));

Khi đ逢嬰c g丑i đến, hệ thống sẽ hiển th鵜 danh sách các Activity phù h嬰p theo b瓜 l丑c Intent (trong tr逢運ng h嬰p này là 02 Activity) để ng逢運i dùng ch丑n. Kèm theo cửa sổ ch丑n sẽ là checkbox “Use by default for this action”. Nếu b衣n ch丑n checkbox này thì hệ thống sẽ ghi nh噂 lựa ch丑n c栄a b衣n và không h臼i l衣i cho các lần sau nữa, nếu không cửa sổ ch丑n Activity cần m荏 sẽ hiển th鵜 m厩i lần b衣n g丑i hàm startActivity kể trên. Nếu đư lỡ ch丑n ghi nh噂 lựa ch丑n mặc đ鵜nh này, b衣n có thể xóa ghi nh噂 này bằng cách vào m映c Settings c栄a hệ thống, ch丑n Apps > Manage Applications, sau đó ch丑n 泳ng d映ng đang dùng (UsingIntent) và ch丑n nút “Clear defaults” 荏 phía cuối màn hình. Hình 違nh d逢噂i đây minh h丑a các tr逢ơng h嬰p vừa kể ra:

Các 泳ng d映ng mặc đ鵜nh sẵn có c栄a hệ điều hành Android cũng đ逢嬰c m荏 ra bằng cơ chế Intent v噂i các b瓜 l丑c nh逢 vậy. Cơ chế này làm hệ điều hành Android tr荏 nên vô cùng mềm dẻo: m丑i thành phần c栄a hệ điều hành đều đ逢嬰c đối xử nh逢 nhau và đều có kh違 năng “thay thế” đ逢嬰c. Ví d映 b衣n có thể viết m瓜t 泳ng d映ng sử lý tin nhắn SMS thay cho 泳ng d映ng Message mặc đ鵜nh bằng cách khai báo action cho Activity c栄a b衣n trùng v噂i action c栄a 泳ng d映ng tin nhắn mặc đ鵜nh. (các intent action này đ逢嬰c mô t違 r医t đầy đ栄 trong các tài liệu tham chiếu c栄a Google). Khi đó, khi có yêu cầu gửi tin nhắn từ m瓜t 泳ng d映ng b医t kỳ, hệ thống sẽ liệt kê ra các 泳ng d映ng có kh違 năng xử lý yêu cầu này cho ng逢運i dùng lựa ch丑n, bao gồm 泳ng d映ng tin nhắn mặc đ鵜nh và 泳ng d映ng b衣n m噂i viết.

Lấy kết quả trả về từ Activity thông qua Intent

Trong r医t nhiều tr逢運ng h嬰p, ta m荏 Activty m噂i v噂i m映c đích yêu cầu thêm dữ liệu từ ng逢運i dùng, nh逢 yêu cầu ng逢運i dùng nhập vào tên truy cập và mật khẩu… Trong tr逢運ng h嬰p đó,

Page 60: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

60

sau khi ng逢運i dùng kết thúc nhập liệu và quay tr荏 l衣i Activity tr逢噂c đó, dữ liệu ng逢運i dùng vừa nhập vào cần ph違i đ逢嬰c truyền về Activity ban đầu để xử lý. Để làm đ逢嬰c điều này, trong Activty th泳 nh医t (UsingIntentActivity 荏 trên) thay vì m荏 Activity th泳 2 (SecondActivity) bằng ph逢ơng th泳c startActivity, ta cần g丑i ph逢ơng th泳c startActivityForResult và khai báo thêm ph逢ơng th泳c onActivityResult để h泳ng sự kiện khi SecondActivity đóng l衣i và tr違 về dữ liệu cho nó. Bên c衣nh đó trong SecondActivity cũng ph違i ch泳a đo衣n mã tr違 về dữ liệu ng逢運i dùng nhập vào thông qua Intent.

Để minh h丑a cho quá trình trên, ta thực hiện các b逢噂c sau:

1. Trong SecondActivity, thêm m瓜t ô nhập liệu và m瓜t nút b医m nh逢 sau:

<EditText android:id="@+id/txt_username" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn_OK" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="OK"

android:onClick="onClick"/>

2. Trong hàm xử lý sự kiện click c栄a nút OK c栄a SecondActivity, ta thêm đo衣n code tr違

về dữ liệu cho Activity gốc (Activity g丑i nó, trong ví d映 là UsingIntentActivity) tr逢噂c khi đóng l衣i:

Intent data = new Intent();

//---get the EditText view--- EditText txt_username = (EditText) findViewById(R.id.txt_username);

Page 61: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

61

//---set the data to pass back--- data.setData(Uri.parse(txt_username.getText().toString())); setResult(RESULT_OK, data); //---closes the activity— finish();

3. Trong UsingIntentActivity, thay vì m荏 SecondActivity bằng ph逢ơng th泳c startActivity, ta dùng startActivityForResult kèm theo m瓜t mã request tự quy đ鵜nh (ch丑n = 1 chẳng h衣n):

startActivityForResult(new Intent("net.learn2develop.SecondActivity"), 1);

4. Và khai báo n衣p chồng hàm h泳ng sự kiện Activity tr違 kết qu違 về (onActivityResult):

@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 1) { if (resultCode == RESULT_OK) { Toast.makeText(this,data.getData().toString(), Toast.LENGTH_SHORT).show(); } }

}

5. Khi nhận đ逢嬰c kết qu違 (d衣ng chu厩i) từ SecondActivity, v噂i m映c đích minh h丑a, ta ch雨 hiển th鵜 text này lên màn hình d逢噂i d衣ng Toast message. Kết qu違 thu đ逢嬰c khi ch衣y 泳ng d映ng sẽ nh逢 hình bên d逢噂i:

Page 62: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

62

Truyền dữ liệu giữa các Activity với Intent

Ngoài việc l医y dữ liệu tr違 về c栄a Activity, m瓜t thao tác phổ biến khác là truyền dữ liệu cho Activity m噂i đ逢嬰c m荏 ra. Ví d映 trong tr逢運ng h嬰p trên, khi g丑i m荏 SecondActivity ta có thể truyền sẵn chu厩i mặc đ鵜nh cần hiển th鵜 sẵn trong ô nhập liệu trong Activity này. Để làm đ逢嬰c điều này, trong UsingIntentActivity, tr逢噂c khi g丑i startActivity, ta gắn dữ liệu cần truyền vào đối t逢嬰ng Intent dùng để m荏 SecondActivity bằng ph逢ơng th泳c putExtra c栄a đối t逢嬰ng Intent nh逢 sau:

Intent i = new Intent("net.learn2develop.PassingDataSecondActivity"); //---use putExtra() to add new key/value pairs--- i.putExtra("str1", "This is a string"); i.putExtra("age1", 25); //---use a Bundle object to add new key/values pairs--- Bundle extras = new Bundle(); extras.putString("str2", "This is another string"); extras.putInt("age2", 35); //---attach the Bundle object to the Intent object--- i.putExtras(extras); //---start the activity startActivityForResult(i);

Page 63: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

63

Khi đó, trong hàm onCreate c栄a SecondActivity, ta có thể l医y dữ liệu đ逢嬰c truyền sang bằng cách l医y Intent qua hàm getIntent() và lần l逢嬰t l医y ra các tr逢運ng dữ liệu t逢ơng 泳ng bằng các ph逢ơng th泳c getStringExtra, getIntExtra, getExtras… nh逢 sau:

//---get the data passed in using getStringExtra()--- Toast.makeText(this,getIntent().getStringExtra("str1"), Toast.LENGTH_SHORT).show(); //---get the data passed in using getIntExtra()--- Toast.makeText(this,Integer.toString(getIntent().getIntExtra("age1", 0)), Toast.LENGTH_SHORT).show(); //---get the Bundle object passed in--- Bundle bundle = getIntent().getExtras(); //---get the data using the getString()--- Toast.makeText(this, bundle.getString("str2"), Toast.LENGTH_SHORT).show(); //---get the data using the getInt() method--- Toast.makeText(this,Integer.toString(bundle.getInt("age2")),Toast.LENGTH_SHORT).show();

Sử dụngàIntentàđể gọi các ứng dụng sẵn có của hệ điều hành

Nh逢 đư nói 荏 trên, các 泳ng d映ng mặc đ鵜nh sẵn có c栄a hệ điều hành Android cũng đ逢嬰c m荏 ra bằng cơ chế Intent nh逢 các 泳ng d映ng thông th逢運ng. Từ 泳ng d映ng c栄a mình, b衣n có thể dùng Intent để m荏 trình duyệt v噂i m瓜t website b衣n ch丑n, hay m荏 泳ng d映ng gửi tin nhắn v噂i số điện tho衣i và n瓜i dung tin nhắn ch丑n sẵn…. Phần này sẽ đ逢a ra vài tr逢運ng h嬰p c映 thể sử d映ng Intent trong các việc nh逢 vậy.

M荏 trình duyệt web:

Intent i = new Intent("android.intent.action.VIEW"); i.setData(Uri.parse("http://www.amazon.com")); startActivity(i);

Kết qu違:

Page 64: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

64

M荏 泳ng d映ng g丑i điện tho衣i:

Intent i = new Intent(android.content.Intent.ACTION_DIAL, Uri.parse("tel:+651234567")); startActivity(i);

Page 65: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

65

M荏 泳ng d映ng b違n đồ và điều h逢噂ng đến v鵜 trí nh医t đ鵜nh:

Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("geo:37.827500,-122.481670")); startActivity(i);

Page 66: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

66

0

Đốiàtượng Intent

雲 các ví d映 trên ta đư xem qua m瓜t số cách sử d映ng Intent khác nhau, phần này sẽ tổng h嬰p l衣i mô t違 chi tiết hơn về đối t逢嬰ng Intent.

M厩i đối t逢嬰ng Intent (Intent Object) có thể ch泳a các thông tin sau:

- Action (hành đ瓜ng) - Data (dữ liệu) - Type (lo衣i) - Category (danh m映c)

Trong ví d映 trên, ta đư th医y để m荏 Activity khác, ta cần truyền Action c栄a activity đó trong hàm dựng c栄a đối t逢嬰ng Intent nh逢 sau:

startActivity(newIntent(“net.learn2develop.SecondActivity”)); Action 荏 đây ( “net.learn2develop.SecondActivity”) còn đ逢嬰c g丑i là “component name”.

Trong tr逢運ng h嬰p Activity cần m荏 nằm cùng project v噂i Activity hiện t衣i, ta có thể g丑i nh逢 sau:

startActivity(newIntent(this, SecondActivity.class));

Activity cũng có thể đ逢嬰c g丑i bằng cách truyền Action và dữ liệu (Data) kèm theo nh逢 trong tr逢運ng h嬰p m荏 trình duyệt 荏 trên:

Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(“http://www.amazon.com”)); startActivity(i);

Page 67: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

67

Phần “hành đ瓜ng” mô t違 việc chúng ta cần làm, còn phần “dữ liệu” ch泳a thông tin cần thiết cho Activity sắp đ逢嬰c m荏 ra xử lý. Trong ví d映 trên, ta t衣o Intent v噂i yêu cầu cần hiển th鵜 thông tin, v噂i dữ liệu đi kèm là url đến m瓜t website. Hệ thống Android sẽ l丑c trong t医t c違 泳ng d映ng đư đ逢嬰c cài đặt trên hệ thống và liệt kê ra các 泳ng d映ng có thể xử lý đ逢嬰c Intent này để ng逢運i dùng lựa ch丑n.

Intent trên cũng có thể đ逢嬰c g丑i t逢運ng minh hơn nh逢 sau:

Intent i = new Intent(“android.intent.action.VIEW”); i.setData(Uri.parse(“http://www.amazon.com”)); M瓜t số Intent không cần truyền theo dữ liệu c映 thể, mà ch雨 cần truyền theo lo衣i dữ liệu, ví

d映 l医y m瓜t b違n ghi trong danh sách danh b衣, ta có thể dùng Intent nh逢 sau:

Intent i = new Intent(android.content.Intent.ACTION_PICK); i.setType(ContactsContract.Contacts.CONTENT_TYPE);

Hàm setType()method ch雨 ra lo衣i dữ liệu (MIME data type) c栄a thông tin tr違 về cho activity hiện t衣i. MIME type c栄a ContactsContract.Contacts.CONTENT_TYPE là xâu “vnd.android.cursor.dir/contact”.

Ngoài hành đ瓜ng, dữ liệu và lo衣i dữ liệu, m厩i đối t逢嬰ng Intent có thể có thêm tham số “danh m映c” (category) dùng để nhóm các Activity l衣i theo danh m映c nhằm thuận tiện cho việc l丑c các Activity theo nhu cầu c栄a 泳ng d映ng. Các b衣n có thể tìm hiểu kỹ hơn về b瓜 l丑c Activity 荏 các tài liệu khác. Phần này coi nh逢 bài tập.

3.3. Fragment

Trong phần tr逢噂c ta đư tìm hiểu qua Activty là giao diện c栄a m瓜t “màn hình” 泳ng d映ng, m厩i màn hình ch雨 ch泳a 01 Activity. Tuy nhiên khi các máy tính b違ng ra đ運i v噂i màn hình l噂n hơn r医t nhiều so v噂i điện tho衣i truyền thống, cho phép thiết kế v噂i nhiều lo衣i view khác nhau, và phát sinh nhu cầu dùng l衣i các view này trên các màn hình khác nhau (điện tho衣i và máy tính b違ng). Khái niệm fragment đ逢嬰c sinh ra nhằm ph映c v映 nhu cầu đó. Có thể hiểu fragment nh逢 các “tiểu Activity”, ch泳a tập h嬰p các view khác bên trong nó. Fragment luôn luôn đ逢嬰c ch泳a trong m瓜t Activity hoặc fragment khác, m厩i Activity có thể ch泳a m瓜t hoặc nhiều fragment . M瓜t ví d映 điển hình c栄a việc sử d映ng fragment là tr逢運ng h嬰p thiết kế “master-detail”, bao gồm 2 view: view tổng quan ch泳a danh sách các đối t逢嬰ng (danh sách tiêu đề các bài báo chẳng h衣n), và view chi tiết, hiển th鵜 n瓜i dung c栄a đối t逢嬰ng (bài báo) đang đ逢嬰c ch丑n. M厩i view nh逢 vậy đ逢嬰c đặt trong 1 fragement. Trên màn hình điện tho衣i, do kích th逢噂c h衣n chế, 2 fragement này sẽ nằm trong 2 activity khác nhau, trong khi đối v噂i màn hình máy tính b違ng, 2 fragment này nằm trên cùng m瓜t Activity (xem hình d逢噂i). Thiết kế này giúp việc dùng l衣i code đ逢嬰c tối đa, m瓜i logic c栄a 泳ng d映ng nằm trong 2 fragment, đ逢嬰c dùng l衣i cho c違 điện tho衣i và máy tính b違ng, còn Activity ch雨 là v臼 ch泳a tối thiểu mã nguồn.

Khái niệm fragment m噂i đ逢嬰c đ逢a vào từ phiên b違n Android 3.0 HoneyComb, tuy nhiên tính năng này cũng đ逢嬰c Google bổ sung cho các API th医p hơn (từ Level 4) thông qua th逢 viện h厩 tr嬰 Android Support Library v4.

Page 68: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

68

1. T衣o project m噂i, đặt tên là Fragments 2. T衣o file fragment1.xml trong res/layout, đây là file ch泳a mô t違 giao diện c栄a fragment

th泳 nh医t, v噂i n瓜i dung nh逢 sau:

<?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" android:background="#00FF00" > <TextView android:id="@+id/lblFragment1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="This is fragment #1" android:textColor="#000000" android:textSize="25sp" />

</LinearLayout>

3. T衣o file fragment2.xml trong res/layout, đây là file ch泳a mô t違 giao diện c栄a fragment th泳 hai, v噂i n瓜i dung nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

Page 69: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

69

android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFFE00" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="This is fragment #2" android:textColor="#000000" android:textSize="25sp" /> <Button android:id="@+id/btnGetText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Get text in Fragment #1" android:textColor="#000000" android:onClick="onClick" /> </LinearLayout>

4. Sửa n瓜i dung file main.xml nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <fragment android:name="net.learn2develop.Fragments.Fragment1" android:id="@+id/fragment1" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" /> <fragment android:name="net.learn2develop.Fragments.Fragment2" android:id="@+id/fragment2" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" />

</LinearLayout>

5. T衣o file Fragment1.java và Fragment2.java trong namespace mặc đ鵜nh c栄a 泳ng d映ng:

Page 70: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

70

6. N瓜i dung file Fragment1.java:

public class Fragment1 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d("Fragment 1", "onCreateView"); //---Inflate the layout for this fragment--- return inflater.inflate( R.layout.fragment1, container, false);

}

}

7. N瓜i dung file Fragment2.java:

public class Fragment2 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //---Inflate the layout for this fragment--- return inflater.inflate( R.layout.fragment2, container, false); } @Override public void onStart() { super.onStart(); //---Button view--- Button btnGetText = (Button) getActivity().findViewById(R.id.btnGetText);

Page 71: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

71

btnGetText.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { TextView lbl = (TextView) getActivity().findViewById(R.id.lblFragment1); Toast.makeText(getActivity(), lbl.getText(), Toast.LENGTH_SHORT).show(); } }); }

}

8. Sau khi ch衣y:

Thêm fragment trong thời gian thực thi (không khai báo trong layout):

1. Sửa l衣i file main.xml, xóa b臼 khai báo 2 fragment trong này:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" >

</LinearLayout>

2. Sửa hàm onCreate c栄a FramentActivity nh逢 sau:

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //---get the current display info--- WindowManager wm = getWindowManager(); Display d = wm.getDefaultDisplay(); if (d.getWidth() > d.getHeight()) { //---landscape mode--- Fragment1 fragment1 = new Fragment1(); // android.R.id.content refers to the content // view of the activity

Page 72: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

72

fragmentTransaction.replace( android.R.id.content, fragment1); } else { //---portrait mode--- Fragment2 fragment2 = new Fragment2(); fragmentTransaction.replace( android.R.id.content, fragment2); } //---add to the back stack--- fragmentTransaction.addToBackStack(null); fragmentTransaction.commit();

}

Ch衣y 泳ng d映ng và thay đổi h逢噂ng c栄a màn hình (bật auto-rotate trên thiết b鵜 và quay màn hình theo h逢噂ng cần thiêt, hoặc b医m Ctrl+F11 nếu đang ch衣y trên emulator), ta sẽ quan sát th医y 2 fragment khác nhau đ逢嬰c gắn vào Activity khi thiết b鵜 đang 荏 2 h逢噂ng khác nhau nh逢 hình d逢噂i:

Page 73: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

73

Vòngàđời của Fragment

Để hiểu rõ hơn vòng đ運i c栄a m瓜t Frament, chúng ta n衣p chồng t医t c違 c違 các hàm sự kiện t逢ơng 泳ng trong và ghi ra log:

@Override public void onAttach(Activity activity) { super.onAttach(activity); Log.d("Fragment 1", "onAttach");

Page 74: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

74

} @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("Fragment 1", "onCreate"); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d("Fragment 1", "onActivityCreated"); } @Override public void onStart() { super.onStart(); Log.d("Fragment 1", "onStart"); } @Override public void onResume() { super.onResume(); Log.d("Fragment 1", "onResume"); } @Override public void onPause() { super.onPause(); Log.d("Fragment 1", "onPause"); } @Override public void onStop() { super.onStop(); Log.d("Fragment 1", "onStop"); } @Override public void onDestroyView() { super.onDestroyView(); Log.d("Fragment 1", "onDestroyView"); } @Override public void onDestroy() { super.onDestroy(); Log.d("Fragment 1", "onDestroy"); } @Override public void onDetach() { super.onDetach(); Log.d("Fragment 1", "onDetach");

}

Ch衣y 泳ng d映ng trên thiết b鵜 Android, thực hiện các thao tác b医m phím Home, Back, m荏 泳ng d映ng khác… và theo dõi th泳 tự c栄a các sự kiện trên trong cửa sổ LogCat sẽ cho b衣n khái niệm chắc chắn nh医t về vòng đ運i c栄a các Frament:

11-03 23:24:29.398: D/Fragment 1(11354): onAttach

Page 75: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

75

11-03 23:24:29.398: D/Fragment 1(11354): onCreate

11-03 23:24:29.398: D/Fragment 1(11354): onCreateView

11-03 23:24:29.398: D/Fragment 1(11354): onActivityCreated

11-03 23:24:29.398: D/Fragment 1(11354): onStart

11-03 23:24:29.398: D/Fragment 1(11354): onResume

11-03 23:24:33.835: D/Fragment 1(11354): onPause

11-03 23:24:33.835: D/Fragment 1(11354): onStop

11-03 23:24:33.835: D/Fragment 1(11354): onDestroyView

11-03 23:24:33.835: D/Fragment 1(11354): onDestroy

11-03 23:24:33.835: D/Fragment 1(11354): onDetach

11-03 23:24:33.914: D/Fragment 1(11354): onAttach

Tươngàt=Iàgiữa các fragment

Trong ví d映 trên, khi thực hiện b医m vào nút b医m trong Fragment2, ta tiến hành l医y và hiển th鵜 xâu ký tự ch泳a trong TextView c栄a Fragment1 d逢噂i d衣ng Toast:

@Override public void onStart() { super.onStart(); //---Button view--- Button btnGetText = (Button) getActivity().findViewById(R.id.btnGetText); btnGetText.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { TextView lbl = (TextView) getActivity().findViewById(R.id.lblFragment1); Toast.makeText(getActivity(), lbl.getText(), Toast.LENGTH_SHORT).show(); } });

}

Do 2 fragment thu瓜c cùng m瓜t Activity, nên ta có thể truy xu医t đến View trong m厩i fragment thông qua Activity chung này. Activity ch泳a fragment đ逢嬰c l医y thông qua ph逢ơng th泳c getActivity().

Page 76: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

76

Page 77: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

77

Chươngàヴ. Giao diệnàngười dùng của ứng dụng Android

Trong các ch逢ơng tr逢噂c ta đư làm quen v噂i thành phần cơ b違n c栄a giao diện Android là Activity và vòng đ運i c栄a nó. Tuy nhiên b違n thân Activity không ph違i những th泳 chúng ta nhìn th医y trên màn hình điện tho衣i, thay vào đó Activity cần vẽ các thành phần đồ h丑a khác bên trong nó, là các View và ViewGroup. Trong ch逢ơng này chúng ta sẽ tìm hiểu chi tiết hơn về các View và ViewGroup trong Android để t衣o nên giao diện đồ h丑a c栄a 泳ng d映ng, cũng nh逢 cách th泳c t逢ơng tác v噂i chúng.

4.1. View và ViewGroup

Nh逢 đư đề cập 荏 trên, m厩i Activity muốn hiển th鵜 giao diện đồ h丑a cần ch泳a các thành phần giao diện khác nh逢 nút b医m, các nhãn, các ô nhập liệu, checkbox, radio button… Những thành phần nh逢 vậy trong Android đ逢嬰c g丑i chung là các View. T医t c違 các View đều đ逢嬰c kế thừa từ l噂p android.view.View.

M瓜t hoặc nhiều View có thể đ逢嬰c nhóm l衣i v噂i nhau trong m瓜t ViewGroup. M厩i ViewGroup cũng là m瓜t View, đ逢嬰c dùng để nhóm các View con bên trong nó và hiển th鵜 chúng theo m瓜t th泳 tự hay quy luật nào đó. M丑i ViewGroup đều đ逢嬰c kế thừa từ l噂p android.view.ViewGroup.

Các lo衣i ViewGroup phổ biến nh医t trong Android bao gồm:

➤ LinearLayout

➤ AbsoluteLayout

➤ TableLayout

➤ RelativeLayout

➤ FrameLayout

➤ ScrollView

Các View và ViewGroup t衣o thành giao diện c栄a Activity và th逢運ng đ逢嬰c mô t違 ngay trong file layout c栄a activity, nằm trong th逢 m映c res/layout (file mail.xml trong các ví d映 tr逢噂c đó). Ví d映:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:layout_width="160dp" android:layout_height="wrap_content" android:text="Button" android:layout_gravity="left" android:layout_weight="1" /> <Button android:layout_width="160dp" android:layout_height="wrap_content"

Page 78: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

78

android:text="Button" android:layout_gravity="center" android:layout_weight="2" /> <Button android:layout_width="160dp" android:layout_height="wrap_content" android:text="Button" android:layout_gravity="right" android:layout_weight="3" />

</LinearLayout>

M瓜t sô thu瓜c tính chung cho các View và ViewGroup đ逢嬰c kể ra trong b違ng d逢噂i đây:

Thu瓜c tính Mô t違

layout_width Chiều r瓜ng c栄a View|ViewGroup

layout_height Chiều cao c栄a View|ViewGroup

layout_marginTop Chiều r瓜ng kho違ng trống (lề) phía trên c栄a View

layout_marginBottom Chiều r瓜ng kho違ng trống (lề) phía d逢噂i c栄a View

layout_marginLeft Chiều r瓜ng kho違ng trống (lề) phía bên trái c栄a View

layout_marginRight Chiều r瓜ng kho違ng trống (lề) phía bên ph違i c栄a View

layout_gravity Cách xếp đặt View (trái, ph違i, trên, d逢噂i, giữa theo chiều d丑c, giữa theo chiều ngang)

Phần tiếp theo sẽ mô t違 chi tiết hơn về m瓜t số lo衣i ViewGroup phổ biến trên. Cần chú ý rằng trong thực tế sử d映ng, giao diện đồ h丑a c栄a 泳ng d映ng th逢運ng đ逢嬰c t衣o thành b荏i m瓜t tổ h嬰p phân c医p giữa các lo衣i ViewGroup khác nhau.

LinearLayout

LinearLayout sắp xếp các view con bên trong nó theo m瓜t c瓜t (từ trên xuống d逢噂i) hoặc theo m瓜t hang (từ trái qua ph違i). Các view con đ逢嬰c xếp d丑c hoặc ngang tùy thu瓜c vào tham số android:orientation c栄a LinearLayout, giá tr鵜 c栄a tham số này có thể là “vertical” (cho layout d丑c) hoặc “horizontal” (cho layout ngang).

Xem ví d映 sau:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:text="@string/hello" />

Page 79: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

79

<Button android:layout_width="160dp" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button" />

</LinearLayout>

Layout trên bao gồm m瓜t LinearLayout theo chiều d丑c, ch泳a 1 view bên trong là đo衣n chữ “Hello world” và nút b医m “Button” bên d逢噂i nó. Chiều r瓜ng và cao c栄a LinearLayout là fill_parent, t泳c là nó sẽ chiếm hết chiều r瓜ng, chiều dài c栄a view mẹ (trong tr逢運ng h嬰p này là Activity, t泳c là toàn màn hình). Chiều r瓜ng c栄a textview là 100dp (pixel không ph映 thu瓜c vào mật đ瓜 màn hình, chi tiết xem bên d逢噂i), chiều cao c栄a text này là wrap_content t泳c là chiều cao sẽ đ逢嬰c l医y bằng đúng chiều cao c栄a n瓜i dung ch泳a trong nó (ph映 thu瓜c vào số dòng chữ, kích th逢噂c chữ, kho違ng cách… thực tế).

Các đơn v鵜 đo kích th逢噂c trong Android có các lo衣i sau:

➤ dp (hoặc dip) - Density-independent pixel (điểm 違nh không ph映 thu瓜c vào mật đ瓜

màn hình). 1 dp t逢ơng đ逢ơng v噂i 1pixel trên màn hình có mật đ瓜 điểm 違nh 160 dpi (160 pixel trên m厩i inch màn hình). Đây là đơn v鵜 khuyên dùng trong hầu hết các tr逢運ng h嬰p đặt kích th逢噂c c栄a view trong layout. Chi tiết hơn về mật đ瓜 màn hình 荏 bên d逢噂i.

➤ sp - Scale-independent pixel, đơn v鵜 này t逢ơng tự dp, đ逢嬰c dùng khi mô t違 kích th逢噂c

font chữ (font size)

➤ pt - Point. 1 point = 1/72 inch, dựa trên kích th逢噂c vật lý thật c栄a màn hình.

➤ px – Pixel – m瓜t pixel vật lý trên màn hình, đơn v鵜 này không đ逢嬰c khuyên dùng

trong thiết kế giao diện 泳ng d映ng vì giao diện sẽ hiển th鵜 không đồng nh医t trên các màn hình có đ瓜 phân gi違i khác nhau.

Trong ví d映 荏 trên, nút b医m có chiều r瓜ng là 160dp, và textview là 100dp, để hiểu đ逢嬰c kích th逢噂c này, tr逢噂c hết ta xem khái niệm kích th逢噂c và mật đ瓜 màn hình trong Android. Ta xét trên ví d映 c映 thể: điện tho衣i Nexus S c栄a Google. Thiết b鵜 này có màn hình 4 inch theo đ逢ơng chéo, 2.04 inch theo chiều ngang, v噂i đ瓜 phân gi違i 480x800 pixel. Chiều r瓜ng 2.04 inch v噂i 480 pixel cho ta mật đ瓜 điểm 違nh kho違ng 235 dpi (dots per inch – điểm 違nh m厩i inch) – xem hình bên d逢噂i.

Page 80: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

80

Android đ鵜nh nghĩa 4 lo衣i mật đ瓜 màn hình nh逢 sau:

➤ Mật đ瓜 th医p: Low density (ldpi) - 120 dpi

➤ Mật đ瓜 trung bình: Medium density (mdpi) - 160 dpi

➤ Mật đ瓜 cao: High density (hdpi) - 240 dpi

➤ Mật đ瓜 r医t cao: Extra High density (xhdpi) - 320 dpi

M厩i thiết b鵜 sẽ đ逢嬰c xếp vào m瓜t trong các lo衣i mật đ瓜 trên, ví d映 thiết b鵜 Nexus S 荏 trên sẽ đ逢嬰c xếp vào thiết b鵜 mật đ瓜 cao, do mật đ瓜 màn hình (235dpi) gần nh医t v噂i mật đ瓜 hdpi – 240dpi. Còn điện tho衣i The HTC Hero, có màn hình 3.2inch, đ瓜 phân gi違i 320x480 có mật đ瓜 180dpi sẽ đ逢嬰c xếp vào điện tho衣i mật đ瓜 trung bình (mdpi) do gần nh医t v噂i con số 160dpi.

D逢噂i đây là giao diện c栄a layout trên ch衣y trên 2 thiết b鵜 có kích th逢噂c và đ瓜 phân gi違i khác nhau. Hình bên trái là thiết b鵜 4 inch, đ瓜 phân gi違i 480x800 (mật đ瓜 235dpi – hdpi), hình bên ph違i là thiết b鵜 3.2 inch, đ瓜 phân gi違i 320x480 (mật đ瓜 180dpi).

Page 81: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

81

Có thể th医y mặc dù ch衣y trên 2 thiết b鵜 đ瓜 phân gi違i, kích th逢噂c và mật đ瓜 khác nhau, nh逢ng nút b医m và text có kích th逢噂c r医t đồng nh医t (nút bẩm chiếm kho違ng 1/2 chiều ngang màn hình).

Kích th逢噂c thực tế (tính bằng pixel vật lý) đ逢嬰c tính từ kích th逢噂c dp nh逢 sau:

Kích th逢噂c pixel thật = dp * (dpi / 160), 荏 đó dpi = 120, 160, 240, hoặc 320 tùy thu瓜c vào màn hình thiết b鵜.

雲 ví d映 trên, nút b医m trên màn hình bên trái sẽ có kích th逢噂c thật là: 160*(240/160) = 240 pixel, còn trên màn hình bên ph違i sẽ là 160*(160/160) = 160 pixel.

Nếu ta thay đơn v鵜 dp trong khai báo layout 荏 trên thành đơn v鵜 px nh逢 d逢噂i đây:

<TextView android:layout_width="100px" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:layout_width="160px" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button" />

thì kết qu違 sẽ là:

Page 82: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

82

Nh逢 vậy có thể th医y việc sử d映ng đơn v鵜 px trong thiết kế UI là không nên, mà nên sử d映ng đơn v鵜 dp, đơn v鵜 này đư bao gồm việc thích nghi giao diện v噂i các kích th逢噂c màn hình khác nhau.

Nếu thay tham số android:orientation="vertical" c栄a linearlayout thành

android:orientation="horizontal", sẽ thu đ逢嬰c:

Page 83: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

83

AbsoluteLayout

AbsoluteLayout cho phép đặt các view con bên trong nó t衣i v鵜 trí chính xác, cố đ鵜nh, tính theo px hoặc dp. Layout lo衣i này không linh ho衣t và không thích nghi đ逢嬰c v噂i sự thay đổi c栄a đ瓜 phân gi違i màn hình, vì vậy không đ逢嬰c khuyên dùng trong các phiên Android gần đây. Vì vậy cho đến th運i điểm hiện t衣i, ta có thể quên đi lo衣i layout này.

TableLayout

Tablelayout cho phép sắp xếp các view con bên trong nó theo dòng và c瓜t. M厩i dòng đ逢嬰c đặt trong thẻ <TableRow>, m厩i view con trong TableRow đ逢嬰c đặt trong m瓜t ô c栄a dòng, chiều r瓜ng c栄a m厩i c瓜t đ逢嬰c xác đ鵜nh bằng chiều r瓜ng l噂n nh医t c栄a các ô trong c瓜t đó.

Xét ví d映 sau:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="fill_parent" android:layout_width="fill_parent" > <TableRow> <TextView android:text="User Name:" android:width ="120dp" /> <EditText android:id="@+id/txtUserName" android:width="200dp" />

Page 84: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

84

</TableRow> <TableRow> <TextView android:text="Password:" /> <EditText android:id="@+id/txtPassword" android:password="true" /> </TableRow> <TableRow> <TextView /> <CheckBox android:id="@+id/chkRememberPassword" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Remember Password" /> </TableRow> <TableRow> <Button android:id="@+id/buttonSignIn" android:text="Log In" /> </TableRow>

</TableLayout>

Kết qu違 c栄a layout trên khi ch衣y trên emulator sẽ nh逢 sau:

RelativeLayout

RelativeLayout cho phép các view con bên trong đ逢嬰c sắp đặt t逢ơng đối v噂i nhau và t逢ơng đối so v噂i view mẹ.

<RelativeLayout android:id="@+id/RLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <TextView android:id="@+id/lblComments"

Page 85: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

85

android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Comments" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" /> <EditText android:id="@+id/txtComments" android:layout_width="fill_parent" android:layout_height="170px" android:textSize="18sp" android:layout_alignLeft="@+id/lblComments" android:layout_below="@+id/lblComments" android:layout_centerHorizontal="true" /> <Button android:id="@+id/btnSave" android:layout_width="125px" android:layout_height="wrap_content" android:text="Save" android:layout_below="@+id/txtComments" android:layout_alignRight="@+id/txtComments" /> <Button android:id="@+id/btnCancel" android:layout_width="124px" android:layout_height="wrap_content" android:text="Cancel" android:layout_below="@+id/txtComments" android:layout_alignLeft="@+id/txtComments" />

</RelativeLayout>

Kết qu違 c栄a layout trên nh逢 sau:

Page 86: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

86

M厩i view con trong relativelayout có m瓜t số thu瓜c tính nh医t đ鵜nh giúp chúng căn ch雨nh theo view mẹ hoặc theo các view khác cùng c医p. Ta có thể th医y các thu瓜c tính này trong ví d映 荏 trên nh逢:

➤ layout_alignParentTop – xếp trên cùng so v噂i layout mẹ

➤ layout_alignParentLeft – căn trái so v噂i layout mẹ

➤ layout_alignLeft – căn trái so v噂i layout khác (có id đ逢嬰c ch雨 ra trong giá tr鵜 c栄a thu瓜c

tính này)

➤ layout_alignRight – căn trái so v噂i layout khác (có id đ逢嬰c ch雨 ra trong giá tr鵜 c栄a

thu瓜c tính này)

➤ layout_below – đặt xuống d逢噂i layout khác (có id đ逢嬰c ch雨 ra trong giá tr鵜 c栄a thu瓜c

tính này)

➤ layout_centerHorizontal – căn giữa theo chiều ngang so v噂i layout mẹ (relativelayout

hiện t衣i)

FrameLayout

Là layout đ逢嬰c dùng để hiện th鵜 m瓜t view bên trong. View con c栄a Framlayout luôn đ逢嬰c căn phía trên, bên trái so v噂i layout mẹ này. Nếu b衣n thêm nhiều hơn 1 view vào bên trong FrameLayout, thì các view này sẽ nằm chồng lên nhau nh逢 ví d映 d逢噂i đây.

<RelativeLayout android:id="@+id/RLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <TextView android:id="@+id/lblComments" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, Android!" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/lblComments" android:layout_below="@+id/lblComments" android:layout_centerHorizontal="true" > <ImageView android:src = "@drawable/droid" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:layout_width="124dp" android:layout_height="wrap_content" android:text="Print Picture" /> </FrameLayout>

Page 87: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

87

</RelativeLayout>

ScrollView

ScrollView là m瓜t FrameLayout đặc biệt, cho phép ng逢運i dùng cu瓜n d丑c màn hình khi n瓜i dung bên trong c栄a ScrollView chiếm nhiều diện tích hơn view mẹ.

<ScrollView android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:focusable="true" android:focusableInTouchMode="true" > <Button android:id="@+id/button1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Button 1" /> <Button android:id="@+id/button2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Button 2" /> <Button android:id="@+id/button3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Button 3" /> <EditText android:id="@+id/txt" android:layout_width="fill_parent" android:layout_height="600dp" /> <Button android:id="@+id/button4" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Button 4" />

Page 88: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

88

<Button android:id="@+id/button5" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Button 5" /> </LinearLayout>

</ScrollView>

Trong ví d映 trên, EditText 荏 giữa đ逢嬰c đặt chiều cao lên đến 600dp để chắc chắn nó v逢嬰t quá chiều cao c栄a màn hình điện tho衣i, khi đó khi ch衣y trên điện tho衣i/emulator, ta sẽ th医y view đ逢嬰c có thể cu瓜n lên, cu瓜n xuống (Xem hình bên d逢噂i).

4.2. Bố cục giao diện thích nghi vớiàhướng màn hình (ngang|dọc)

M瓜t tính năng xu医t hiện trên hầu hết các điện tho衣i thông mình hiện hành là tính năng tự đ瓜ng thay đổi h逢噂ng hiển th鵜 c栄a màn hình từ d丑c sang ngang hoặc ng逢嬰c l衣i khi ng逢運i dùng xoay điện tho衣i theo h逢噂ng t逢ơng 泳ng. Android cũng không ngo衣i lệ, khi thiết b鵜 thay đổi h逢噂ng từ d丑c sang ngang hoặc ng逢嬰c l衣i, activity hiện t衣i sẽ vẽ l衣i các view con c栄a mình theo h逢噂ng m噂i, khi đó hàm onCreate c栄a Activity sẽ đ逢嬰c g丑i l衣i từ đầu. Mặt khác, do diện tích và tỷ lệ vùng hiển th鵜 trong h逢噂ng d丑c và h逢噂ng ngang khác nhau t逢ơng đối nhiều, nên khi thiết kế layout ta cần có biện pháp thích h嬰p cho sự thay đổi này.

Có 2 ph逢ơng pháp phổ biến để thiết kế layout thích nghi v噂i sự thay đổi này:

➤ Neo – neo (xếp cố đ鵜nh) các view con theo các c衣nh c栄a màn hình. Đây là cách dễ làm

nh医t, khi kích th逢噂c màn hình thay đổi, v鵜 trí c栄a các layout con sẽ đ逢嬰c xếp l衣i nh逢ng vẫn căn theo các c衣nh gần nh医t.

Page 89: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

89

➤ Thay đổi kích th逢噂c và v鵜 trí – cách làm tốn công hơn và linh ho衣t hơn và sắp xếp l衣i

toàn b瓜 layout c栄a các view con khi có sự thay đổi về màn hình. Ngoài ra còn có thể thêm/b噂t view con v噂i những h逢噂ng nh医t đ鵜nh.

Ta sẽ xem ví d映 c映 thể cho 2 ph逢ơng án trên.

Neo các view con theo các cạnh màn hình

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Top Left" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Top Right" android:layout_alignParentTop="true" android:layout_alignParentRight="true" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bottom Left" android:layout_alignParentLeft="true" android:layout_alignParentBottom="true" /> <Button android:id="@+id/button4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bottom Right" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" /> <Button android:id="@+id/button5" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Middle" android:layout_centerVertical="true" android:layout_centerHorizontal="true" />

</RelativeLayout>

Trong ví d映 trên button1 đ逢嬰c neo theo góc trên bên trái, button2 – góc trên bên ph違i, button3 – góc d逢噂i bên trái, button4 – góc d逢噂i bên ph違i, button5 – chính giữa màn hình.

Layout trên khi hiển th鵜 trên màn hình d丑c và ngang sẽ nh逢 sau:

Page 90: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

90

Tha┞àđổiàkケIhàthước và vị trí

Trong ph逢ơng pháp này, thông th逢運ng m厩i h逢噂ng màn hình sẽ có m瓜t layout riêng. Layout này có thể đ逢嬰c c医u hình trong code, hoặc đặt file layout vào th逢 m映c c医u hình sẵn để hệ thống tự ch丑n lựa ch丑n trong quá trình ch衣y. Để t衣o layout riêng cho Activity trên trong màn hình ngang, ta t衣o th逢 m映c layout-land trong th逢 m映c res, sau đó t衣o file main.xml (trùng trên v噂i file layout trong th逢 m映c res/layout), v噂i n瓜i dung nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout

Page 91: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

91

android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Top Left" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Top Right" android:layout_alignParentTop="true" android:layout_alignParentRight="true" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bottom Left" android:layout_alignParentLeft="true" android:layout_alignParentBottom="true" /> <Button android:id="@+id/button4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bottom Right" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" /> <Button android:id="@+id/button5" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Middle" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <Button android:id="@+id/button6" android:layout_width="180px" android:layout_height="wrap_content" android:text="Top Middle" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:layout_alignParentTop="true" /> <Button android:id="@+id/button7" android:layout_width="180px" android:layout_height="wrap_content" android:text="Bottom Middle" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" />

</RelativeLayout>

Để ý th医y layout này có 7 nút thay vì 5 nút nh逢 layout mặc đ鵜nh (cho màn hình d丑c). Kết qu違 hiển th鵜 cho màn hình ngang sẽ xu医t hiện thêm 2 nút b医m 荏 trên và d逢噂i màn hình, căn giữa theo chiều ngang nh逢 hình d逢噂i:

Page 92: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

92

Ngoài ra khi thay đổi h逢噂ng màn hình, Activity sẽ đ逢嬰c vẽ l衣i hoàn toàn từ đầu, và sẽ tr衣ng thái hiện t衣i sẽ m医t, bao gồm giá tr鵜 c栄a các tr逢運ng, n瓜i dung c栄a các view không đ逢嬰c đặt tên trong layout… Vì vậy, trong tr逢運ng h嬰p cần thiết l逢u trữ tr衣ng thái hiện t衣i c栄a Activity, việc ta cần làm là n衣p chồng 2 hàm sau:

@Override public void onSaveInstanceState(Bundle outState) { //---save whatever you need to persist--- outState.putString("ID", "1234567890"); super.onSaveInstanceState(outState); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); //---retrieve the information persisted earlier--- String ID = savedInstanceState.getString("ID"); }

Dữ liệu cần l逢u trữ đ逢嬰c ch泳a trong m瓜t đối t逢嬰ng Bundle, chi tiết về đối t逢嬰ng này và các lo衣i dữ liệu có thể l逢u trữ trong nó b衣n đ丑c tự tìm hiểu coi nh逢 bài tập. Trong ví d映 trên ta đư tiến hành l逢u và l医y l衣i giá tr鵜 c栄a m瓜t chu厩i (“0123456789”) vào Bundle d逢噂i tên là “ID”.

Điều khiểnàhướng của màn hình

Trong m瓜t số tr逢運ng h嬰p, ta cần thiết kế m瓜t số Activity ch雨 h厩 tr嬰 m瓜t lo衣i h逢噂ng màn hình c映 thể. Ví d映 màn hình xem phim có thể đ逢嬰c thiết lập ch雨 có h逢噂ng nằm ngang, hay màn hình g丑i điện tho衣i đ逢嬰c thiết lập luôn luôn hiển th鵜 theo chiều d丑c.

Để làm việc này, ta có thể khai báo thu瓜c tính c栄a activity t逢ơng 泳ng trong file Manifest hoặc c医u hình trong mã nguồn c栄a hàm onCreate t逢ơng 泳ng v噂i Activity cần thiết lập.

Ví d映 về c医u hình h逢噂ng luôn nằm ngang trong mã nguồn:

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

Page 93: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

93

setContentView(R.layout.main); //---change to landscape mode--- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }

Và trong Manifest:

<activity android:label="@string/app_name" android:name=".OrientationsActivity" android:screenOrientation="landscape" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>

4.3. Sử dụngàtrクnhàđơnàふMenuぶ

Trình đơn dùng để hiển th鵜 các hành đ瓜ng th逢運ng ít dùng hơn và không hiển th鵜 trực tiếp lên màn hình. Trong Android có 2 lo衣i trình đơn :

➤ Trình đơn chính (Options menu) – hiển th鵜 các hành đ瓜ng liên quan đến toàn b瓜

Activity hiện t衣i. Trong Android, để kích ho衣t trình đơn này, ta b医m nút Menu c栄a thiết b鵜 (phím c泳ng hoặc phím 違o trên màn hình)

➤ Trình đơn ngữ c違nh (Context Menu) – hiển th鵜 các hành đ瓜ng liên quan đến m瓜t view

c映 thể trên màn hình, trình đơn này đ逢嬰c kích ho衣t bằng cách b医m và giữ ngón tay (long tap) trên view cần kích ho衣t trình đơn ngữ c違nh.

Hình d逢噂i đây minh h丑a trình đơn chính (bên trái) và trình đơn ngữ c違nh khi b医m và giữ trên 違nh (bên ph違i) c栄a 泳ng d映ng Browser (trình duyệt web):

Page 94: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

94

Về mặt lập trình, 2 lo衣i menu này sử d映ng cùng m瓜t l噂p (android.view.Menu) và ch泳a các đối t逢嬰ng giống nhau (android.view.MenuItem), vì vậy ta t衣o sẵn 2 ph逢ơng th泳c để dùng chung cho 2 lo衣i menu này để t衣o menu v噂i các item bên trong và xử lý sự kiện b医m vào từng item nh逢 d逢噂i đây:

Hàm CreateMenu dùng để thêm 7 items vào menu có sẵn (đ逢嬰c truyền vào d衣ng tham số):

private void CreateMenu(Menu menu) { menu.setQwertyMode(true); MenuItem mnu1 = menu.add(0, 0, 0, "Item 1"); { mnu1.setAlphabeticShortcut('a'); mnu1.setIcon(R.drawable.ic_launcher); } MenuItem mnu2 = menu.add(0, 1, 1, "Item 2"); { mnu2.setAlphabeticShortcut('b'); mnu2.setIcon(R.drawable.ic_launcher); } MenuItem mnu3 = menu.add(0, 2, 2, "Item 3"); { mnu3.setAlphabeticShortcut('c'); mnu3.setIcon(R.drawable.ic_launcher); } MenuItem mnu4 = menu.add(0, 3, 3, "Item 4"); { mnu4.setAlphabeticShortcut('d'); } menu.add(0, 4, 4, "Item 5"); menu.add(0, 5, 5, "Item 6"); menu.add(0, 6, 6, "Item 7");

}

Hàm MenuChoice để xử lý sự kiện t逢ơng 泳ng v噂i menu item đ逢嬰c lựa ch丑n (truyền vào d衣ng tham số). V噂i m映c đích minh h丑a, khi m瓜t menu item đ逢嬰c ch丑n, ta ch雨 đơn gian hiển th鵜 tên c栄a item đó d逢噂i d衣ng Toast.

private boolean MenuChoice(MenuItem item) { switch (item.getItemId()) { case 0: Toast.makeText(this, "You clicked on Item 1", Toast.LENGTH_LONG).show(); return true; case 1: Toast.makeText(this, "You clicked on Item 2", Toast.LENGTH_LONG).show(); return true; case 2: Toast.makeText(this, "You clicked on Item 3", Toast.LENGTH_LONG).show(); return true; case 3: Toast.makeText(this, "You clicked on Item 4", Toast.LENGTH_LONG).show(); return true; case 4:

Page 95: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

95

Toast.makeText(this, "You clicked on Item 5", Toast.LENGTH_LONG).show(); return true; case 5: Toast.makeText(this, "You clicked on Item 6", Toast.LENGTH_LONG).show(); return true; case 6: Toast.makeText(this, "You clicked on Item 7", Toast.LENGTH_LONG).show(); return true; } return false;

}

TrクnhàđơnàIhケnh

Để hiển th鵜 trình đơn chính, ta n衣p chồng hàm onCreateOptionMenu(Menu menu) và thêm các menu item vào đối t逢嬰ng menu (trong tham số c栄a hàm):

@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); CreateMenu(menu); return true;

}

Để hiển th鵜 menu này lúc ch衣y 泳ng d映ng, ta b医m phím MENU c栄a thiết b鵜.

Để xử lý sự kiện ch丑n m瓜t item trong menu hiện ra, ta cần n衣p chồng hàm onOptionsItemSelected(MenuItem item):

@Override public boolean onOptionsItemSelected(MenuItem item) { return MenuChoice(item); }

Hình bên d逢噂i minh h丑a menu chính đ逢嬰c t衣o 荏 trên trong tr逢運ng h嬰p thiết lập SDK nh臼 nh医t đ逢嬰c h厩 tr嬰 trong AndroidManifest.xml >=10 (hình bên trái) và < 10 (hình bên ph違i) (<uses-sdkandroid:minSdkVersion=“10” />).

Page 96: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

96

Trクnhàđơnàngữ cảnh

Để hiển th鵜 trình đơn ngữ c違nh, ta n衣p chồng hàm onCreateContextMenu(Menu menu) và thêm các menu item vào đối t逢嬰ng menu (trong tham số c栄a hàm):

@Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, view, menuInfo); CreateMenu(menu); }

Để xử lý sự kiện ch丑n m瓜t item trong menu hiện ra, ta cần n衣p chồng hàm onContextItemSelected (MenuItem item):

@Override public boolean onContextItemSelected (MenuItem item) { return MenuChoice(item); }

Để gắn menu ngữ c違nh này vào nút b医m button1, ta thêm code sau vào hàm onCreate c栄a activity:

Button btn = (Button) findViewById(R.id.button1); btn.setOnCreateContextMenuListener(this);

Để hiển th鵜 menu này lúc ch衣y 泳ng d映ng, ta b医m và giữ ngón tay lên trên nút b医m button1, trình đơn hiện ra nh逢 hình bên d逢噂i:

Page 97: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

97

4.4. Sử dụng thanh tác vụ (Action Bar)

Cùng v噂i Fragment, m瓜t tính năng m噂i đ逢嬰c gi噂i thiệu từ Android 3.0 HoneyComb là thanh tác v映 bên trong 泳ng d映ng (Action Bar) để thay thế cho thanh tiêu đề cũ. Action bar bao gồm icon c栄a 泳ng d映ng và tiêu đề c栄a Activity 荏 bên trái. Ngoài ra ng逢運i dùng có thể tùy ch丑n đặt 荏 bên ph違i các nút b医m đặc biệt, g丑i là action item. Hình bên d逢噂i minh h丑a action bar c栄a 泳ng d映ng email trong Android v噂i icon 泳ng d映ng, tiêu đề email và 4 action item 荏 bên ph違i:

Page 98: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

98

Action Bar dùng chung menu chính (option menu) nh逢 mô t違 trong phần tr逢噂c. Để các menu item trong menu chính hiển th鵜 trên Action bar d逢噂i d衣ng các action item, ta ch雨 cần g丑i hàm mnu1.setShowAsAction() c栄a m厩i menu item.

private void CreateMenu(Menu menu) { MenuItem mnu1 = menu.add(0, 0, 0, "Item 1"); { mnu1.setIcon(R.drawable.ic_launcher); mnu1.setShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } MenuItem mnu2 = menu.add(0, 1, 1, "Item 2"); { mnu2.setIcon(R.drawable.ic_launcher); mnu2.setShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } MenuItem mnu3 = menu.add(0, 2, 2, "Item 3"); { mnu3.setIcon(R.drawable.ic_launcher); mnu3.setShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } MenuItem mnu4 = menu.add(0, 3, 3, "Item 4"); { mnu4.setShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } MenuItem mnu5 = menu.add(0, 4, 4, "Item 5"); { mnu5.setShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); }

Page 99: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

99

}

Kết qu違 khi ch衣y trên thiết b鵜 nh逢 bên d逢噂i.

Đối v噂i màn hình d丑c, có ít diện tích để hiển th鵜 action item hơn (2 cái), 3 item còn l衣i sẽ hiển th鵜 d逢噂i d衣ng trình đơn chính bình th逢運ng:

Đối v噂i màn hình ngang, nhiều item đ逢嬰c hiển th鵜 d逢噂i d衣ng action item hơn (4 cái):

Page 100: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

100

4.5. Xử lý sự kiệnàtươngàt=Ià┗ới các thành phầnàđồ họa

Ng逢運i dùng t逢ơng tác v噂i giao diện đồ h丑a c栄a 泳ng d映ng Android d逢噂i 2 m泳c đ瓜: m泳c Activity và m泳c View. 雲 m泳c Activity, l噂p Activity cần n衣p chồng các ph逢ơng th泳c t逢ơng 泳ng đ逢嬰c đ鵜nh nghĩa sẵn. M瓜t số ph逢ơng th泳c nh逢 vậy có thể kể đến nh逢:

➤ onKeyDown – đ逢嬰c g丑i khi m瓜t phím đ逢嬰c nh医n xuống và sự kiện này ch逢a đ逢嬰c xử

lý b荏i b医t c泳 view con nào trong activty

➤ onKeyUp – đ逢嬰c g丑i khi m瓜t phím đ逢嬰c nh違 ra và sự kiện này ch逢a đ逢嬰c xử lý b荏i

b医t c泳 view con nào trong activty

➤ onMenuItemSelected – đ逢嬰c g丑i khi ng逢運i dùng lựa ch丑n m瓜t item trong menu đang đ逢嬰c m荏 ra

➤ onMenuOpened – đ逢嬰c g丑i khi m瓜t trình đơn đ逢嬰c m荏 ra.

Nạp chồng hàm xử lý sự kiện của Activity

Ví d映:

@Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: Toast.makeText(getBaseContext(), "Center was clicked", Toast.LENGTH_LONG).show(); break; case KeyEvent.KEYCODE_DPAD_LEFT: Toast.makeText(getBaseContext(), "Left arrow was clicked", Toast.LENGTH_LONG).show(); break; case KeyEvent.KEYCODE_DPAD_RIGHT: Toast.makeText(getBaseContext(), "Right arrow was clicked", Toast.LENGTH_LONG).show(); break; case KeyEvent.KEYCODE_DPAD_UP: Toast.makeText(getBaseContext(), "Up arrow was clicked", Toast.LENGTH_LONG).show(); break; case KeyEvent.KEYCODE_DPAD_DOWN: Toast.makeText(getBaseContext(), "Down arrow was clicked", Toast.LENGTH_LONG).show(); break; } return false;

}

Page 101: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

101

Đăngàkýàsự kiện cho từng View

M厩i view trong Android có thể sinh ra các sự kiện khi ng逢運i dùng tác đ瓜ng lên nó. Ví d映 nút b医m sinh ra sự kiện onClick khi ng逢運i dùng b医m vào nó, EditText sinh ra sự kiện onFocusChange khi nhận focus (ng逢運i dùng b医m vào ô nhập liệu này) hoặc m医t focus (khi view khác nhận focus).

Để đăng ký sự kiện t逢ơng tác v噂i các view, ta có thể sử d映ng “l噂p không tên” (anonymous class) nh逢 ví d映 d逢噂i đây:

Button btn1 = (Button)findViewById(R.id.btn1);

btn1.setOnClickListener(btnListener);

và:

//---create an anonymous class to act as a button click listener--- private OnClickListener btnListener = new OnClickListener() { public void onClick(View v) { Toast.makeText(getBaseContext(), ((Button) v).getText() + " was clicked", Toast.LENGTH_LONG).show(); }

};

Hoặc sử d映ng hàm n瓜i b瓜 không tên (anonymous inner class) nh逢 sau:

//---create an anonymous inner class to act as an onfocus listener--- EditText txt1 = (EditText)findViewById(R.id.txt1); txt1.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { Toast.makeText(getBaseContext(), ((EditText) v).getId() + " has focus - " + hasFocus, Toast.LENGTH_LONG).show(); }

});

Page 102: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

102

Chươngàヵ. Thiết kế giao diệnàngười dùng vớiàI=IàVie┘àIơàHản

Trong ch逢ơng tr逢噂c, chúng ta đư làm quen v噂i các lo衣i viewgroup trong Android và cách sử d映ng chúng để sắp xếp các view con trong activity. Trong ch逢ơng này ta sẽ làm quen v噂i các lo衣i view dùng để t衣o nên giao diện đồ h丑a cho 泳ng d映ng: các nút b医m, chữ, hình 違nh, danh sách…

5.1. Sử dụngàI=IàVie┘àIơàHản trong Android

Phần này mô t違 m瓜t số View cơ b違n nh医t th逢運ng đ逢嬰c dùng để t衣o nên giao diện đồ h丑a cho 泳ng d映ng Android nh逢:

➤ TextView

➤ EditText

➤ Button

➤ ImageButton

➤ CheckBox

➤ ToggleButton

➤ RadioButton

➤ RadioGroup

TextView

Nh逢 tên g丑i c栄a nó, TextView dùng để hiển th鵜 đo衣n văn b違n (d衣ng chữ) lên màn hình. Đây là view đơn gi違n nh医t và dùng r医t nhiều trong Android, ta đư gặp view này ngay từ dự án HelloAndroid trong những ch逢ơng đầu tiên:

<TextView android:layout_width="fill_parent" android:layout_height="wrap_content” android:text="@string/hello" />

Ngoài m瓜t số thu瓜c tính chung nh逢 layout_width, layout_height, b衣n có thể lựa ch丑n tùy ch雨nh kích th逢噂c font chữ (th逢運ng tính bằng sp – scalable pixel), lo衣i font chữ kiểu chữ (in đậm, in nghiêng), số dòng tối đa để hiển th鵜 đo衣n chữ…

Nếu b衣n muốn cho phép ng逢運i dùng thay đổi/nhập n瓜i dung chữ thì cần sử d映ng m瓜t view kế thừa từ TextView là EditText sẽ đ逢嬰c nhắc đến 荏 phần d逢噂i.

Button và ImageButton

Dùng để hiển th鵜 nút b医m lên màn hình. Sự kiện phổ biến nh医t c栄a nút b医m là sự kiện onClick đ逢嬰c sinh ra khi ng逢運i dùng b医m lên nút b医m này. Điểm khác nhau giữa Button và ImageButton là Button dùng chữ (text) làm nhãn, còn ImageButton dùng 違nh.

Page 103: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

103

EditText

Kế thừa từ l噂p TextView, cho phép ng逢運i dùng sửa đ逢嬰c n瓜i dung chữ trong nó

CheckBox

Là m瓜t lo衣i nút b医m đặc biệt, có 2 tr衣ng thái: ch丑n (checked) và b臼 ch丑n (unchecked)

RadioButton và RadioGroup

RadioButton có 2 tr衣ng thái là ch丑n và b臼 ch丑n, còn RadioGroup nhóm các RadioButton l衣i v噂i nhau để đ違m b違o cùng m瓜t lúc ch雨 có tối đa 01 RadioButton trong nhóm có tr衣ng thái ch丑n.

ToggleButton

T逢ơng tự nh逢 CheckBox, là m瓜t lo衣i nút b医m đặc biệt, có 2 tr衣ng thái là bật (checked) và tắt (unchecked).

Ta sẽ xem các view cơ b違n trên trong cùng m瓜t ví d映 d逢噂i đây:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/btnSave" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/save" android:onClick="btnSaved_clicked"/> <Button android:id="@+id/btnOpen" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Open" /> <ImageButton android:id="@+id/btnImg1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> <EditText android:id="@+id/txtName" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <CheckBox android:id="@+id/chkAutosave" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Autosave" /> <CheckBox android:id="@+id/star" style="?android:attr/starStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <RadioGroup android:id="@+id/rdbGp1" android:layout_width="fill_parent" android:layout_height="wrap_content"

Page 104: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

104

android:orientation="horizontal" > <RadioButton android:id="@+id/rdb1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Option 1" /> <RadioButton android:id="@+id/rdb2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Option 2" /> </RadioGroup> <ToggleButton android:id="@+id/toggle1" android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>

Ch衣y 泳ng d映ng v噂i activity có layout nh逢 trên, ta sẽ th医y các view cơ b違n này đ逢嬰c xếp từ trên xuống d逢噂i theo th泳 tự nh逢 trên (do nằm trong LinearLayout). Thử thực hiện các thao tác ch丑n trên các nút ToggleButton, CheckBox và RadioButton ta sẽ th医y tr衣ng thái ch丑n c栄a chúng nh逢 hình bên ph違i:

Ô nhập liệu (EditText) 荏 trên đ逢嬰c thiết lập chiều cao là “wrap_content” nên chiều cao c栄a nó sẽ đ逢嬰c tự đ瓜ng điều ch雨nh khi n瓜i dung bên trong thay đổi:

Page 105: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

105

View RadioButton có thu瓜c tính orientation t逢ơng tự nh逢 LinearLayout, cho phép xếp các RadionButton bên trong theo chiều d丑c hoặc chiều ngang.

M厩i view trong ví d映 trên đều đ逢嬰c đặt tên (dùng thu瓜c tính android:id), tên này đ逢嬰c sử d映ng trong mã nguồn để truy cập đến view t逢ơng 泳ng thông qua các hàm View.findViewById() hoặc Activity.findViewById().

Sau khi xác đ鵜nh đ逢嬰c view này theo id trong mã nguồn, ta có thể thêm các hàm xử lý sự kiện cho chúng. Ta xét ví d映 d逢噂i đây:

//---Button view--- Button btnOpen = (Button) findViewById(R.id.btnOpen); btnOpen.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { DisplayToast("You have clicked the Open button"); } }); //---CheckBox--- CheckBox checkBox = (CheckBox) findViewById(R.id.chkAutosave); checkBox.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (((CheckBox)v).isChecked()) DisplayToast("CheckBox is checked"); else DisplayToast("CheckBox is unchecked"); } }); //---RadioButton--- RadioGroup radioGroup = (RadioGroup) findViewById(R.id.rdbGp1); radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { RadioButton rb1 = (RadioButton) findViewById(R.id.rdb1); if (rb1.isChecked()) { DisplayToast("Option 1 checked!"); } else { DisplayToast("Option 2 checked!"); } }

Page 106: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

106

}); //---ToggleButton--- ToggleButton toggleButton = (ToggleButton) findViewById(R.id.toggle1); toggleButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (((ToggleButton)v).isChecked()) DisplayToast("Toggle button is On"); else DisplayToast("Toggle button is Off"); }

});

Trong đó, hàm DisplayToast đơn gi違n ch雨 hiển th鵜 thông báo d衣ng Toast lên màn hình:

private void DisplayToast(String msg) { Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT).show();

}

Riêng sự kiện onClick cho nút b医m btnSave đ逢嬰c khai báo ngay trong file layout:

android:onClick="btnSaved_clicked"

khi đó trong mư nguồn c栄a Activity cần khai báo hàm t逢ơng 泳ng:

public void btnSaved_clicked (View view) { DisplayToast("You have clicked the Save button1");

}

ProgressBar

ProgressBar cho phép hiển th鵜 thanh tr衣ng thái “ch運 đ嬰i” khi có m瓜t tác v映 gì đó đang ch衣y, nh逢 khi có m瓜t tác v映 t違i m瓜t tập tin ch衣y ngầm phía d逢噂i. Ví d映 d逢噂i đây minh h丑a cách sử d映ng thanh tình tr衣ng này.

Trong layout c栄a Activity, thêm view ProgressBar nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ProgressBar android:id="@+id/progressbar" android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>

Trong mã nguồn c栄a Activity, ta t衣o m瓜t Thread riêng để gi違 lập thao tác dài ch衣y ngầm và cập nhật l衣i tr衣ng thái c栄a progressBar sau m厩i b逢噂c thực hiện:

progress = 0; progressBar = (ProgressBar) findViewById(R.id.progressbar); progressBar.setMax(200);

Page 107: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

107

//---do some work in background thread--- new Thread(new Runnable() { public void run() { //—-do some work here—- while (progressStatus < 100) { progressStatus = doSomeWork(); //—-Update the progress bar—- handler.post(new Runnable() { public void run() { progressBar.setProgress(progressStatus); } }); } //---hides the progress bar--- handler.post(new Runnable() { public void run() { progressBar.setVisibility(View.GONE); } }); } //---do some long running work here--- private int doSomeWork() { try { //---simulate doing some work--- Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } return ++progress; } }).start();

Ch衣y 泳ng d映ng v噂i Activity nh逢 trên, ta sẽ th医y ProgressBar nh逢 hình minh h丑a bên d逢噂i:

Mặc đ鵜nh ProgressBar là thanh tr衣ng thái không xác đ鵜nh (không có tr衣ng thái c映 thể) nên ta sẽ ch雨 th医y hình tròn xoay xoay.

Page 108: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

108

Ta có thể thay đổi giao diện c栄a thanh tr衣ng thái này theo các cách khác nhau, ví d映 d逢噂i đây ta thêm thu瓜c tính style="@android:style/Widget.ProgressBar.Horizontal" để biến thanh tr衣ng thái thành d衣ng thanh ch衣y ngang có hiển th鵜 phần ch衣y xong và phần còn l衣i: <ProgressBar android:id="@+id/progressbar" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@android:style/Widget.ProgressBar.Horizontal" />

5.2. TimePicker và DatePicker

Ch丑n ngày tháng, gi運 là thao tác t逢ơng đối phổ biến trong các 泳ng d映ng đi đ瓜ng. Android cũng h厩 tr嬰 sẵn thao tác này thông qua các view TimePicker và DatePicker. Phần này sẽ mô t違 cách sử d映ng view này trong Android Activity.

TimePicker

TimePicker cho phép ng逢運i dùng ch丑n th運i gian trong ngày (gi運, phút) theo c違 2 chế đ瓜 24 gi運 và 12 gi運 v噂i AM/PM.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TimePicker android:id="@+id/timePicker" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/btnSet" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="I am all set!" android:onClick="onClick" />

</LinearLayout>

Giao diện trên bao gồm view ch丑n th運i gian và nút b医m, trong hàm onClick sử lý sự kiện b医m c栄a nút b医m này, ta sẽ in ra th運i gian đư đ逢嬰c ch丑n trong TimePicker:

public void onClick(View view) { Toast.makeText(getBaseContext(), "Time selected:" + timePicker.getCurrentHour() + ":" + timePicker.getCurrentMinute(), Toast.LENGTH_SHORT).show();

}

Page 109: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

109

Giao diện 泳ng d映ng sau khi ch衣y sẽ nh逢 sau:

B医m nút “I am all set”, th運i gian vừa đ逢嬰c ch丑n sẽ đ逢嬰c in ra màn hình d逢噂i d衣ng Toast.

Theo mặc đ鵜nh, TimePicker cho ta ch丑n th運i gian d逢噂i d衣ng 12 gi運 v噂i AM và PM, để hiển th鵜 th運i gian d逢噂i d衣ng 24 gi運, ta g丑i hàm setIs24HourView nh逢 sau:

timePicker = (TimePicker) findViewById(R.id.timePicker);

timePicker.setIs24HourView(true);

Kết qu違 thu đ逢嬰c:

Page 110: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

110

Tuy nhiên TimePicker t逢ơng đối tốn diện tích màn hình, vì vậy thông th逢運ng ng逢運i ta hay để ng逢運i dùng lựa ch丑n th運i gian trong m瓜t cửa sổ riêng, sau đó cập nhật th運i gian vừa lựa ch丑n vào giao diện chính d逢噂i d衣ng view khác (TextView chẳng h衣n).

Để ch丑n th運i gian trong h瓜p tho衣i, ta dùng TimePickerDialog cho ng逢運i dùng ch丑n th運i gian và viết sẵn m瓜t hàm lắng nghe sự kiện khi ng逢運i dùng ch丑n xong:

showDialog(TIME_DIALOG_ID);

và:

@Override protected Dialog onCreateDialog(int id) { switch (id) { case TIME_DIALOG_ID: return new TimePickerDialog( this, mTimeSetListener, hour, minute, false); } return null;

}

private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() { public void onTimeSet( TimePicker view, int hourOfDay, int minuteOfHour) { hour = hourOfDay; minute = minuteOfHour; SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm aa"); Date date = new Date(0,0,0, hour, minute);

Page 111: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

111

String strDate = timeFormat.format(date); Toast.makeText(getBaseContext(), "You have selected " + strDate, Toast.LENGTH_SHORT).show(); }

};

Kết qu違 ta thu đ逢嬰c nh逢 sau:

DatePicker

T逢ơng tự nh逢 TimePicker để ch丑n th運i gian, DatePicker đ逢嬰c dùng để ch丑n ngày tháng v噂i cách sử d映ng t逢ơng tự.

Sử d映ng trong layout:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/btnSet" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="I am all set!" android:onClick="onClick" /> <DatePicker android:id="@+id/datePicker"

Page 112: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

112

android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TimePicker android:id="@+id/timePicker" android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>

Hoặc sử d映ng h瓜p tho衣i thông qua DatePickerDialog:

showDialog(DATE_DIALOG_ID);

và:

@Override protected Dialog onCreateDialog(int id) { switch (id) { case DATE_DIALOG_ID: return new DatePickerDialog( this, mDateSetListener, yr, month, day); } return null; } private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() { public void onDateSet( DatePicker view, int year, int monthOfYear, int dayOfMonth) { yr = year; month = monthOfYear; day = dayOfMonth; Toast.makeText(getBaseContext(), "You have selected : " + (month + 1) + "/" + day + "/" + year, Toast.LENGTH_SHORT).show();

Page 113: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

113

} };

5.3. Hiển thị ảnh với ImageView và Gallery

謂nh là đối t逢嬰ng đ逢嬰c sử d映ng r医t tích cực trong các 泳ng d映ng hiện đ衣i. Trong phần này ta sẽ tìm hiểu cách hiển th鵜 違nh trong Android v噂i ImageView và hiển th鵜 danh sách 違nh v噂i Gallery view.

Ta sẽ xem xét 2 lo衣i view này trong m瓜t ví d映 t逢ơng đối điển hình: hiển th鵜 danh sách 違nh cho phép ng逢運i dùng cu瓜n và ch丑n 違nh cần xem. 謂nh đ逢嬰c ch丑n sẽ đ逢嬰c hiển th鵜 to hơn 荏 bên d逢噂i.

Tr逢噂c tiên ta chuẩn b鵜 m瓜t số 違nh cho dự án này:

Page 114: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

114

Các 違nh này ta sẽ đặt vào th逢 m映c res/ drawable-mdpi:

Trong mã nguồn, các 違nh này sẽ đ逢嬰c truy cập thông qua id c栄a nó trong l噂p R (resource):

R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7

Layout c栄a activity cho ví d映 này nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Images of San Francisco" /> <Gallery android:id="@+id/gallery1" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ImageView android:id="@+id/image1" android:layout_width="320dp" android:layout_height="250dp" android:scaleType="fitXY" />

</LinearLayout>

Mã nguồn c栄a activity này nh逢 sau: public class GalleryActivity extends Activity { //---the images to display--- Integer[] imageIDs = {

Page 115: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

115

R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7 }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Gallery gallery = (Gallery) findViewById(R.id.gallery1); gallery.setAdapter(new ImageAdapter(this)); gallery.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Toast.makeText(getBaseContext(), "pic" + (position + 1) + " selected", Toast.LENGTH_SHORT).show(); //---display the images selected--- ImageView imageView = (ImageView) findViewById(R.id.image1); imageView.setImageResource(imageIDs[position]); } }); } public class ImageAdapter extends BaseAdapter { Context context; int itemBackground; public ImageAdapter(Context c) { context = c; //---setting the style--- TypedArray a = obtainStyledAttributes(R.styleable.Gallery1); itemBackground = a.getResourceId( R.styleable.Gallery1_android_galleryItemBackground, 0); a.recycle(); } //---returns the number of images--- public int getCount() { return imageIDs.length; } //---returns the item--- public Object getItem(int position) { return position; } //---returns the ID of an item--- public long getItemId(int position) {

Page 116: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

116

return position; } //---returns an ImageView view--- public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { imageView = new ImageView(context); imageView.setImageResource(imageIDs[position]); imageView.setScaleType(ImageView.ScaleType.FIT_XY); imageView.setLayoutParams(new Gallery.LayoutParams(150, 120)); } else { imageView = (ImageView) convertView; } imageView.setBackgroundResource(itemBackground); return imageView; } }

}

Sau khi ch衣y 泳ng d映ng, ta sẽ quan sát th医y danh sách các 違nh nh臼 荏 phía trên cùng c栄a activity, ta có thể cu瓜n ngang danh sách này để ch丑n 違nh muốn xem, 違nh đ逢嬰c ch丑n sẽ luôn đ逢嬰c căn giữa trong Gallery. Sau khi đ逢嬰c ch丑n, 違nh to sẽ đ逢嬰c hiển th鵜 bên d逢噂i (xem hình minh h丑a bên d逢噂i).

Page 117: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

117

Ta cần gi違i thích thêm m瓜t chút về đo衣n mã nguồn c栄a Activity phía trên. Đầu tiên, ta l逢u danh sách ID c栄a các 違nh cần thêm vào Gallery:

Integer[] imageIDs = { R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7

};

Sau đó, để thêm các 違nh này vào Gallery, ta cần m瓜t l噂p trung gian, g丑i là adapter. Adapter này sẽ cung c医p nguồn n瓜i dung cho các đối t逢嬰ng gồm nhiều phần tử nh逢 Gallery hay các danh sách. Ta sẽ xem chi tiết adapter này 荏 phía d逢噂i. Để gắn adapter này vào gallery, ta dùng hàm setAdapter:

gallery.setAdapter(new ImageAdapter(this));

Khi m瓜t 違nh trong gallery đ逢嬰c ch丑n, ta sẽ hiển th鵜 違nh to phía d逢噂i, để làm việc này, ta cần thêm hàm xử lý sự kiện onItemClick c栄a gallery:

gallery.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Toast.makeText(getBaseContext(), "pic" + (position + 1) + " selected", Toast.LENGTH_SHORT).show(); //---display the images selected--- ImageView imageView = (ImageView) findViewById(R.id.image1); imageView.setImageResource(imageIDs[position]); }

});

M厩i l噂p adapter cho các view nhiều đối t逢嬰ng (nh逢 gallery) cần kế thừa từ l噂p BaseAdapter và cần n衣p chồng các ph逢ơng th泳c sau:

public class ImageAdapter extends BaseAdapter { public ImageAdapter(Context c){ … } public int getCount(){ … } public Object getItem(int position) { … } public long getItemId(int position) { … } public View getView(int position, View convertView, ViewGroup parent) {…} }

Trong đó hàm getView tr違 về view c栄a đối t逢嬰ng con (item) trong danh sách, t衣i v鵜 trí position.

M瓜t số view sử d映ng Adapter làm nguồn dữ liệu trong Android có thể kể đến nh逢:

➤ ListView: danh sách các đối t逢嬰ng (theo chiều d丑c)

Page 118: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

118

➤ GridView: danh sách các đối t逢嬰ng d衣ng b違ng (nhiều c瓜t, cuốn theo chiều d丑c)

➤ Spinner: danh sách xổ xuống (giống khái niệm combo box trong lập trình web)

➤ Gallery: th逢 viện 違nh nh逢 ví d映 荏 trên

Android cũng đ鵜nh nghĩa sẵn m瓜t số l噂p con c栄a l噂p BasicAdapter nh逢:

➤ ListAdapter

➤ ArrayAdapter

➤ CursorAdapter

➤ SpinnerAdapter

Chúng ta sẽ tìm hiểu m瓜t số l噂p trong số đó trong phần còn l衣i c栄a giáo trình.

5.4. Sử dụngàListVie┘àđể hiển thị danh sách dài

Trong Android để hiển th鵜 tập h嬰p nhiều phần tử cùng lo衣i, ta dùng danh sách. Có 2 lo衣i danh sách đ逢嬰c đ鵜nh nghĩa sẵn là ListView và SpinnerView. Trong phần này ta sẽ lần l逢嬰t xem xét từng lo衣i danh sách này.

ListView

ListView hiển th鵜 danh sách các đối t逢嬰ng con d逢噂i d衣ng danh sách d丑c, có kh違 năng cu瓜n khi chiều dài danh sách v逢嬰t quá chiều cao c栄a view mẹ. Ta sẽ xem xét ListView trong tr逢運ng h嬰p đơn gi違n nh医t: hiển th鵜 danh sách các phần tử d衣ng chữ.

Tr逢噂c tiên, ta chuẩn b鵜 m違ng dữ liệu các chữ cần hiển th鵜 trong danh sách. Ta có thể code c泳ng danh sách này trong mã nguồn java c栄a Activity nh逢 sau:

String[] presidents= { "Dwight D. Eisenhower", "John F. Kennedy", "Lyndon B. Johnson", "Richard Nixon", "Gerald Ford", "Jimmy Carter", "Ronald Reagan", "George H. W. Bush", "Bill Clinton", "George W. Bush", "Barack Obama"

};

Tuy nhiên cách làm này làm cho mã nguồn rối hơn, gây khó khăn cho việc b違o trì, cũng nh逢 h衣n chế kh違 năng đ鵜a ph逢ơng hóa (thay đổi ngôn ngữ 泳ng d映ng). Vì vậy, trong lập trình Android, ph逢ơng pháp đ逢嬰c khuyên dùng là đ鵜nh nghĩa các dữ liệu tĩnh này trong th逢 m映c “res”. C映 thể, đối v噂i m違ng chữ nh逢 trên, ta có thể đ鵜nh nghĩa trong file “res/values/string.xml” nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, BasicViews5Activity!</string>

Page 119: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

119

<string name="app_name">BasicViews5</string> <string-array name="presidents_array"> <item>Dwight D. Eisenhower</item> <item>John F. Kennedy</item> <item>Lyndon B. Johnson</item> <item>Richard Nixon</item> <item>Gerald Ford</item> <item>Jimmy Carter</item> <item>Ronald Reagan</item> <item>George H. W. Bush</item> <item>Bill Clinton</item> <item>George W. Bush</item> <item>Barack Obama</item> </string-array>

</resources>

Sau đó, trong mư nguồn Java, ta có thể dễ dàng l医y ra m違ng này bằng cách nh逢 sau:

String[] presidents; presidents = getResources().getStringArray(R.array.presidents_array);

Để t衣o m瓜t danh sách, tr逢噂c tiên ra khai báo 1 ListView trong file layout c栄a Activity:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@+id/android:list" android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>

Đối v噂i Activity có m瓜t ListView bên trong, Android đ鵜nh nghĩa sẵn l噂p con c栄a Activity là ListActivity giúp cho quá trình làm việc v噂i ListView tr荏 đơn gi違n hơn. Để có thể d映ng đ逢嬰c ListActivity này, có 2 việc cần ph違i làm:

- Activity ph違i kế thừa từ l噂p android.app.ListActivity

- ListView trong file layout c栄a Activity ph違i có id là "@+id/android:list"

Mã nguồn c栄a Activity sẽ nh逢 sau: public class BasicViews5Activity extends ListActivity { String[] presidents; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); presidents = getResources().getStringArray(R.array.presidents_array); setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, presidents));

Page 120: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

120

} @Override public void onListItemClick( ListView parent, View v, int position, long id) { Toast.makeText(this, "You have selected " + presidents[position], Toast.LENGTH_SHORT).show(); }

}

ListView trong Android cũng l医y n瓜i dung từ m瓜t Adapter giống nh逢 tr逢運ng h嬰p c栄a Gallery ta đư làm quen tr逢噂c đó. Đối v噂i ListActivity, ta không cần l医y tham chiếu đến ListView m瓜t cách minh b衣ch, mà có thể g丑i thẳng hàm setListAdapter để đặt adapter cho listView trong Activity (đ逢嬰c đặt id theo quy đ鵜nh nh逢 đư nói 荏 trên).

Để xử lý sự kiện ng逢運i dùng b医m ch丑n m瓜t phần tử trong ListView, ta ch雨 cần n衣p chồng hàm onListItemClick nh逢 đo衣n code 荏 trên. Trong ví d映 này ta ch雨 đơn thuần in ra chữ c栄a phần tử đ逢嬰c ch丑n.

Activity trên khi ch衣y trên emulator sẽ có d衣ng nh逢 sau:

Ta có thể vuốt lên/xuống màn hình để xem toàn b瓜 danh sách.

Có r医t nhiều tùy ch丑n có thể làm v噂i ListView, b衣n đ丑c tự tìm hiểu coi nh逢 bài tập, 荏 đây ta ch雨 nói thêm m瓜t tính kh違 năng c栄a ListView cho phép lựa ch丑n nhiều phần tử cùng lúc (multi-item selection). Để bật tính năng này, ta ch雨 cần g丑i hàm setChoiceMode c栄a ListView nh逢 sau:

ListView lstView = getListView();

lstView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

Page 121: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

121

ListView v噂i thu瓜c tính lựa ch丑n nhiều phần tử đ逢嬰c bật sẽ có d衣ng nh逢 sau:

SpinnerView

ListView r医t tiện d映ng cho việc hiển th鵜 danh sách các phần tử đồng d衣ng. Tuy nhiên ListView chiếm t逢ơng đối nhiều diện tích trên màn hình. Trong thực tế có nhiều tr逢運ng h嬰p ta ch雨 cần hiển th鵜 phần tử đang ch丑n c栄a danh sách, khi b医m vào phần tử này, sẽ hiện ra danh sách đầy đ栄 các phần tử còn l衣i để ta lựa ch丑n. Để làm đ逢嬰c việc này, ta dùng SpinnerView. Để dễ hình dung, ta có thể hiều SpinnerView chính là ComboBox trong lập trình web và Windows Form.

Trong ví d映 d逢噂i đây, ta vẫn hiễn th鵜 danh sách các phần tử d衣ng chữ nh逢 ví d映 tr逢噂c, tuy nhiên dùng SpinerView thay cho ListView.

Tr逢噂c tiên ta thêm khai báo m瓜t SpinnerView trong file layout c栄a Activity:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Spinner android:id="@+id/spinner1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawSelectorOnTop="true" />

Page 122: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

122

</LinearLayout>

Sau đó, trong hàm onCreate c栄a Activity, ta cần thêm mã nguồn để truy xu医t đến SpinnerView này, đặt adapter cho nó và thêm hàm xử lý sự kiện khi ta ch丑n m瓜t phần tử c栄a spinner:

presidents = getResources().getStringArray(R.array.presidents_array); Spinner s1 = (Spinner) findViewById(R.id.spinner1); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, presidents); s1.setAdapter(adapter); s1.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { int index = arg0.getSelectedItemPosition(); Toast.makeText(getBaseContext(), "You have selected item : " + presidents[index], Toast.LENGTH_SHORT).show(); } @Override public void onNothingSelected(AdapterView<?> arg0) { }

});

Khi m瓜t phần tử c栄a SpinnerView đ逢嬰c ch丑n, ta ch雨 đơn thuần in lên màn hình thông báo d衣ng Toast. Ch衣y 泳ng d映ng vừa t衣o lên thiết b鵜 hoặc emulator, ta sẽ quan sát th医y spinner view c栄a chúng ta sẽ có d衣ng nh逢 hình d逢噂i đây:

Page 123: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

123

5.5. Hiển thị nội dung trang web với WebView

WebView cho phép chúng ta nhúng trình duyệt web vào bên trong 泳ng d映ng c栄a mình. Sử d映ng web view r医t hữu d映ng trong tr逢運ng h嬰p chúng ta cần hiển th鵜 n瓜i dung m瓜t trang web bên trong 泳ng d映ng, cũng nh逢 khi chúng ta muốn thiết kế m瓜t phần hoặc thậm chí toàn b瓜 giao diện bằng ngôn ngữ web quen thu瓜c (HTML5, Javascript, CSS).

Trong ví d映 d逢噂i đây, ta sẽ sử d映ng web view để hiển th鵜 n瓜i dung c栄a m瓜t trang web trên Internet, c映 thể ta sẽ hiển th鵜 m瓜t biểu đồ từ d鵜ch v映 Chart c栄a Google.

Tr逢噂c tiên, ta cần thêm m瓜t WebView vào file layout c栄a Activity:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <WebView android:id="@+id/webview1" android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>

Sau đó trong hàm onCreate c栄a Activity, ta cần thêm đo衣n mư để c医u hình có webview này hiển th鵜 n瓜i dung trang web từ internet:

WebView wv = (WebView) findViewById(R.id.webview1);

Page 124: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

124

WebSettings webSettings = wv.getSettings(); webSettings.setBuiltInZoomControls(true); wv.loadUrl( "http://chart.apis.google.com/chart" + "?chs=300x225" + "&cht=v" + "&chco=FF6342,ADDE63,63C6DE" + "&chd=t:100,80,60,30,30,30,10" +

"&chdl=A|B|C");

Ngoài ra, do 泳ng d映ng muốn truy cập vào Internet để l医y dữ liệu từ trang web c栄a Google Chart, ta cần khai báo quyền truy cập Internet m瓜t cách t逢運ng mình trong file AndroidManifest.xml nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="net.learn2develop.WebView" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" /> <uses-permission android:name="android.permission.INTERNET"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >

… </application>

</manifest>

Ch衣y 泳ng d映ng trên điện tho衣i hoặc Emulator, ta sẽ th医y m瓜t đồ th鵜 đ逢嬰c vẽ b荏i d鵜ch v映 Google Chart trên màn hình:

Page 125: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

125

Ngoài ra, WebView cũng có thể đ逢嬰c dùng để hiển th鵜 giao diện bằng HTML ta tự khai báo trong mã nguồn nh逢 ví d映 d逢噂i đây:

WebView wv = (WebView) findViewById(R.id.webview1); WebSettings webSettings = wv.getSettings(); webSettings.setBuiltInZoomControls(true); final String mimeType = "text/html"; final String encoding = "UTF-8"; String html = "<H1>A simple HTML page</H1><body>" + "<p>The quick brown fox jumps over the lazy dog</p></body>";

wv.loadDataWithBaseURL("", html, mimeType, encoding, "");

Ch衣y 泳ng d映ng, ta sẽ th医y giao diện t逢ơng tự nh逢 minh h丑a trong hình sau:

Page 126: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

126

Page 127: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

127

Chươngàヶ. Lưuàtrữ dữ liệu

Trong ch逢ơng này chúng ta sẽ xem xét cách th泳c l逢u trữ dữ liệu trong Android. L逢u trữ dữ liệu là tính năng quan tr丑ng đối v噂i những 泳ng d映ng nghiêm túc, giúp cho ng逢運i dùng có thể dùng l衣i đ逢嬰c những dữ liệu tr逢噂c đó mà không cần nhập l衣i. Trong Android có 3 cách để l逢u l衣i dữ liệu:

➤ Cơ chế “c医u hình chia sẻ” (shared preferences) đ逢嬰c dùng để l逢u những dữ liệu nh臼

d逢噂i d衣ng key-value (tên khóa – giá tr鵜 khóa)

➤ L逢u dữ liệu cố đ鵜nh vào tập tin trong b瓜 nh噂 trong hoặc b瓜 nh噂 ngoài c栄a điện tho衣i

➤ L逢u dữ liệu quan hệ sử d映ng cơ s荏 dữ liệu quan hệ c映c b瓜 SQLite

Chúng ta sẽ lần l逢嬰t duyệt qua các ph逢ơng pháp kê trên trong ch逢ơng này.

6.1.àLưuàtrữ dữ liệu cố định với shared preferences

Android cung c医p sẵn m瓜t cơ chế cho đơn gi違n giúp chúng ta l逢u trữ nhanh các dữ liệu ngắn nh逢 c医u hình 泳ng d映ng, tên đăng nhập, email… và l医y l衣i dữ liệu đư ghi này trong các lần ch衣y 泳ng d映ng tiếp theo.

Cách th泳c thuận tiện nh医t là mô t違 tập trung các c医u hình ta cần l逢u l衣i trong m瓜t Activity (th逢運ng là màn hình “Settings” c栄a 泳ng d映ng). Android cung c医p sẵn m瓜t lo衣i Activity đặc biệt là PreferenceActivity giúp đơn hóa quá trình này. Ví d映 d逢噂i đây minh h丑a cách sử d映ng Activity này.

Để sử d映ng đ逢嬰c PreferenceActivity, tr逢噂c hết ta mô t違 các thông tin ta cần l逢u l衣i trong m瓜t tài liệu xml trong th逢 m映c “res/xml”, trong ví d映 này, ta t衣o file “res/xml/myapppreferences.xml” v噂i n瓜i dung nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="Category 1"> <CheckBoxPreference android:title="Checkbox" android:defaultValue="false" android:summary="True or False" android:key="checkboxPref" /> </PreferenceCategory> <PreferenceCategory android:title="Category 2"> <EditTextPreference android:summary="Enter a string" android:defaultValue="[Enter a string here]" android:title="Edit Text" android:key="editTextPref" /> <RingtonePreference android:summary="Select a ringtone" android:title="Ringtones" android:key="ringtonePref" /> <PreferenceScreen android:title="Second Preference Screen" android:summary=

Page 128: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

128

"Click here to go to the second Preference Screen" android:key="secondPrefScreenPref" > <EditTextPreference android:summary="Enter a string" android:title="Edit Text (second Screen)" android:key="secondEditTextPref" /> </PreferenceScreen> </PreferenceCategory> </PreferenceScreen>

Sau đó, ta cần t衣o m瓜t Activity kế thừa từ PreferenceActivity v噂i n瓜i dung nh逢 sau: import android.os.Bundle; import android.preference.PreferenceActivity; public class AppPreferenceActivity extends PreferenceActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

PreferenceManager prefMgr = getPreferenceManager(); prefMgr.setSharedPreferencesName("appPreferences"); //---load the preferences from an XML file--- addPreferencesFromResource(R.xml.myapppreferences); }

}

Ch衣y 泳ng d映ng v噂i Activity nh逢 trên, ta sẽ có ngay m瓜t màn hình settings cho 泳ng d映ng:

Page 129: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

129

N瓜i dung c栄a màn hình này đ逢嬰c mô t違 hoàn toàn trong file xml 荏 trên, trong đó chia các c医u hình này thành 2 danh m映c (category 1 và category 2) và m瓜t số lo衣i c医u hình khác nhau nh逢 checkbox, edittext, nh衣c chuông và m瓜t ví d映 minh h丑a cho việc m荏 thêm màn hình c医u hình th泳 2 (khi màn hình đầu có nhiều chi tiết).

B医m vào edittext, sẽ có popup cho b衣n nhập giá tr鵜 cần l逢u l衣i:

C医u hình nh衣c chuông:

Page 130: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

130

Màn hình preference th泳 2:

Page 131: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

131

Sauk hi b衣n thay đổi giá tr鵜 c栄a các m映c c医u hình trong Activity này, hệ thống sẽ tự đ瓜ng l逢u l衣i giá tr鵜 c栄a chúng để có thể sử d映ng đ逢嬰c trong các lần tiếp theo.

Việc l逢u trữ dữ liệu này là trong suốt v噂i ng逢運i dùng, tuy nhiên v噂i máy 違o Android ta có thể xem đ逢嬰c c映 thể các giá tr鵜 này. Trên thực tế chúng đ逢嬰c l逢u trong 1 file xml nằm trên b瓜 nh噂 trong, trong vùng nh噂 ch雨 có thể truy cập đ逢嬰c b荏i 泳ng d映ng t衣o ra nó (th逢 m映c /data/data/{package-name}/shared_prefs/appPreferences.xml):

N瓜i dung file này có d衣ng nh逢 sau:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="editTextPref">HUMG - Software engineer</string> <string name="secondEditTextPref">HUMG - 2nd screen text</string> <string name="ringtonePref">content://settings/system/ringtone</string> <boolean name="checkboxPref" value="true" />

Page 132: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

132

</map>

Để l医y giá tr鵜 c栄a các c医u hình này trong code, ta làm nh逢 sau: SharedPreferences appPrefs = getSharedPreferences("appPreferences",

MODE_PRIVATE);

Toast.makeText(this, appPrefs.getString("editTextPref", ""),

Toast.LENGTH_LONG).show();

Trong đó là tên c栄a file c医u hình cần m荏 (đ逢嬰c đặt 荏 hàm

prefMgr.setSharedPreferencesName("appPreferences"); phía trên), còn editTextPref là tên c栄a thu瓜c tính cần l医y giá tr鵜 (đ逢嬰c đặt trong file res/xml/myappprefererences.xml 荏 trên).

Ngoài ra ta cũng có thể đặt l衣i giá tr鵜 c栄a các c医u hình này bằng tay mà không cần thông

qua PreferenceActivity bằng cách sử d映ng SharedPreferences.Editor nh逢 sau:

SharedPreferences appPrefs = getSharedPreferences("appPreferences", MODE_PRIVATE); SharedPreferences.Editor prefsEditor = appPrefs.edit(); prefsEditor.putString("editTextPref", ((EditText) findViewById(R.id.txtString)).getText().toString());

prefsEditor.commit();

Sauk hi thay đổi giá tr鵜 c栄a các thu瓜c tính cần thay đổi, ta cần g丑i ph逢ơng th泳c commit() c栄a l噂p Editor này để các thay đổi có hiệu lực (tiến hành ghi vào file xml trong b瓜 nh噂 trong nh逢 mô t違 荏 trên)

ヶ.ヲ.àLưuàtrữ dữ liệu với file trên bộ nhớ trong và bộ nhớ ngoài

Trong tr逢運ng h嬰p bàn cần l逢u l衣i dữ liệu t逢ơng đối ph泳c t衣p hơn (khó có thể l逢u l衣i d衣ng key-value trong shared preference), ta có thể dùng hệ thống file. Trong Android, để làm việc (nhập/xu医t) v噂i file, ta có thể d映ng các l噂p c栄a gói java.io. Trong phần này ta sẽ xem cách làm việc v噂i file trong b瓜 nh噂 trong lẫn b瓜 nh噂 ngoài.

Làm việc với file trong bộ nhớ trong

Ta sẽ t衣o m瓜t Activity có m瓜t ô nhập văn b違n (EditText) và 2 nút b医m cho phép ghi và đ丑c văn b違n này vào file.

Layout c栄a Activity này nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Please enter some text" /> <EditText android:id="@+id/txtText1"

Page 133: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

133

android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnSave" android:text="Save" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="onClickSave" /> <Button android:id="@+id/btnLoad" android:text="Load" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="onClickLoad" />

</LinearLayout>

Mã nguồn c栄a Activity v噂i 2 hàm đ丑c (onClickLoad) và ghi (onClickSave) vào file nh逢 sau:

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class FilesActivity extends Activity { EditText textBox; static final int READ_BLOCK_SIZE = 100; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textBox = (EditText) findViewById(R.id.txtText1); } public void onClickSave(View view) { String str = textBox.getText().toString(); try { FileOutputStream fOut = openFileOutput("textfile.txt", MODE_PRIVATE); OutputStreamWriter osw = new OutputStreamWriter(fOut); //---write the string to the file--- osw.write(str); osw.flush(); osw.close();

Page 134: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

134

//---display file saved message--- Toast.makeText(getBaseContext(), "File saved successfully!", Toast.LENGTH_SHORT).show(); //---clears the EditText--- textBox.setText(""); } catch (IOException ioe) { ioe.printStackTrace(); } } public void onClickLoad(View view) { try { FileInputStream fIn = openFileInput("textfile.txt"); InputStreamReader isr = new InputStreamReader(fIn); char[] inputBuffer = new char[READ_BLOCK_SIZE]; String s = ""; int charRead; while ((charRead = isr.read(inputBuffer))>0) { //---convert the chars to a String--- String readString = String.copyValueOf(inputBuffer, 0, charRead); s += readString; inputBuffer = new char[READ_BLOCK_SIZE]; } //---set the EditText to the text that has been // read--- textBox.setText(s); Toast.makeText(getBaseContext(), "File loaded successfully!", Toast.LENGTH_SHORT).show(); } catch (IOException ioe) { ioe.printStackTrace(); } }

}

Trong đo衣n mã trên, ta th医y việc đ丑c ghi vào file t逢ơng đối đơn gi違n và quen thu瓜c, để ghi dữ liệu vào file, ta t衣o m瓜t đối t逢嬰ng OutputStreamWriter trên luồng xu医t FileOutputStream và tiến hành ghi vào qua ph逢ơng th泳c write. Sau đó g丑i flush để đẩy hết dữ liệu trong b瓜 đệm vào file và đóng luồng l衣i:

FileOutputStream fOut = openFileOutput("textfile.txt", MODE_PRIVATE); OutputStreamWriter osw = new OutputStreamWriter(fOut);

Page 135: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

135

//---write the string to the file--- osw.write(str); osw.flush(); osw.close();

Để đ丑c n瓜i dung file này, ta cũng thao tác t逢ơng tự, t衣o đối t逢嬰ng InputStreamReader từ luồng nhập liệu (FileInputStream) và tiến hành đ丑c dữ liệu bằng ph逢ơng th泳c read(). M厩i lần

đ丑c sẽ đ丑c READ_BLOCK_SIZE byte và l逢u vào b瓜 đệm (m違ng byte), n瓜i dung này sẽ đ逢嬰c chuyển thành string và nối thêm vào biến s, quá trình đ逢嬰c lặp l衣i cho đến khi hết n瓜i dung c栄a file:

FileInputStream fIn = openFileInput("textfile.txt"); InputStreamReader isr = new InputStreamReader(fIn); char[] inputBuffer = new char[READ_BLOCK_SIZE]; String s = ""; int charRead; while ((charRead = isr.read(inputBuffer))>0) { String readString = String.copyValueOf(inputBuffer, 0, charRead); s += readString; inputBuffer = new char[READ_BLOCK_SIZE]; } textBox.setText(s);

M瓜t câu h臼i đặt ra là file "textfile.txt" 荏 trên đ逢嬰c t衣o ra 荏 đâu trong cây th逢 m映c. Câu tr違 l運i là nó đ逢嬰c t衣o ra trong b瓜 nh噂 trong c栄a thiết b鵜, trong th逢 m映c dành riêng cho 泳ng d映ng (/data/data/{package-name}/files)

Ch衣y 泳ng d映ng, nhập n瓜i dung cho ô nhập liệu và b医m Save, ta sẽ th医y n瓜i dung văn b違n này đ逢嬰c ghi vào file trong b瓜 nh噂 trong.

Page 136: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

136

Kéo file này về máy tính để xem n瓜i dung file, ta sẽ th医y n瓜i dung văn b違n ta nhập vào tr逢噂c đó

Làm việc với file trong bộ nhớ ngoài

File trong b瓜 nh噂 trong ch雨 đ逢嬰c truy cập b荏i 泳ng d映ng t衣o ra nó. Ngoài ra dung l逢嬰ng l逢u trữ c栄a b瓜 nh噂 trong th逢運ng h衣n chế hơn b瓜 nh噂 ngoài (SDCard). Vì vậy trong tr逢運ng h嬰p ta muốn chia sẻ thông tin l逢u trữ v噂i các 泳ng d映ng khác, ta nên sử d映ng b瓜 nh噂 ngoài. Làm việc v噂i file trong b瓜 nh噂 ngoài hoàn toàn t逢ơng tự v噂i file trong b瓜 nh噂 trong, ch雨 khác phần l医y ra FileInputStream và FileOutputStream:

Thay vì dùng:

FileOutputStream fOut = openFileOutput("textfile.txt", MODE_PRIVATE);

Ta dùng:

File sdCard = Environment.getExternalStorageDirectory(); File directory = new File(sdCard.getAbsolutePath() + "/MyFiles"); directory.mkdirs(); File file = new File(directory, "textfile.txt"); FileOutputStream fOut = new FileOutputStream(file);

Và thay vì:

FileInputStream fIn = openFileInput("textfile.txt");

Ta dùng:

File sdCard = Environment.getExternalStorageDirectory(); File directory = new File (sdCard.getAbsolutePath() + "/MyFiles"); File file = new File(directory, "textfile.txt"); FileInputStream fIn = new FileInputStream(file); InputStreamReader isr = new InputStreamReader(fIn);

Page 137: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

137

M丑i thao tác 泳ng xử vẫn nh逢 tr逢運ng h嬰p tr逢噂c, ch雨 khác b鵜 trí l逢u trữ file trong cây th逢 m映c:

6.3. CSDL SQLite trong ứng dụng Android

Trong phần tr逢噂c ta đư tìm hiểu cách l逢u dữ liệu vào file và vào shared preferences. Tuy nhiên v噂i lo衣i dữ liệu quan hệ thì sử d映ng cơ s荏 dữ liệu quan hệ sẽ thuận tiện hơn r医t nhiều. Ví d映 ta cần l逢u trữ kết qu違 kiểm tra c栄a các sinh viên trong tr逢運ng h丑c, dùng cơ s荏 dữ liệu sẽ cho phép chúng ta truy v医n kết qu違 c栄a tập sinh viên nh医t đ鵜nh theo các tiêu chí khác nhau, việc thêm, b噂t, thay đổi thông tin thông qua các câu truy v医n SQL cũng dễ dàng hơn nhiều so v噂i việc thao tác trên file. Android sử d映ng hệ cơ s荏 dữ liệu SQLite. CSDL do m瓜t 泳ng d映ng t衣o ra sẽ ch雨 đ逢嬰c truy xu医t b荏i 泳ng d映ng đó, và file CSDL sẽ nằm trong b瓜 nh噂 trong dành riêng cho 泳ng d映ng (/data/data/{package-name}/databases/).

M瓜t thói quen tốt th逢運ng đ逢嬰c các lập trình viên kinh nghiệm sử d映ng là tập trung t医t c違 mã lệnh truy cập đến CSDL vào m瓜t l噂p riêng để thao tác trên CSDL tr荏 nên trong suốt v噂i môi tr逢運ng ngoài. Chúng ta sẽ t衣o tr逢噂c m瓜t l噂p nh逢 vậy, g丑i là DBAdapter.

Tạo lớp DBAdapter

Trong ví d映 này ta sẽ t衣o m瓜t CSDL tên là MyDB, ch泳a m瓜t b違ng duy nh医t là contacts, b違ng này ch泳a các tr逢運ng _id, name và email.

L噂p DBAdapter có mã nguồn nh逢 sau: import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; public class DBAdapter {

Page 138: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

138

static final String KEY_ROWID = "_id"; static final String KEY_NAME = "name"; static final String KEY_EMAIL = "email"; static final String TAG = "DBAdapter"; static final String DATABASE_NAME = "MyDB"; static final String DATABASE_TABLE = "contacts"; static final int DATABASE_VERSION = 2; static final String DATABASE_CREATE = "create table contacts (_id integer primary key autoincrement, " + "name text not null, email text not null);"; final Context context; DatabaseHelper DBHelper; SQLiteDatabase db; public DBAdapter(Context ctx) { this.context = ctx; DBHelper = new DatabaseHelper(context); } private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { try { db.execSQL(DATABASE_CREATE); } catch (SQLException e) { e.printStackTrace(); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS contacts"); onCreate(db); } } //---opens the database--- public DBAdapter open() throws SQLException { db = DBHelper.getWritableDatabase(); return this; } //---closes the database--- public void close() { DBHelper.close();

Page 139: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

139

} //---insert a contact into the database--- public long insertContact(String name, String email) { ContentValues initialValues = new ContentValues(); initialValues.put(KEY_NAME, name); initialValues.put(KEY_EMAIL, email); return db.insert(DATABASE_TABLE, null, initialValues); } //---deletes a particular contact--- public boolean deleteContact(long rowId) { return db.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0; } //---retrieves all the contacts--- public Cursor getAllContacts() { return db.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME, KEY_EMAIL}, null, null, null, null, null); } //---retrieves a particular contact--- public Cursor getContact(long rowId) throws SQLException { Cursor mCursor = db.query(true, DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME, KEY_EMAIL}, KEY_ROWID + "=" + rowId, null, null, null, null, null); if (mCursor != null) { mCursor.moveToFirst(); } return mCursor; } //---updates a contact--- public boolean updateContact(long rowId, String name, String email) { ContentValues args = new ContentValues(); args.put(KEY_NAME, name); args.put(KEY_EMAIL, email); return db.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0; }

}

Tr逢噂c tiên ta khai báo các hằng số: tên CSDL, tên b違n, tên các tr逢運ng để dễ dàng truy xu医t và thay đổi trong quá trình phát triển. Ngoài ra ta cũng khai báo phiên b違n (do ta tự đánh số) c栄a CSDL trong 泳ng d映ng và viết sẵn câu truy v医n dùng để t衣o CSDL:

static final String KEY_ROWID = "_id"; static final String KEY_NAME = "name"; static final String KEY_EMAIL = "email"; static final String TAG = "DBAdapter"; static final String DATABASE_NAME = "MyDB"; static final String DATABASE_TABLE = "contacts"; static final int DATABASE_VERSION = 2; static final String DATABASE_CREATE =

Page 140: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

140

"create table contacts (_id integer primary key autoincrement, " + "name text not null, email text not null);";

Ta cũng t衣o thêm m瓜t l噂p c映c b瓜 (l噂p DatabaseHelper 荏 trên) để tr嬰 giúp cho việc t衣o CSDL và nâng c医p c医u trúc khi có sự thay đổi trong các phiên b違n tiếp theo. L噂p này kế thừa từ l噂p SQLiteOpenHelper. Hàm dựng c栄a l噂p này sẽ g丑i về hàm dựng c栄a l噂p mẹ v噂i tên và phiên b違n CSDL c栄a 泳ng d映ng:

super(context, DATABASE_NAME, null, DATABASE_VERSION);

Ngoài ra trong l噂p này ta n衣p chồng 2 hàm:

- Hàm onCreate(): đ逢嬰c g丑i để kh荏i t衣o CSDL trong lần đầu tiên ch衣y 泳ng d映ng, trong

hàm này ta tiến hành thực thi câu lệnh t衣o CSDL 荏 trên (DATABASE_CREATE) - Hàm onUpgrade(): đ逢嬰c g丑i khi ta nâng c医p 泳ng d映ng và thay đổi giá tr鵜 c栄a phiên

b違n CSDL (DATABASE_VERSION) 荏 trên. Trong ví d映 荏 trên, khi có thay đổi phiên b違n này, ta xóa CSDL cũ và t衣o l衣i cái m噂i.

Ngoài ra ta cũng viết thêm các hàm để m荏 CSDL, t衣o m噂i b違n ghi, cập nhật b違n ghi, l医y t医t c違 b違n ghi, l医y b違n ghi theo id… (xem code 荏 trên).

Sau khi có l噂p DBAdapter này, việc truy xu医t CSDL tr荏 nên t逢ơng đối đơn gi違n, đo衣n mư d逢噂i đây minh h丑a các thao tác thêm, b噂t, truy v医n CSDL:

DBAdapter db = new DBAdapter(this); //--- thêm một bản ghi --- db.open(); long id = db.insertContact("Wei-Meng Lee", "[email protected]"); id = db.insertContact("Mary Jackson", "[email protected]"); db.close(); //-- lấy danh sách tất cả bản ghi --- db.open(); Cursor c = db.getAllContacts(); if (c.moveToFirst()) { do { DisplayContact(c); } while (c.moveToNext()); } db.close(); //--- lấy một bản ghi theo id --- db.open(); c = db.getContact(2); if (c.moveToFirst()) DisplayContact(c); else Toast.makeText(this, "No contact found", Toast.LENGTH_LONG).show(); db.close(); //--- cập nhật bản ghi --- db.open(); if (db.updateContact(1, "Wei-Meng Lee", "[email protected]")) Toast.makeText(this, "Update successful.", Toast.LENGTH_LONG).show(); else Toast.makeText(this, "Update failed.", Toast.LENGTH_LONG).show(); db.close();

Page 141: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

141

//--- xóa bản ghi --- db.open(); if (db.deleteContact(1)) Toast.makeText(this, "Delete successful.", Toast.LENGTH_LONG).show(); else Toast.makeText(this, "Delete failed.", Toast.LENGTH_LONG).show();

db.close();

Trong đó hàm DisplayContact(c)ch雨 đơn gi違n hiển th鵜 lên màn hình n瓜i dung b違n ghi d逢噂i d衣ng Toast:

public void DisplayContact(Cursor c) { Toast.makeText(this, "id: " + c.getString(0) + "\n" + "Name: " + c.getString(1) + "\n" + "Email: " + c.getString(2), Toast.LENGTH_LONG).show(); }

Ch衣y 泳ng d映ng và dùng trình duyệt file c栄a Emulator, ta có thể th医y file CSDL đ逢嬰c t衣o

ra trong th逢 m映c /data/data/{package-name}/databases/myDB:

Nếu ta l医y file này về máy tính và đ丑c nó bằng các phần mềm h厩 tr嬰 CSDL SQLite (nh逢

NaviCat) ta sẽ th医y đ逢嬰c n瓜i dung b違ng contacts bên trong.

Page 142: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

142

ChươngàΑ. Lập trình mạng với Android

Trong các 泳ng d映ng hiện đ衣i, nhu cầu giao tiếp giữa 泳ng d映ng v噂i thế gi噂i bên ngoài (Internet) hết s泳c phổ biến, từ việc l医y và cập nhật n瓜i dung trực tuyến (từ các web site, các web service), t逢ơng tác v噂i máy ch栄, cho đến lập trình socket để m荏 kết nối cố đ鵜nh đến 泳ng d映ng trên server.

Trong ch逢ơng này ta sẽ tìm hiểu cách th泳c t違i dữ liệu d衣ng nh鵜 phân cũng nh逢 d衣ng văn b違n từ máy ch栄 web thông qua giao th泳c HTTP, cũng nh逢 việc phân tích cú pháp dữ liệu nhận về từ d衣ng XML hoặc JSON để l医y ra thông tin cần thiết.

Việc lập trình socket cần thêm 泳ng d映ng phía server, nằm ngoài ph衣m vi c栄a giáo trình, nên sẽ không đ逢嬰c đề cập 荏 đây, b衣n đ丑c quan tâm có thể tự tìm hiểu thêm trong các tài liệu khác.

7.1. Sử dụng web services thông qua giao thức HTTP

Cách th泳c phổ biến nh医t để cập nhật dữ liệu trực tuyến là l医y dữ liệu từ trang web trên Internet thông qua giao th泳c HTTP. Sử d映ng giao th泳c này, ta có thể thực hiện r医t nhiều việc trao đổi dữ liệu v噂i thế gi噂i bên ngoài, từ việc l医y n瓜i dung trang web, t違i dữ liệu nh鵜 phân (file nh鵜 phân, 違nh…), t違i dữ liệu d衣ng văn b違n…

Về mặt network, các thao tác này là nh逢 nhau cho m丑i lo衣i dữ liệu t違i về, vì vậy tr逢噂c tiên ta t衣o m瓜t dự án khung cho các 泳ng d映ng sử d映ng tài nguyên m衣ng theo giao th泳c HTTP.

Tr逢噂c hết, ta cần yêu cầu quyền truy cập Internet cho 泳ng d映ng m瓜t cách t逢運ng mình trong file AndroidManifest.xml nh逢 sau:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="net.learn2develop.Networking" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="13" /> <uses-permission android:name="android.permission.INTERNET"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".NetworkingActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>

</manifest>

Sau đó, trong mư nguồn c栄a Activity chính, ta viết thêm m瓜t hàm để l医y dữ liệu từ trên m衣ng về qua giao th泳c HTTP. Kết qu違 c栄a việc l医y dữ liệu này sẽ cho ta m瓜t luồng nhập liệu

Page 143: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

143

(InputStream) để ta xử lý dữ liệu (việc l医y dữ liệu ra lo衣i gì – nh鵜 phân hay văn b違n sẽ do luồng nhập liệu này xử lý).

Mã nguồn c栄a Activity ban đầu sẽ nh逢 sau: public class NetworkingActivity extends Activity { private InputStream OpenHttpConnection(String urlString) throws IOException { InputStream in = null; int response = -1; URL url = new URL(urlString); URLConnection conn = url.openConnection(); if (!(conn instanceof HttpURLConnection)) throw new IOException("Not an HTTP connection"); try{ HttpURLConnection httpConn = (HttpURLConnection) conn; httpConn.setAllowUserInteraction(false); httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET"); httpConn.connect(); response = httpConn.getResponseCode(); if (response == HttpURLConnection.HTTP_OK) { in = httpConn.getInputStream(); } } catch (Exception ex) { Log.d("Networking", ex.getLocalizedMessage()); throw new IOException("Error connecting"); } return in; } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);

}

}

Hàm OpenHttpConnection 荏 trên nhận vào đ逢運ng link đến tài nguyên trên Internet,

thực hiện kết nối và tr違 dữ liệu về vào luồng nhập liệu (InputStream). Do việc làm việc v噂i tài nguyên m衣ng th逢運ng x違y ra l厩i (không kết nối đ逢嬰c, link không còn tồn t衣i...), toàn b瓜 đo衣n mã cho việc này nằm trong b瓜 xử lý nhận ngo衣i lệ try-catch để bắt các l厩i có thể x違y ra.

L逢u ý là việc kết nối đến máy ch栄 để l医y tài nguyên có thể kéo dài, tùy thu瓜c vào kích th逢噂c tài nguyên, tốc đ瓜 đ逢運ng truyền, kh違 năng xử lý c栄a thiết b鵜... Vì vậy hàm trên th逢運ng đ逢嬰c g丑i trong thread riêng để tránh việc khóa c泳ng giao diện ng逢運i dùng trong quá trình xử lý. Ta sẽ làm việc này trong các ví d映 c映 thể bên d逢噂i về việc t違i dữ liệu nh鵜 phân cũng nh逢 t違i dữ liệu văn b違n.

Page 144: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

144

7.2. Tải dữ liệu nhị phân thông qua HTTP

Trong phần này ta sẽ minh h丑a m瓜t tr逢運ng h嬰p t違i dữ liệu nh鵜 phân từ máy ch栄 web thông qua giao th泳c HTTP. Ta sẽ dùng 泳ng d映ng khung về sử d映ng tài nguyên qua HTTP 荏 trên để t違i m瓜t 違nh (違nh là dữ liệu nh鵜 phân) từ trên m衣ng về và hiển th鵜 bên trong Activity.

Tr逢噂c tiên ta thêm m瓜t đối t逢嬰ng ImageView vào file layout c栄a Activity để hiển th鵜 違nh khi đ逢嬰c t違i về:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" />

</LinearLayout>

Nh逢 đư nói 荏 trên, việc t違i tài nguyên từ m衣ng ph違i nằm trong thread riêng, khác v噂i thread vẽ giao diện 泳ng d映ng (UI thread). 雲 đây ta dùng AsyncTask cho việc này:

private Bitmap DownloadImage(String URL) { Bitmap bitmap = null; InputStream in = null; try { in = OpenHttpConnection(URL); bitmap = BitmapFactory.decodeStream(in); in.close(); } catch (IOException e1) { Log.d("NetworkingActivity", e1.getLocalizedMessage()); } return bitmap; } private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { protected Bitmap doInBackground(String... urls) { return DownloadImage(urls[0]); } protected void onPostExecute(Bitmap result) { ImageView img = (ImageView) findViewById(R.id.img); img.setImageBitmap(result); }

}

Hàm DownloadImage thực hiện t違i 違nh từ trên m衣ng về và l逢u vào m瓜t đối t逢嬰ng Bitmap (đối t逢嬰ng này sẵn sàng để đ逢a vào ImageView). Hàm này sử d映ng hàm OpenHttpConnection ta đư làm 荏 trên để l医y m瓜t luồng nhập liệu ch泳a dữ liệu 違nh này, sau đó dùng hàm tĩnh decodeStream c栄a l噂p BitmapFactory để gi違i mã luồng nhập liệu này và l逢u vào đối t逢嬰ng Bitmap cần thiết.

Page 145: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

145

Tuy nhiên hàm DownloadImage này cũng sẽ chiếm nhiều th運i gian (bằng th運i gian t違i 違nh về c栄a hàm OpenHttpConnection và th運i gian gi違i mã 違nh), vì vậy ta cần g丑i hàm này bên trong m瓜t thread khác. Trong ví d映 trên ta dùng AsyncTask cho việc này.

Để sử d映ng AsyncTask, ta cần n衣p chồng tối thiểu 2 hàm:

- doInBackground - hàm này đ逢嬰c thực hiện trong thread riêng, khi kết thúc hàm này,

nó sẽ tự đ瓜ng g丑i hàm onPostExecute trong UI thread. Đây là nơi ta sẽ thực hiện các thao tác tốn th運i gian.

- onPostExecute hàm này đ逢嬰c g丑i trong UI thread, sau khi công việc ngầm 荏 hàm trên đư kết thúc. Đây là nơi mình cập nhật l衣i UI từ dữ liệu đ逢嬰c t違i về.

Trong ví d映 trên, ta sẽ tiến hành t違i 違nh trong thread riêng (trong hàm doInBackground)

và tiến hành hiển th鵜 違nh m噂i đ逢嬰c t違i về trong hàm onPostExecute.

Cuối cùng, để tiến hành t違i 違nh, ta thêm dòng mã g丑i đến AsyncTask này trong hàm onCreate c栄a Activity:

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new DownloadImageTask().execute("http://www.mayoff.com/5-01cablecarDCP01934.jpg"); }

Ch衣y 泳ng d映ng trên điện tho衣i hoặc Android Emulator, ta sẽ th医y 違nh từ m衣ng sẽ đ逢嬰c hiển th鵜 trên màn hình (có thể ph違i ch運 m瓜t lúc nếu kết nối m衣ng không tốt) nh逢 hình minh h丑a bên d逢噂i:

Page 146: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

146

7.3. Tải dữ liệu dạng text thông qua HTTP

T逢ơng tự nh逢 việc t違i dữ liệu nh鵜 phân 荏 trên, trong nhiều tr逢運ng h嬰p ta cần t違i dữ liệu d衣ng văn b違n từ m衣ng (l医y dữ liệu từ các web service chẳng h衣n). Ta cũng sẽ thực hiện thao tác này trong thread riêng, sử d映ng AsyncTask và tr違 ra dữ liệu d衣ng String tr逢噂c khi hiển th鵜 lên màn hình (d衣ng Toast).

Đo衣n mã t違i và hiển dữ liệu văn b違n trong thread riêng nh逢 sau: private String DownloadText(String URL) { int BUFFER_SIZE = 2000; InputStream in = null; try { in = OpenHttpConnection(URL); } catch (IOException e) { Log.d("NetworkingActivity", e.getLocalizedMessage()); return ""; } InputStreamReader isr = new InputStreamReader(in); int charRead; String str = ""; char[] inputBuffer = new char[BUFFER_SIZE]; try { while ((charRead = isr.read(inputBuffer))>0) { //---convert the chars to a String--- String readString = String.copyValueOf(inputBuffer, 0, charRead); str += readString;

Page 147: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

147

inputBuffer = new char[BUFFER_SIZE]; } in.close(); } catch (IOException e) { Log.d("NetworkingActivity", e.getLocalizedMessage()); return ""; } return str; } private class DownloadTextTask extends AsyncTask<String, Void, String> { protected String doInBackground(String... urls) { return DownloadText(urls[0]); } @Override protected void onPostExecute(String result) { Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show(); }

}

Đo衣n mã trên ch雨 khác v噂i việc t違i 違nh trong phần tr逢噂c 荏 phần đ丑c dữ liệu từ luồng nhập liệu tr違 về. Trong tr逢運ng h嬰p dữ liệu văn b違n, ta dùng l噂p InputStreamReader và hàm read c栄a nó để d丑c lần l逢嬰t dữ liệu d衣ng char ra, sau đó gắn thêm dần vào string kết qu違.

Cuối cùng ta ch雨 cần g丑i AsyncTask m噂i t衣o ra này trong hàm onCreate c栄a Activity để xem kết qu違:

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //---download text--- new DownloadTextTask().execute( "http://iheartquotes.com/api/v1/random?max_characters=256&max_lines=10");

}

Ch衣y 泳ng d映ng, ta sẽ th医y dữ liệu từ web service trên đ逢嬰c in ra màn hình:

Page 148: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

148

7.4. Web service với dữ liệu XML

Trong phần trên ta đư tiến hành l医y dữ liệu văn b違n từ web service thông qua th泳c HTTP, tuy nhiên trong ví d映 tr逢噂c ta cũng th医y dữ liệu tr違 về có d衣ng XML. Đây là đ鵜nh d衣ng t逢ơng đối phổ biến c栄a các web service hiện nay (bên c衣nh JSON), và để có thể sử d映ng đ逢嬰c dữ liệu này trong 泳ng d映ng, ta cần phân tích cú pháp (parsing) c栄a dữ liệu XML này. Trong phần này ta sẽ xem xét cách th泳c ta phân tích tài liệu XML trong Android.

Trong ví d映 này, ta sẽ thực hiện tra nghĩa c栄a m瓜t từ tiếng anh qua web service tra từ điển trực tuyến c栄a aonaware. Để thực hiện tra từ, ta g丑i API nh逢 sau:

http://services.aonaware.com/DictService/DictService.asmx/Define?word={t ừ-cần-tra}

ví d映 để tra nghĩa c栄a từ “apple”, ta cần g丑i API nh逢 sau:

http://services.aonaware.com/DictService/DictService.asmx/Define?word=apple

Nếu b衣n m荏 link này vào trình duyệt web, ta sẽ th医y n瓜i dung web service này tr違 về d逢噂i d衣ng XML nh逢 sau:

Page 149: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

149

Nhiệm v映 c栄a chúng ra là viết code phân tích tài liệu XML trên để l医y ra phần nghĩa c栄a từ (trong thẻ WordDefinition) và hiển th鵜 lên màn hình.

Để thực hiện việc này, ta cũng cần khai báo m瓜t AsyncTask để tránh khóa c泳ng UI thread:

private String WordDefinition(String word) { InputStream in = null; String strDefinition = ""; try { in = OpenHttpConnection("http://services.aonaware.com/DictService/DictService.asmx/Define?word=" + word); Document doc = null; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; try { db = dbf.newDocumentBuilder(); doc = db.parse(in); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) {

Page 150: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

150

// TODO Auto-generated catch block e.printStackTrace(); } doc.getDocumentElement().normalize(); // ---retrieve all the <Definition> elements--- NodeList definitionElements = doc .getElementsByTagName("Definition"); // ---iterate through each <Definition> elements--- for (int i = 0; i < definitionElements.getLength(); i++) { Node itemNode = definitionElements.item(i); if (itemNode.getNodeType() == Node.ELEMENT_NODE) { // ---convert the Definition node into an Element--- Element definitionElement = (Element) itemNode; // ---get all the <WordDefinition> elements under // the <Definition> element--- NodeList wordDefinitionElements = (definitionElement) .getElementsByTagName("WordDefinition"); strDefinition = ""; // ---iterate through each <WordDefinition> elements--- for (int j = 0; j < wordDefinitionElements.getLength(); j++) { // ---convert a <WordDefinition> node into an Element--- Element wordDefinitionElement = (Element) wordDefinitionElements .item(j); // ---get all the child nodes under the // <WordDefinition> element--- NodeList textNodes = ((Node) wordDefinitionElement) .getChildNodes(); strDefinition += ((Node) textNodes.item(0)) .getNodeValue() + ". \n"; } } } } catch (IOException e1) { Log.d("NetworkingActivity", e1.getLocalizedMessage()); } // ---return the definitions of the word--- return strDefinition; } private class AccessWebServiceTask extends AsyncTask<String, Void, String> { protected String doInBackground(String... urls) { return WordDefinition(urls[0]); } protected void onPostExecute(String result) { Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show(); }

}

Page 151: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

151

Trong đó hàm WordDefinition sẽ t違i n瓜i dung c栄a webservice và tiến hành phân tích cú pháp tài liệu XML tr違 về. Công việc này tốn th運i gian nên ta cần làm trong thread riêng, do đó ta cần viết thêm l噂p AccessWebServiceTask nh逢 荏 trên.

Việc cuối cùng là g丑i AsyncTask này trong hàm onCreate c栄a Activity:

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // ---access a Web Service using GET--- new AccessWebServiceTask().execute("apple");

}

永ng d映ng khi ch衣y sẽ có d衣ng nh逢 minh h丑a trong hình bên d逢噂i.

Ta sẽ đi chi tiết hơn m瓜t chút về hàm WordDefinition 荏 trên. Tr逢噂c hết ta vẫn sử d映ng hàm OpenHttpConnection đư viết 荏 trên để l医y thông tin từ m衣ng và đ逢a vào luồng nhập liệu:

in = OpenHttpConnection(http://services.aonaware.com/DictService/DictService.asmx/Define?word= + word);

Sau đó ta dùng l噂p javax.xml.parsers.DocumentBuilder để phân tích tài liệu XML trong luồng nhập liệu này thành cây đối t逢嬰ng tài liệu (DOM – Document object model):

Document doc = null;

Page 152: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

152

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; db = dbf.newDocumentBuilder(); doc = db.parse(in);

doc.getDocumentElement().normalize();

L逢u ý: trong đo衣n code trên ta b臼 qua phần bắt ngo衣i lệ try-catch cho dễ quan sát.

Sau khi parsing nh逢 trên, ta thu đ逢嬰c m瓜t cây đối t逢嬰ng trong tr逢運ng “doc” (đối t逢嬰ng c栄a l噂p org.w3c.dom.Document). Ta có thể duyệt cây tài liệu này để l医y ra các tr逢運ng mong muốn, c映 thể:

Để l医y danh sách các node “Definitions”:

NodeList definitionElements = doc.getElementsByTagName("Definition");

Sau đó duyệt từng phần tử trong danh sách node trên để l医y ra WordDefinition c栄a từng node:

NodeList wordDefinitionElements = (definitionElement).getElementsByTagName("WordDefinition");

Việc duyệt cây DOM để trích xu医t ra dữ liệu cần thiết là công việc khá điển hình và phổ biến, b衣n đ丑c quan tâm có thể tham kh違o chi tiết hơn t衣i các tài liệu khác.

7.5. Web service với dữ liệu JSON

Ngoài XML, m瓜t đinh d衣ng dữ liệu văn b違n đ逢嬰c sử d映ng r医t phổ biến hiện nay trong các web service là JSON (JavaScript Object Notation).

So v噂i XML, đ鵜nh d衣ng JSON có m瓜t số 逢u điểm:

- Json có đ瓜 nén dữ liệu tốt hơn: cùng m瓜t dữ liệu, XML tốn nhiều dung l逢嬰ng hơn để đóng gói, do các thẻ (tag) trong XML có đ瓜 dài nh医t đ鵜nh. Dung l逢噂ng l噂n 違nh h逢荏ng x医u đến tốc đ瓜 truyền t違i cũng nh逢 kh違 năng l逢u trữ tài liệu.

- Xử lý (phân tích) tài liệu XML tốn kém hơn so v噂i JSON c違 về b瓜 nhỡ lẫn tài nguyên CPU.

Ví d映 về m瓜t tài liệu JSON ta sẽ thử phân tích trong phần tiếp theo có thể l医y đ逢嬰c qua đ逢運ng link sau: http://extjs.org.cn/extjs/examples/grid/survey.html

Nếu ta m荏 link này bằng trình duyệt, ta sẽ quan sát đ逢嬰c n瓜i dung nh逢 hình bên d逢噂i.

Page 153: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

153

Ví d映 d逢噂i đây sẽ phân tích tài liệu JSON 荏 trên và in ra màn hình appeId và inputTime cho từng đối t逢嬰ng trong danh sách phân tích đ逢嬰c.

Toàn b瓜 mã nguồn c栄a Activity cho ví d映 này nh逢 sau:

package net.learn2develop.JSON; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient;

Page 154: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

154

import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONObject; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.widget.Toast; public class JSONActivity extends Activity { public String readJSONFeed(String URL) { StringBuilder stringBuilder = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(URL); try { HttpResponse response = client.execute(httpGet); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); BufferedReader reader = new BufferedReader( new InputStreamReader(content)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line); } } else { Log.e("JSON", "Failed to download file"); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return stringBuilder.toString(); } private class ReadJSONFeedTask extends AsyncTask<String, Void, String> { protected String doInBackground(String... urls) { return readJSONFeed(urls[0]); } protected void onPostExecute(String result) { try { JSONArray jsonArray = new JSONArray(result); Log.i("JSON", "Number of surveys in feed: " + jsonArray.length()); //---print out the content of the json feed--- for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); Toast.makeText(getBaseContext(), jsonObject.getString("appeId") + " - " + jsonObject.getString("inputTime"), Toast.LENGTH_SHORT).show(); } } catch (Exception e) {

Page 155: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

155

e.printStackTrace(); } } } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new ReadJSONFeedTask().execute("http://extjs.org.cn/extjs/examples/grid/survey.html"); }

}

L逢u ý: trong mư nguồn trên, ta dùng l噂p org.apache.http.client.HttpClient để l医y

n瓜i dung web service thông qua HTTP thay cho java.net.HttpURLConnection. B衣n đ丑c quan tâm có thể tự tìm hiểu về l噂p này 荏 các tài liệu khác, 荏 đây ta ch雨 quan tâm đến đo衣n mã nguồn phân tích tài liệu JSON.

Để phân tích tài liệu JSON và đ逢a vào m瓜t m違ng các JSONObject, ta ch雨 cần g丑i m瓜t lệnh đơn gi違n:

JSONArray jsonArray = new JSONArray(result);

V噂i result là dữ liệu văn b違n thô (d衣ng String) l医y đ逢嬰c từ webservice. Sau đó tiền hành

duyệt lần l逢嬰t các JSONObject thu đ逢嬰c bằng hàm getJSONObject(i)và l医y n瓜i dung c栄a từng

tr逢運ng dữ liệu trong m厩i đối t逢嬰ng JSON bằng ph逢ơng th泳c getString c栄a l噂p JSONObject.

for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); Toast.makeText(getBaseContext(), jsonObject.getString("appeId") +

" - " + jsonObject.getString("inputTime"), Toast.LENGTH_SHORT).show();

}

Page 156: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

156

Chươngà8. Google Play Store và việc phân phối ứng dụng

Nh逢 vậy chúng ta đư h丑c đ逢嬰c r医t nhiều th泳 xuyên suốt giáo trình giúp chúng ta có thể phát triển m瓜t 泳ng d映ng Android ch医t l逢嬰ng. Tuy nhiên để 泳ng d映ng có thể đ逢嬰c cài đặt lên thiết b鵜 c栄a ng逢運i dùng, ta cần đóng gói và phân phối. Trong ch逢ơng này chúng ta sẽ tìm hiểu cách th泳c đóng gói 泳ng d映ng Android và phân phối đến máy ng逢運i dùng qua các cách khác nhau, cũng nh逢 tìm hiểu cách phân phối 泳ng d映ng Android lên ch嬰 泳ng d映ng chính hãng c栄a Google là Google Play Store.

8.1. Chuẩn bị ứng dụngàtrước khi phân phối

Google đ逢a ra quy trình t逢ơng đối đơn gi違n giúp ng逢運i dùng đóng gói và đ逢a 泳ng d映ng lên Google Play Store để phân phối đến ng逢運i dùng. Các b逢噂c nh逢 sau:

- Xu医t 泳ng d映ng ra file .apk (Android Package)

- T衣o ch泳ng thực ký điện tử và tiến hành ký 泳ng d映ng (file apk) trên theo ch泳ng thực m噂i đ逢嬰c t衣o ra

- Xu医t b違n 泳ng d映ng đư đ逢嬰c ký này. Có nhiều cách xu医t b違n nh逢: cài trực tiếp lên thiết b鵜, đ逢a lên web site, hoặc phân phối lên các ch嬰 泳ng d映ng (c違 chính hãng lẫn không chính hãng).

Đ=nhàsố phiên bản phần mềm

Phiên b違n phần mềm đ逢嬰c đánh số trong file AndroidManifest.xml, d逢噂i hai thu瓜c tính là

android:versionCode và android:versionName:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="net.learn2develop.JSON" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="13" /> <uses-permission android:name="android.permission.INTERNET"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > … </application>

</manifest>

Trong đó versionCode là số hiệu phiên b違n, có kiểu số nguyên, dùng cho hệ thống để phân biệt các phiên b違n c栄a 泳ng d映ng đ逢嬰c cài đăt. M厩i khi b衣n nâng c医p phiên b違n c栄a 泳ng d映ng, b衣n cần thay đổi (tăng lên) số này tr逢噂c khi phân phối. Còn tham số versionName là tên c栄a phiên b違n, thông số này không đ逢嬰c dùng b荏i hệ thống, mà ch雨 là tên phiên b違n ng逢運i dùng sẽ nhìn th医y khi xu医t b違n lên các ch嬰 泳ng d映ng. VersionName có kiểu chu厩i và có thể đặt tùy ý, tuy nhiên đ鵜nh dàng th逢運ng đ逢嬰c dùng là <major>.<minor>.<point>, 荏 đó <major> là số hiệu phiên b違n chính, <minor> là phiên b違n ph映, <point> là số hiệu cập nhật nh臼 trong phiên b違n ph映, ví d映 “1.0.1”, “2.1.0”…

Page 157: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

157

Trong nhiều tr逢運ng h嬰p, ta cần l医y số hiệu phiên b違n 泳ng d映ng hiện t衣i lúc ch衣y ch逢ơng trình, khi đó, ta dùng l医y thông tin PackageInfo nh逢 sau:

PackageManager pm = getPackageManager(); try { //---get the package info--- PackageInfo pi = pm.getPackageInfo("net.learn2develop.LBS", 0); //---display the versioncode--- Toast.makeText(getBaseContext(), "VersionCode: " +Integer.toString(pi.versionCode), Toast.LENGTH_SHORT).show(); } catch (NameNotFoundException e) { e.printStackTrace();

}

Ngoài ra để 泳ng d映ng có thể đ逢嬰c phân phối trên ch嬰 泳ng d映ng, b衣n cần ch雨 ra icon và tiêu đề c栄a 泳ng d映ng để hiển th鵜 trong danh sách 泳ng d映ng, để làm điều này, ta cần đặt giá tr鵜 cho

tham số android:icon và android:label c栄a thẻ <application> (xem ví d映 trên).

Chứng thực số cho ứng dụng Android

T医t c違 泳ng d映ng Android đều ph違i đ逢嬰c ký theo m瓜t ch泳ng thực số tr逢噂c khi có thể cài đặt lên thiết b鵜 hoặc Android Emulator. Không nh逢 m瓜t số hệ nền khác yêu cầu b衣n ph違i mua ch泳ng ch雨 số từ m瓜t hãng chuyên cung c医p ch泳ng thực, hệ thống Android cho phép chúng ta tự sinh ra ch泳ng thực số để ký 泳ng d映ng. Eclipse và ADT cũng cung c医p sẵn công c映 giúp ta t衣o ra ch泳ng thực này m瓜t cách rât trực quan và dễ dàng.

Trong quá trình b衣n phát triển 泳ng d映ng, b衣n vẫn có thể ch衣y 泳ng d映ng c栄a mình trên thiết b鵜 hoặc trình gi違 lập. Đó là do Eclipse+ADT đư ký sẵn 泳ng d映ng c栄a b衣n theo m瓜t ch泳ng thực mặc đ鵜nh tr逢噂c khi chuyển 泳ng d映ng lên thiết b鵜, ch泳ng thực mặc đ鵜nh này ch泳a trong file debug.keystore:

Page 158: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

158

Tuy nhiên ch泳ng thực này ch雨 dùng trong quá trình phát triển, tr逢噂c khi b衣n xu医t b違n 泳ng d映ng, b衣n cần ký 泳ng d映ng theo m瓜t ch泳ng thực khác. Phần d逢噂i đây mô t違 quá trình sinh ch泳ng thực số và đóng gói 泳ng d映ng theo ch泳ng thực đó.

Để xu医t b違n 泳ng d映ng, từ trình đơn File c栄a Eclipse, ch丑n Export..., trong cửa sổ m荏 ra, ch丑n Export Android Application, b医m Next:

Page 159: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

159

Trong màn hình tiếp theo, ch丑n tên dự án muốn xu医t b違n:

Page 160: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

160

Tiếp đó ta cần ch雨 ra v鵜 trí c栄a file ch泳a ch泳ng thực số cần dùng để ký 泳ng d映ng và nhập vào mật khẩu c栄a ch泳ng thực này (mật khẩu này ta đặt lúc t衣o ch泳ng thực số). Trong tr逢運ng h嬰p ch逢a có ch泳ng thực số, ta ch丑n “Create new keystore” để t衣o m噂i:

Trong tr逢運ng h嬰p t衣o m噂i keystore, ta cần nhập thông tin để t衣o ra m瓜t key (dùng để ký 泳ng d映ng), ví d映 ta điền thông tin nh逢 bên d逢噂i:

Page 161: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

161

Cuối cùng ta nhập tên file apk cần xu医t ra và b医m Finish:

Khi quá trình kết thúc, ta sẽ thu đ逢嬰c 泳ng d映ng file apk đư đóng gói sẵn sang để phân phối.

Page 162: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

162

8.2. Phân phối ứng dụng

Sau khi đư đóng gói và ký theo ch泳ng thực số cần thiết, file apk đư sẵn sàng để đ逢嬰c phân phối lên các ch嬰 泳ng d映ng. Có nhiều cách để có thể phân phối 泳ng d映ng đến ng逢運i dùng nh逢:

- Cài đặt trực tiếp lên thiết b鵜 đầu cuối thông qua công c映 adb.exe - Đặt file cài đặt (.apk) lên web server và phân phối đ逢運ng link t違i xuống cho ng逢運i

dùng - Phân phối 泳ng d映ng trên các ch嬰 泳ng d映ng: điển hình là Google Play Store

Sử dụng công cụ adb

Công c映 adb có thể đ逢嬰c sử d映ng để cài trực tiếp 泳ng d映ng lên thiết b鵜 đầu cuối. Để dùng đ逢嬰c công c映 này, ta cần:

- Kết nối thiết b鵜 v噂i máy tính thông qua cổng USB - Cài đặt driver cho thiết b鵜 (nếu ch逢a có) - Bật tùy ch丑n “USB debugging” trong “Developer options” c栄a m映c c医u hình

(Settings) trên thiết b鵜 Android

Để kiểm tra thiết b鵜 đư đ逢嬰c kết nối thành công v噂i máy tính ch逢a, ta có thể gõ lệnh “adb devices: từ màn hình console (cmd.exe):

Hình trên cho th医y có 01 thiết b鵜 v噂i mư “05863c50” đang đ逢嬰c kết nối v噂i máy tính.

L逢u ý: công c映 adb.exe nằm trong th逢 m映c platform-tools c栄a Android SDK.

Khi thiêt b鵜 đư đ逢嬰c kết nối, ta có thể dùng lệnh “adb install <apk filee>” để cài đặt 泳ng d映ng lên thiết b鵜:

Chữ “success” báo hiệu quá trình cài đặt đư thành công, ta sẽ th医y 泳ng d映ng xu医t hiện trong danh sách 泳ng d映ng c栄a thiết b鵜 và sẵn sàng ho衣t đ瓜ng.

Phân phối trên web server

Cách th泳 2 là đ逢a 泳ng d映ng c栄a b衣n lên m瓜t web server và phân phối link t違i (ví d映: http://myserver.com/app/LBS.apk ) đến ng逢運i dùng. Ng逢運i dùng ch雨 cần b医m vào link này từ thiết b鵜 android c栄a mình, hoặc gõ đ逢運ng link này vào thanh đ鵜a ch雨 c栄a trình duyệt web trên thiết b鵜, 泳ng d映ng sẽ tự đ瓜ng đ逢嬰c t違i về.

Page 163: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

163

Sau khi t違i xong, b医m ch丑n file vừa t違i để thực hiện cài đặt, tuy nhiên để có thể cài đặt 泳ng d映ng từ nguồn này (không ph違i từ Google Play Store), b衣n cần bật tùy ch丑n “Unknown source” trong phần Settings > Security c栄a thiết b鵜:

Phân phối trên Google Play Store

Kênh phân phối chính thống và tiềm năng nh医t cho 泳ng d映ng Android là ch嬰 泳ng d映ng Google Play Store (cửa hàng Play) c栄a Google. Để có thể phân phối 泳ng d映ng trên cửa hàng Play, ta cần đăng ký tài kho違n lập trình viên Google Android. Lệ phí lập tài kho違n này là $25 tr丑n đ運i tài kho違n. B衣n có thể thanh toán kho違n tiền này bằng thẻ thanh toán hoặc thẻ tín d映ng quốc tế (Visa, Master, America Express, Discovery…)

Để đăng ký tài kho違n lập trình viên, ta truy cập https://play.google.com/apps/publish/signup/ và đăng nhập bằng tài kho違n google c栄a b衣n (nếu ch逢a có tài kho違n google, b衣n cần t衣o m噂i, miễn phí):

Page 164: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

164

B医m ch医p nhận điều kho違n và tiếp t映c (Continue to payment). Trong màn hình tiếp theo, nhập thông tin thẻ quốc tế để thanh toán và b医m “Đồng ý và tiếp t映c”:

Page 165: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

165

Nếu thẻ c栄a b衣n đ逢嬰c ch医p nhận, Google sẽ đ逢a tài kho違n c栄a b衣n vào tr衣ng thái ch運 kiểm tra, sau kho違ng vài ngày sẽ có ph違n hồi từ Google ch医p nhận tài kho違n c栄a b衣n hay không. Trong tr逢運ng h嬰p không đ逢嬰c ch医p nhận, Google sẽ yêu cầu b衣n gửi thêm tài liệu ch泳ng thực thông tin cá nhân và tài kho違n ngân hàng c栄a b衣n.

Trong th運i gian ch運 đ嬰i Google kiểm tra tr衣ng thái thanh toán, b衣n vẫn có thể đ逢a 泳ng d映ng lên server c栄a Google, tuy nhiên ch逢a thể phân phối đến ng逢運i dùng.

Giao diện c栄a Developer console sau khi đăng ký thành công sẽ có d衣ng nh逢 sau:

Page 166: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

166

Tài kho違n trên đư có m瓜t 泳ng d映ng đang đ逢嬰c phân phối đến ng逢運i dùng, 泳ng d映ng này hiện đang có 2071 ng逢運i dùng trên tổng số 15180 l逢嬰t t違i, có 93 ng逢運i bình ch丑n và điểm trung bình là 3.98/5 sao!!!!

Để phân phối 泳ng d映ng khác, ta b医m vào nút “+ Add new application” phía trên c栄a trang (nút đ逢嬰c bôi vàng trên hình).

B衣n cần cung c医p đầy đ栄 thông tin yêu cầu về 泳ng d映ng tr逢噂c khi có thể phân phối đến ng逢運i dùng, bao gồm các thông tin:

T違i file 泳ng d映ng (apk) c栄a b衣n lên hệ thống:

Page 167: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

167

Cung c医p tiêu đề (tên 泳ng d映ng), mô t違, t違i lên file icon l噂n (512x512px) và ít nh医t 02 hình ch映p màn hình c栄a 泳ng d映ng, ch丑n lo衣i 泳ng d映ng, c医u hình website và email h厩 tr嬰…:

Page 168: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

168

Đặt giá bán 泳ng d映ng (hiện t衣i 荏 Việt Nam ta ch雨 đ逢嬰c phép đăng 泳ng d映ng miễn phí) và các quốc gia muốn phân phối 泳ng d映ng:

Cuối cùng b医m “Save and publish”, 泳ng d映ng c栄a b衣n sẽ bắt đầu đ逢嬰c phân phối trên hệ thống Google Play. Chú ý: cần ph違i m医t đến vài tiếng đến vài ngày để 泳ng d映ng có thể v逢嬰t qua đ逢嬰c hệ thông kiểm tra c栄a Google và phân phối khắp m衣ng CDN c栄a Google.

Sauk hi hoàn t医t các b逢噂c nh逢 trên ta đư hoàn thành việc phát triển m瓜t 泳ng d映ng cho hệ điều hành Android và phân phối đến ng逢運i dùng. B衣n có thể th逢運ng xuyên ghé thăm trang dành cho developer này để xem các thống kê khác nhau liên quan đến việc cài đặt và sử d映ng 泳ng d映ng c栄a mình nh逢: số l逢嬰t cài đặt/gỡ b臼 theo ngày, t雨 lệ các phiên b違n Android đang dùng, các l厩i crash 泳ng d映ng, đánh giá, ph違n hồi c栄a ng逢運i dùng…, hình d逢噂i đây minh h丑a m瓜t trong những màn hình thống kê nh逢 vậy. Phần này cũng kết thúc giáo trình “Lập trình cho thiết b鵜 di đ瓜ng” c栄a chúng ta!.

Page 169: Lập trình Androi

Phát triển ứng dụng cho thiết bị di động Hồ Thị Thảo Trang

169