You are on page 1of 267

TRUNG TÂM TIN HỌC - ĐẠI HỌC KHOA HỌC TỰ NHIÊN

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH

CHƯƠNG TRÌNH ĐÀO TẠO

LẬP TRÌNH VIÊN CHUYÊN NGHIỆP TRÊN THIẾT BỊ DI ĐỘNG

TÀI LIỆU

LẬP TRÌNH THIẾT BỊ DI ĐỘNG TRÊN


ANDROID
MODULE 02:
KIẾN TRÚC VÀ XÂY DỰNG ỨNG DỤNG ANDROID

Tháng 06/2015
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 1
TỔNG QUAN VỀ LẬP TRÌNH ANDROID
VÀ MÔI TRƯỜNG PHÁT TRIỂN

1. TỔNG QUAN ANDROID


1.1. Hệ điều hành Android
- Năm 2003, Android Inc. được thành lập bởi Andy Rubin, Rich Miner, Nick Sears và
Chris White tại California.
- Năm 2005, Google mua lại Android Inc và bắt đầu nuôi ý tưởng tự sản xuất điện thoại
di động.
- Năm 2007, tổ chức OHA (Open Handset Alliance) được thành lập với hơn 80 công ty
trong lĩnh vực kỹ thuật điện tử bao gồm các công ty chuyên về phần cứng, phân phối
thiết bị di động đến các công ty phần mềm, sản xuất chất bán dẫn… Có thể kể đến một
số công ty nổi tiếng như Samsung, Motorola, LG, HTC, T-Mobile, Vodafone, ARM và
Qualcomm…
- Năm 2008, Google ra mắt chiếc di động đầu tiên đồng thời open source bản SDK
(Software Development Kit) phiên bản 1.0.
- Năm 2010, Google khởi đầu dòng thiết bị Nexus với thiết bị đầu tiên của HTC là Nexus
One.
- Năm 2013, ra mắt loạt thiết bị phiên bản GPE.
- Năm 2014, Google công báo Android Wear, hệ điều hành dành cho các thiết bị đeo
được.
- Các phiên bản của hệ điều hành Android:

Hình 1.1. Các phiên bản hệ điều hành Android.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |1


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Thời gian
Phiên bản API Đặc điểm nổi bật
phát hành
Thanh thông báo kéo từ trên xuống, màn hình
Android 1.0 1 10/2008 chính phong phú, tích hợp chặt chẽ với Gmail, giao
diện đơn giản nhưng khá đẹp mắt thời bấy giờ.
Tải và cài đặt bản cập nhật ngay trên thiết bị,
Android 1.1 2 02/2009 không cần kết nối với máy tính (phương thức Over
The Air).
Là bản Android đầu tiên được Google gọi tên theo
các món đồ ăn với chữ cái bắt đầu được xếp theo
thứ tự alphabet. Với các tính năng: bàn phím ảo,
Android 1.5 mở rộng khả năng cho widget – khả năng tùy biến
3 05/2009
Cupcake giao diện của Android được đẩy mạnh, cải tiến
clipboard, có khả năng quay phim, cho phép tải
ảnh, video lên YouTube, truy cập danh bạ trong
Google Talk,…
Một vài điểm trong giao diện được cải thiện, hỗ trợ
mạng CDMA, hỗ trợ các thành phần đồ họa độc
lập với độ phân giải, tính năng Quick Search Box –
Android 1.5
4 09/2009 tìm kiếm tất cả mọi thứ chỉ trong một hộp tìm
Donut
kiếm, Android Market – hiển thị các ứng dụng
miễn phí và trả phí hàng đầu. Camera được cải
thiện, tích hợp trình xem ảnh tốt hơn.
Hỗ trợ nhiều tài khoản người dùng, tính năng
Quick Contact, cải tiến bàn phím ảo. Trình duyệt
Android 2.0 – mới: hỗ trợ HTML5, phát video ở chế độ toàn màn
11/2009
Android 2.0.1 5, 6 hình, hộp địa chỉ kết hợp với thanh tìm kiếm, cho
- 12/2009
Eclair phép phóng to, thu nhỏ bằng cách chạm tay vào
màn hình. Giao diện đẹp, sang trọng và gọn gàng
hơn trước.
Android 2.1 Hỗ trợ Live Wallpaper, chuyển giọng nói thành
7 01/2010
Eclair văn bản và một màn hình khóa mới.
Từ 3 màn hình chính tăng lên thành 5 màn hình.
Dãy nút kích hoạt nhanh chế độ gọi điện, web và
Android 2.2 App Drawer xuất hiện. Khả năng hiển thị hình ảnh
8 06/2010
Froyo 3D. Tính năng trạm phát Wifi xuất hiện. Hỗ trợ
duyệt web với Flash. Tính năng di chuyển một
phần ứng dụng từ bộ nhớ máy sang thẻ nhớ.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |2


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Có hai thanh chặn khi chọn văn bản. Bàn phím


được cải thiện đẹp hơn và dễ sử dụng hơn. Xuất
Android 2.3.3 –
11/2010 hiện công cụ quản lý pin và ứng dụng. Hỗ trợ máy
Android 2.3.7 9, 10
– 02/2011 ảnh trước. Cung cấp nhiều tính năng mới, tập trung
Gingerbread
vào việc phát triển game, đa phương tiện và
phương thức truyền thông mới.
Phiên bản này dành riêng cho máy tính bảng. Sử
dụng màu đen và màu xanh dương làm tông màu
chủ đạo. Homescreen và widget được thiết kế lại.
Android 3.0 – Không còn nút nhấn vật lý. Cải thiện đa nhiệm –
11, 02/2011
Android 3.1 – xuất hiện nút Recent Apps giúp chuyển đổi ứng
12, – 05/2011
Android 3.2 dụng dễ dàng và nhanh chóng. Thanh Action Bar
13 – 06/2011
Honeycomb xuất hiện.
Phiên bản Android 3.1 và 3.2 sửa lỗi và thêm vài
tính năng mới như thay đổi kích thước widget ngay
trên homescreen, hỗ trợ thẻ SD,...
Hỗ trợ bộ font Roboto. Hệ thống thông báo
(Noitification) được làm mới hoàn toàn, đẹp và
Android 4.0 –
thuận tiện hơn. Bàn phím tiếp tục được cải thiện.
Android 4.0.3 14, 10/2011
Hệ điều hành dành cho smartphone và cho máy
Ice Cream 15 – 12/2011
tính bảng được hợp nhất làm một. Duyệt web
Sandwich
nhanh hơn, tối ưu hóa hiệu suất hoạt động của thiết
bị, kéo dài thời gian dùng pin...
Màn hình Lockscreen - vòng trượt mở khóa dùng
kích hoạt 3 tính năng khác nhau : mở khóa máy, sử
dụng camera, kích hoạch Google Now (Android
Android 4.1 – 4.0 có 2 tính năng: mở khóa máy, sử dụng camera).
16 07/2012
Jelly Bean Khả năng tìm kiếm bằng giọng nói, kết quả trả về
được thiết kế theo dạng thẻ đồ họa, thông minh
hơn, trực quan hơn. Project butter giúp mang lại độ
mượt mà chưa từng có cho Android.
Hỗ trợ Miracast - một chuẩn chia sẻ nội dung số
thông qua kết nối Wi-Fi , bàn phím có thể nhập
Android 4.2 liệu bằng cách vẽ các đường nét từ kí tự này đến kí
17 11/2012
Jelly Bean tự khác, chế độ chụp ảnh toàn cảnh Photo Sphere.
Hỗ trợ nhiều tài khoản người dùng trên máy tính
bảng.
Android 4.3 18 07/2013 Hỗ trợ kết nối Bluetooth Smart, bộ API OpenGL

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |3


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Jelly Bean ES 3.0, bổ sung tính năng sử dụng Wi-Fi để định vị


ngay cả khi người dùng tắt kết nối này. Hỗ trợ tính
năng Restricted Profile, Notification Access,…
Hiệu suất được cải tiến: RAM 512 MB cũng có thể
chạy KitKat, hiệu năng cao gấp 1,6 lần phiên bản
trước . Giao diện nhìn chung được làm phẳng hơn.
Android 4.4 Kết hợp dịch vụ tìm kiếm Google Search cho phép
KitKat 19, dò và tự động liên kết các danh bạ có sẵn trên
10/2013
Android 4.4W 20 internet vào số điện thoại mới. Gộp chung Text
KitKat Watch Messages và Hangouts. Bổ sung các biểu tượng
Emoji vào bàn phím mặc định. Tính năng Screen
Recording cho phép ghi các hoạt động diễn ra trên
màn hình thành các đoạn video MP4.
Hình ảnh phẳng hơn, nhiều màu sắc hơn so với
trước đây. Xuất hiện chức năng “T action”: tùy vào
động tác lắc máy sẽ tương ứng với chức năng cụ
Android 5.0
thể. Tính năng tự động trả lời điện thoại khi đưa
Lollipop 21,
10/2014 máy lên tai hay tự động giảm nhạc chuông khi
Android 5.1 22
nhấc máy lên khỏi mặt bàn… Người dùng có thể
Lollipop
nhận và trả lời các thông báo bao gồm email, tin
nhắn, cuộc gọi nhỡ ngay ngoài màn hình khoá. Tiết
kiệm pin và bảo mật hơn.
Thiết kế lại quyền hạn của các ứng dụng. Trang bị
cho trình duyệt Chrome tính năng mới với tên gọi
Chrome Custom Tabs, cho phép các nhà phát triển
có thể chèn trực tiếp nội dung trang web đầy đủ
Android M
Công bố ngày vào các ứng dụng. Cho phép mở trực tiếp nội dung
(Chưa có tên
28/05/2015 bằng các ứng dụng liên quan. Trang bị hệ thống
chính thức)
thanh toán mới trên di động, với tên gọi Android
Pay. Cải thiện độ ổn định, hiệu suất cũng như khả
năng tiết kiệm pin. Hỗ trợ cổng kết nối USB Type-
C thế hệ mới.
Bảng 1-1. Các phiên bản hệ điều hành Android.

1.2. Tại sao lập trình trên Android


1.2.1. Xu thế phát triển công nghệ di động
- Theo nhận định của nhiều chuyên gia công nghệ từ các hãng công nghệ hàng đầu như
Microsoft, Google, IBM, … Ba xu hướng tất trên toàn cầu hiện nay là: Social and

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |4


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Security (mạng xã hội và bảo mật), Mobility (công nghệ di động), Analytics Big Data
(phân tích dữ liệu lớn), Cloud (Điện toán đám mây).
- Trên thế giới:
o Tháng 01/2014, trang WeAreSocial đã đưa ra báo cáo về “Bối cảnh dữ liệu toàn
cầu” với những chỉ số phát triển rất đang kinh ngạc của Thế Giới Số. Cụ thể số
liệu thống kê của WeAreSocial cho thấy:
 Số lượng đăng kí sử dụng di động đang hoạt động vào khoảng 93% của
dân số thế giới.
 Tỉ lệ người kết nối Internet toàn cầu đạt 35%, tương đương 2,5 tỉ người.
 Các kênh Mạng xã hội tiếp tục phát triển mạnh mẽ trong 12 tháng qua,
khi đạt tỉ lệ thâm nhập người dùng là 26%.
 Hơn 4 tỉ người trên khắp thế giới hiện đang sở hữu ít nhất một chiếc điện
thoại di động.

Hình 1.2. Bối cảnh dữ liệu toàn cầu - Nguồn: WeAreSocial


- Tại Việt Nam:
o Trong giai đoạn 2014 - 2016, xu hướng Mobile và lượng người dùng Internet 3G
sẽ tiếp tục tăng mạnh. Các dịch vụ kết nối OTT và truyền thông xã hội đóng góp
hơn 80% phương thức giao tiếp online, video online và nội dung số mobile. Điều
này góp phần đẩy mạnh xu hướng truyền thông số đa phương tiện, đa màn hình
sẽ bùng nổ với độ phủ hơn 50% dân số Việt Nam.
o Doanh thu điện thoại thông minh và máy tính bảng giờ đây đã vượt qua PC và
laptop. Các doanh nghiệp hoạt động trong lĩnh vực sản xuất công nghệ cũng
đang cố gắng hướng tới các dịch vụ như “thanh toán di động, nội dung di động,
dịch vụ xác định địa điểm hay khai thác dữ liệu sử dụng của người dùng thiết bị
di động”.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |5


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.3. Chỉ số về Internet trên di động tại Việt Nam năm 2014 - Nguồn: Theo thống kê Cục
Thương mại điện tử và công nghệ thông tin (VECITA), Bộ Công thương.

- Tỉ lệ truy cập Internet qua các thiết bị di động: 36% tổng số dân.
- Tỉ lệ truy cập Internet có tham gia mua sắm online 57%.
- Một người Việt Nam truy cập Internet 5,6 giờ/ngày, 6,4 ngày/tuần - Tổng số thời gian
36 giờ/tuần.

Hình 1.4. Thống kê các chỉ số người dùng smartphone tại Việt Nam năm 2014 - Nguồn: Theo
thống kê Cục Thương mại điện tử và công nghệ thông tin (VECITA), Bộ Công thương.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |6


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.5. Thống kê chỉ số điện thoại di động và các loại hình thanh toán tại Việt Nam năm
2014 - Nguồn: Theo thống kê Cục Thương mại điện tử và công nghệ thông tin (VECITA), Bộ
Công thương.

1.2.2. Thị trường thiết bị Android


- Trong tất cả các hệ điều hành dành cho di động hiện nay, có thể nói: Android đã mang
lại một cuộc cách mạng thật sự cho các lập trình viên. Nổi bật với tính mở, đơn giản
nhưng mạnh mẽ, không tốn phí cho bất cứ bản quyền nào và đặc biệt cộng đồng lập
trình viên vô cùng lớn mạnh. Android thật sự là một nền tảng mạnh mẽ cho phép các
lập trình viên, những người chưa từng lập trình trên thiết bị di động có thể tạo ra các
ứng dụng một cách nhanh chóng và dễ dàng. Có thể nói Android đang dần mang lại
phong cách mới trong thói quen sử dụng điện thoại của người dùng.
- Kể từ khi bắt đầu được thương mại hóa, ước tính mỗi ngày có khoảng 850 ngàn thiết bị
Android được kích hoạt. Nhiều cuộc nghiên cứu đã chỉ ra rằng phần lớn các thiết bị
smartphone mới được xuất xưởng chạy hệ điều hành Android.
- Có tới 53 triệu thiết bị sử dụng mã nguồn mở Android (AOSP) được bán ra, chiếm tới
11% tổng số smartphone trong quý 1/2014. Điều này một lần nữa cho thấy, Android đã
có được một địa vị cực kỳ vững chắc trên thị trường smartphone.
- Công ty nghiên cứu thị trường Strategy Analytics công bố hôm 31/10/2014 cho biết, số
lượng smartphone chạy Android bán ra trên phạm vi toàn cầu đạt 268 triệu chiếc, tăng
mạnh so với thành tích 206 triệu chiếc của cùng kỳ năm ngoái. Nếu xét về thị phần, chú
robot xanh của đại gia công nghệ Google đang giữ 84% thị phần.

1.2.3. Nhu cầu tuyển dụng lập trình viên Android


- Với xu thế phát triển công nghệ di động nhanh và mạnh như hiện nay, thị trường thiết
bị Anroid chiếm vị trí cao nhất không chỉ ở Việt Nam mà trên toàn thế giới, thì nhu cầu
sử dụng các ứng dụng cho các thiết bị Android là rất lớn. Vì vậy, nhu cầu tuyển dụng
lập trình viên Android cũng rất lớn và sẽ tăng nhanh.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |7


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2. KIẾN TRÚC ANDROID


- Có thể hiểu Android Software Stack bao gồm nhân Linux, tập các thư viện C/C++ được
truy xuất bởi tầng ứng dụng để sử dụng các dịch vụ, các bộ quản lý thực thi và quản lý
ứng dụng. Mỗi tầng đều có chức năng vai trò riêng biệt với nhau:
o Linux kernel – lõi chính của toàn hệ thống bao gồm các điều khiển phần cứng,
bộ quản lý xử lý và bộ nhớ, bảo mật, kết nối mạng, bộ quản lý năng lượng.
o Libraries – thực thi trên tầng nhân Linux, bao gồm các thư viện lõi khác nhau
của C/C++ như libc và SSL. Có các dạng sau:
 Thư viện hổ trợ phát các tập tin đa truyền thông.
 Bộ quản lý hiển thị
 Thư viện hổ trợ đồ họa OpenGL 2D và 3D
 SQLite hổ trợ lưu trữ cơ sở dữ liệu
 SSL và WebKit cho phép tương tác với trình duyệt và bảo mật Internet.
- Android Run Time – đây chính là điểm làm nên sự khác biệt giữa thiết bị Android và
thiết bị Linux. Bên trong thành phần này bao gồm máy ảo Dalvik và thư viện lõi.
Android Run Time ngoài tăng tốc độ cho ứng dụng còn làm nền cho tầng Application
Framework kết nối đến.
o Core Libraries – mặc dù hầu hết các ứng dụng Android viết bằng ngôn ngữ Java
nhưng Dalvik không phải là máy ảo Java. Các thư viện lõi Android sẽ cung cấp
hầu hết các chức năng chính có thể có trong thư viện Java cũng như thư viện
riêng biệt của Android.
o Dalvik VM – dạng máy ảo cho phép tối ưu hóa để có thể chạy được nhiều tiến
trình một các hiệu quả, dựa trên nhân Linux các máy ảo cho phép quản lý các
tiểu trình và quản lý bộ nhớ ở bậc thấp.
- Application Framework – cung cấp các lớp cho việc tạo ra các ứng dụng. Bên cạnh đó
nó cũng chứa các lớp trừu tượng cho phép truy nhập phần cứng, quản lý giao diện
người dùng và tài nguyên của ứng dụng.
- Application Layer – gồm các ứng dụng được tích hợp sẵn và các ứng dụng của hãng
thứ ba. Tầng ứng dụng trong Android Run Time sử dụng các lớp từ tầng Application
Framework để thực thi ứng dụng.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |8


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.6. Kiến trúc Android.

3. MÔI TRƯỜNG PHÁT TRIỂN ỨNG DỤNG ANDROID


3.1. Giới thiệu Java JDK, Android SDK, Android Studio
- Android SDK (Software Development Kit) và JDK (Java Development Kit) là hai công
cụ cần thiết để chúng ta có thể lập trình nên các ứng dụng Android. Và tất nhiên nếu
bạn không muốn lập trình trên phần mềm soạn thảo văn bản thì một công cụ lập trình
IDE (Integrated development environment) sẽ rất hữu ích và tiện lợi. Eclipse được xem
là một công cụ hỗ trợ rất tốt trong việc lập trình ứng dụng Android.
- Android SDK, JDK và Eclipse đều có mặt trên một số phiên bản hệ điều hành
Windows, Mac OS và Linux do đó chúng ta có thể lập trình trên hệ điều hành mà chúng
ta đã quen sử dụng. Thêm nữa, Android được thực thi trên máy ảo Dalvik nên việc phát
triển ứng dụng là như nhau trên cả 3 môi trường.
- Android Studio được Google chính thức phát hành phiên bản đầu tiên Android Studio
0.1 vào tháng 5/ 2013 (Phiên bản hiện nay là 1.2.1 – phát hành vào tháng 5/ 2015 và
phiên bản 1.3 đã được công bố tại Google I/O 2015). Là công cụ lập trình dựa trên nền
IntelliJ, cung cấp các tính năng mạnh mẽ hơn ADT như:
o Hỗ trợ xây dựng dự án dạng Gradle.
o Hỗ trợ sửa lỗi nhanh và tái sử dụng cấu trúc phương thức.
o Cung cấp các công cụ kiểm tra tính khả dụng, khả năng họat động của ứng dụng,
tương thích nền tảng…
o Hỗ trợ bảo mật mã nguồn và đóng gói ứng dụng.
o Trình biên tập giao diện cung cấp tổng quan giao diện ứng dụng và các thành
phần, cho phép tuỳ chỉnh trên nhiều cấu hình khác nhau.
o Cho phép tương tác với nền Google Cloud.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 |9


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Với mục tiêu tạo ra môi trường phát triển tất cả trong một, trải nghiệm nhanh và mượt
hơn các IDE khác, Android Studio không ngừng ra đời các phiên bản cải tiến.
3.2. Thiết lập môi trường phát triển:
- Như đã nói ở trên, ứng dụng Android được thực thi trên máy ảo Dalvik nên chúng ta có
thể lập trình trên nhiều phiên bản của các hệ điều hành. Cụ thể như sau:
o Microsoft® Windows® 8/7/Vista/2003 (32 or 64-bit).
o 2 GB RAM trở lên.
o Dung lượng ổ đĩa ứng còn trống ít nhất 400 MB.
o Ít nhất 1 GB cho Android SDK, emulator system images và caches.
o Độ phân giảm tối thiểu 1280 x 800.
o Java Development Kit (JDK) 7 trở lên.
o Tùy chọn thêm cho accelerated emulator: hỗ trợ bộ xử lý Intel® với các phiên
bản: Intel® VT-x, Intel® EM64T (Intel® 64), và tính năng Execute Disable
(XD) Bit.
- Để bắt đầu viết ứng dụng với Android Studio, chúng ta cần tải và cài đặt hai bộ phần
mềm sau:
o Java JDK: http://java.sun.com/javase/downloads/index.jsp (Cài đặt trước hết và
nên chọn phiên bản mới nhất).
o Android Studio: http://developer.android.com/sdk/index.html - tải gói Android
Studio, gói này sẽ chứa các thành phần:
o Android Studio IDE.
o Android SDK tools.
o Android 5.0 (Lollipop) Platform.
o Android 5.0 emulator system image with Google APIs.

Hình 1.7

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 10


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Sau khi tải bộ cài Android Studio thành công, chúng ta chạy tập tin android – studio –
bundle để tiến hành cài đặt Android Studio → màn hình Welcome to Android Studio
Setup xuất hiện → Next:

Hình 1.8.
- Nếu hệ thống không phát hiện ra JDK trong máy tính của bạn, một hộp thoại yêu cầu
chỉ rõ đường dẫn hoặc cài đặt JDK xuất hiện:

Hình 1.9
Nếu đã có JDK thì tìm đường dẫn đến nơi cài đặt. Sau đó, nhấn Next. Hộp thoại lựa chọn cấu
hình cài đặt sẽ mở ra → chọn (check) đủ các thành phần như hình bên dưới → Next:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 11


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.10
- Xuất hiện hộp loại thông báo các điều khoản và một số lưu ý khi sử dụng Android
Studio → chọn I Agree:

Hình 1.11.
- Xuất hiện hộp thoại yêu cầu chọn nơi cài đặt Android Studio và Android SDK như sau:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 12


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.12.
- Sau đó, nhấn Next để tiếp tục quá trình cài đặt. Hộp thoại chọn Start Menu xuất hiện,
chọn Android Studio và nhấn vào Installl để tiếp tục quá trình cài đặt:

Hình 1.13.
- Khi quá trình cài đặt hoàn tất, nhấn Next để tiếp tục:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 13


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.14.
- Hộp thoại cuối cùng của quá trình cài dặt xuất hiện, chọn Finish để kết thúc quá trình
cài đặt:

Hình 1.15.
Ở lần khởi động đầu tiên, một hộp thoại “import” bản Android Studio cũ xuất hiện, nếu bạn
cài đặt mới thì chọn như hình dưới → chọn OK:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 14


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.16.
- Vì là lần đầu tiên khởi động nên Android Studio phải cập nhật một vài thứ cho quá
trình làm việc sau này:

Hình 1.17.
- Khi hoàn tất quá trình cập nhật, nhấn Finish để kết thúc và hoàn thành quá trình cài đặt.
3.3. Tạo ứng dụng đầu tiên
3.3.1. Khởi tạo dự án
- Khởi chạy Android Studio, xuất hiện màn hình “Welcome to Android Studio” → chọn
Start a new Android Studio project để tạo dự án Android Studio (Android Studio
project) mới như sau:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 15


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.18.
- Hộp thoại tiếp theo xuất hiện yêu cầu đặt tên cho ứng dụng và tên domain như hình sau:

Hình 1.19.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 16


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Trong hộp thoại này:


o Application name: là tên của ứng dụng.
o Company Domain: là tên domain của công ty kết hợp với tên của ứng dụng để
tạo ra package. Sử dụng để đưa ứng dụng của bạn lên Google Play Store.
o Pakage name: Tên của gói ứng dụng của bạn. Dùng để phân biệt với các gói
khác trên Google Play Store.
o Project location: Nơi lưu trữ ứng dụng của bạn.
- Sau khi nhập xong thông tin (bao gồm tên ứng dụng, domain và nơi lưu dự án) → nhấn
Next để tiếp tục → Xuất hiện hộp thoại chọn thiết bị (device) mà bạn muốn phát triển
ứng dụng:

Hình 1.20.

- Chọn như hình trên nếu muốn phát triển ứng dụng trên điện thoại (phone) và tablet. Sau
đó nhấn, Next để tiếp tục.
o Chú ý: Minimum SDK là phiên bản thấp nhất được chỉ định để chạy ứng dụng
và một số các phương thức API sẽ được gọi bổ sung trong phần thư viện hỗ trợ.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 17


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.21.
- Chọn Blank Activity và nhấn Next. Hộp thoại nhập thông tin của Activity xuất hiện
như sau:

Hình 1.22.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 18


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Trong hộp thoại này:


o Activity Name: Tên lớp lưu giữ mã nguồn.
o Layout Name: Tên tập tin XML làm giao diện cho Activity Name.
o Title: Tên tiêu đề, sẽ hiển thị khi kích hoạt activity trên thiết bị.
o Menu Resource Name: Tên tập tin xml để tạo menu cho phần mềm.
- Sau khi nhập đầy đủ thông tin, nhấn Finish để kết thúc. Chờ “building” dự án xong là
hoàn tất việc tạo dự án.
3.3.2. Cấu trúc dự án
- Sau khi tạo dự án, chúng ta tiến hành mở dự án đã tạo để xem cấu trúc của nó. Và trên
màn hình của chúng ta lúc này sẽ tương tự như sau:

Hình 1.23.
- Ở hình trên, màn hình làm việc được chia thành 7 phần – 7 phần này, chúng ta sẽ tương
tác thường với chúng với các chức năng cụ thể như sau:
o Phần 1: thanh công cụ này rất tiện lợi. Nó giúp chúng ta thao tác nhanh các chức
năng thường dùng khi lập trình, chi tiết như sau:
 Biểu tượng dùng để mở một tập tin (file) hay một dự án (Project).
 Biểu tượng dùng dể lưu lại tất cả các tập tin trong dự án (Save All).
Chúng ta cũng có thể dùng phím Ctrl + S để thực hiện chức năng này thay
vì chọn biểu tượng.
 Biểu tượng cho phép đồng bộ tập tin. Chức năng này sẽ tìm tất cả các
tập tin đã thay đổi từ bên ngoài và tải lại (reload) chúng từ ổ đĩa cứng.
Chúng ta có thể dùng phím Ctrl + All +Y để thực hiện chức năng này
thay vì chọn biểu tượng này.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 19


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Hai biểu tượng cho phép chúng ta quay lại hành động đã làm trước
hoặc sau (Undo – Redo). Chúng ta cũng có thể sử dụng phím Ctrl + Z và
Ctrl + Shift + Z để sử dụng chức năng này.
 Biểu tượng để “cut” tập tin hoặc hình ảnh đến Clipboad. Có thể sử
dụng phím Ctrl + X để thực hiện chức năng này thay vì chọn biểu tượng
này.
 Biểu tượng để sao chép (copy) tập tin hoặc hình ảnh đến Clipboad. Có
thể sử dụng phím Ctrl + C để thực hiện chức năng này thay vì chọn biểu
tượng này.
 Biểu tượng để dán (paste) tập tin hoặc hình ảnh từ Clipboad. Có thể sử
dụng phím Ctrl + V để thực hiện chức năng này thay vì chọn biểu tượng
này.
 Biểu tượng để chạy (run) ứng dụng. Chúng ta cũng có thể dùng phím
Shift + F10 thay vì chọn biểu tượng này.
 Biểu tượng để “debug” ứng dụng. Chúng ta cũng có thể dùng phím
Shift + F9 thay vì chọn biểu tượng này.
 Biểu tượng là Android Virtual Device Manager (AVD Manager) cho
phép tạo và quản lý các thiết bị ảo.
 Biểu tượng là SDK Manager có chức năng quản lí các phiên bản
Android.
- Đó là các biểu tượng với các chức năng thường sử dụng trong khi lập trình, ngoài ra
còn các biểu tượng khác, bạn có thể tự tìm hiểu thêm.
o Phần 2: là phần dành cho cấu trúc hệ thống của ứng dụng:

Hình 1.24.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 20


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Chúng ta cũng có thể thay đổi cách hiển thị (thường đặt mặc định là
Android).

Hình 1.25.
 Cấu trúc dự án có thể chia thành phần sau:
 Thư mục:
 src: Thư mục này chứa các file mã nguồn .java cho dự án
của bạn.
 gen: Thư mục này chứa file R.java - 1 file được trình biên
dịch sinh ra có khả năng tham chiếu tới tất cả các tài nguyên
trong dự án. Bạn không nên chỉnh sửa file này.
 bin: Thư mục này chứa các file *.apk (Android Package
file) được build bởi ADT.
 res/drawable-hdpi: Đây là thư mục chứa các đối tượng
drawble được thiết kế dành cho các màn hình có độ phân
giải cao.
 res/layout: Đây là thư mục chứa các file layout cho việc
thiết kế giao diện.
 res/values: Đây là thư mục dành cho các file XML khác
chứa 1 tập hợp các tài nguyên, ví dụ như: các định nghĩa về
strings, colors.
 Tập tin:
 AndroidManifest.xml: chứa thông tin cài đặt ứng dụng.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 21


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Ngoài ra còn có thư mục assets chứa tất cả các tập tin không biên dịch
như: âm thanh, hình ảnh, tập tin CSDL của ứng dụng…
o Phần 3: nó khá quan trọng cho những bạn mới bắt đầu lập trình. Đây là nơi hiển
thị các điều khiển (control) mà Android hỗ trợ, cho phép bạn kéo thả trực tiếp
vào phần 4 (Giao diện thiết bị) để thiết kế.

Hình 1.26.

- Chú ý ở góc trái có 2 phần là Design và Text, với:


o Phần “Design”: cho phép thiết kế giao diện bằng cách kéo thả.
o Phần “Text”: phép chúng ta thiết kế giao diện bằng cách viết thẻ XML.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 22


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.27.

o Phần 4: là vùng giao diện thiết bị, cho phép các điều khiển (control) kéo thả vào
đây. Chúng ta có thể chọn cách hiển thị theo nằm ngang - nằm đứng, phóng to -
thu nhỏ, căn chỉnh điều khiển, lựa chọn loại thiết bị hiển thị, ...
o Phần 5: Khi màn hình của bạn có nhiều điều khiển (control) thì phần 5 này rất
cần thiết. Nó hiển thị giao diện theo dạng cấu trúc cây nên bạn dễ dàng quan sát
và lựa chọn điều khiển khi chúng bị chồng lập trên giao diện.

Hình 1.28.
o Phần 6: cho phép thiết lập trạng thái hay thuộc tính cho các điều khiển trên giao
diện.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 23


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.29.
3.3.3. AndroidManifest
- Vai trò của tập tin AndroidManifest.xml:
- Lưu trữ thông tin tên gói ứng dụng, tồn tại duy nhất một tên gói cho mỗi ứng dụng.
o Ví dụ: com.htsi.myfirstapp
- Cho biết ứng dụng sử dụng các thành phần nào, mỗi thành phần được khai trong một
cặp thẻ.
o Ví dụ: <activity>….</activity>
- Định nghĩa tiến trình quản lý các thành phần ứng dụng.
- Định nghĩa các quyền sử dụng API và truy xuất ứng dụng khác.
- Qui định các yêu cầu khi được ứng dụng khác truy xuất.
- Khai báo cấp độ API tối thiểu xây dựng ứng dụng.
- Khai báo các thư viện có liên quan.
3.4. Cập nhật Android API
- Như đã đề cập ở phần cấu trúc dự án (3.3.2 – Phần 1) để cập nhật Android API, chúng
ta sử dụng công cụ SDK Manager.

Hình 1.30.
- SDK Manager quản lí các phiên bản Android. Ứng với từng phiên bản là các tài liệu
hướng dẫn, các ví dụ minh họa và các phương thức API... Nhấn vào biểu tượng để khởi
động SDK Manager và ADT sẽ tự động cập nhật các gói mới, bạn có thể lựa chọn
phiên bản Android hoặc các công cụ cần thiết và ấn Install Pakages.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 24


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.31. Tải và cài đặt bộ SDK với SDK Manager.


- Chú ý:
o Các gói cần được cài đặt:
 Tools:
 Android SDK Tools.
 Android SDK Platform-tools.
 Android SDK Build-tools.
 SDK Platform (phiên bản mới nhất):
 SDK Platform.
 ARM EABI v7a System Image.
 Extras:
 Android Support Repository.
 Android Support Library.
 Google Repository.
 Google USB Driver (chỉ yêu cầu trên hệ điều hành Windows).
 Intel x86 Emulator Accelerator (HAXM installer).

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 25


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

3.5. Cài đặt và sử dụng Android Virtual Device (AVD)


- Android Virtual Device Manager (AVD Manager), cho phép lập trình viên tạo và quản
lí các thiết bị ảo. Để tạo thiết bị ảo, ta chọn biểu tượng AVD Manager trên thanh công
cụ của Android Studio → một hộp thoại mới hiện ra → Create a virtual device:

Hình 1.32.
- Xuất hiện hộp thoại “Virtual Device Configuration” cho phép bạn chọn thiết bị muốn
tạo như sau:

Hình 1.33.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 26


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Chú ý: chúng ta có thể tùy chỉnh lại tên, loại thiết bị, dung lượng bộ nhớ, … cho thiết bị
muốn tạo bằng cách chọn nút Clone Device → xuất hiện hộp thoại Configure Hardware
Profile như sau:

Hình 1.34.
- Trong đó:
o Device Name: tên thiết ảo cần tạo (thường đặt tên theo phiên bản).
o Device Type: loại thiết bị muốn tạo, có các lựa chọn: Phone/ Tablet, Android
Wear, Android TV.
o Screen: độ rộng và độ phân giải cho màn hình.
o Memory: bộ nhớ thiết bị.
- Tiếp theo, chúng ta chọn Next để tiếp tục quá trình tạo máy ảo → xuất hiện hộp thoại
cho phép chọn phiên bản hệ điều hành muốn tạo:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 27


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.35.

Hình 1.36.
- Để cấu hình nâng cao, chúng ta chọn Show Advanced Settings.
- Chọn Finish để hoàn thành quá trình tạo máy ảo.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 28


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 2
CÁC THÀNH PHẦN ỨNG DỤNG ANDROID

1. CÁC THÀNH PHẦN TRONG ỨNG DỤNG ANDROID


- Trong một ứng dụng Android thường chúng ta sẽ gặp 8 thành phần cơ bản sau:
1.1. Activity
- Trong ứng dụng Android, Activity đóng vai trò là một màn hình, nơi người dùng có thể
tương tác với ứng dụng, ví dụ: chụp hình, xem bản đồ, gửi mail…
- Một ứng dụng có thể có một hoặc nhiều Activity, Activity được khởi chạy đầu tiên khi
ứng dụng hoạt động được gọi là “MainActivity”.
- Activity có thể hiển thị ở chế toàn màn hình, hoặc ở dạng cửa sổ với một kích thước
nhất định.
- Các Activity có thể gọi đến các Activity khác, Activity được gọi sẽ nhận được tương
tác ở thời điểm đó.
1.2. Intent
- Intent là đối tượng mang thông điệp, cho phép tạo ra các yêu cầu hành động giữa các
thành phần trong ứng dụng, hoặc giữa các ứng dụng với nhau.
- Được sử dụng nhiều trong 3 trường hợp sau:
o Khởi động Activity.
o Khởi động Service.
o Chuyển phát thông tin cho Broadcast Receiver.
1.3. View
- View được sử dụng để tạo ra các điều khiển trên màn hình cho phép nhận các tương tác
từ người dùng cũng như hiển thị các thông tin cần thiết.
- View bao gồm hai dạng:
o View: các điều khiển đơn lẻ.
o ViewGroup: tập hợp nhiều điều khiển đơn lẻ.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 29


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 2.1. View.


1.4. Broadcast Receiver
- Thành phần ứng dụng cho phép truyền tải các thông báo trên phạm vi toàn hệ thống.
Không có giao diện nhưng có thể thực hiện thông báo qua thanh trạng thái.
- Broadcast Receiver truyền thông báo ở hai dạng:
o Hệ thống: các thông báo được truyền trực tiếp từ hệ thống như: tắt màn hình, pin
yếu, thay đổi kết nối…
o Ứng dụng: xây dựng các truyền thông báo đến các thành phần trong ứng dụng
như: khởi động Service, tải nội dung đến ứng dụng…
1.5. Service
- Service được sử dụng để thực thi các tác vụ cần nhiều thời gian, thực hiện ở chế độ
ngầm và thường không cần giao diện hiển thị.
- Service được chạy ngầm, tức lại ứng dụng vẫn chạy nhưng không hiển thị giao diện
tương tác.
- Một số tác vụ cần thực hiện bằng Service:
o Trình diễn các tập tin đa truyền thông như nhạc, phim…
o Kết nối và thực hiện tải các nội dung thông qua Internet.
o Truy xuất đọc ghi tập tin.
1.6. Content Provider
- Content Provider xây dựng cách thức truy xuất tập hợp các dữ liệu ứng dụng, dữ liệu
có thể lưu trữ ở nhiều dạng như: SQLite, tập tin, tài nguyên Web hoặc bất kì thư mục
lưu trữ nào.
- Có thể sử dụng Content Provider để xây dựng các ứng dụng sử dụng chung nguồn tài
nguyên hoặc sử dung riêng.
- Trong Android, một số Content Provider được xây dựng sẵn:
o Danh bạ.
o Tài nguyên đa truyền thông.
o Lịch.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 30


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

1.7. Context
- Context thuộc gói android.content (android.content.Context).
- Là một lớp cơ bản chứa hầu hết thông tin về môi trường ứng dụng của android, có
nghĩa là mọi thao tác, tương tác với hệ điều hành điều phải qua lớp này.
- Nó cung cấp các phương thức để các lớp khác có thể tương tác với hệ thống Android.
- Nó cho phép truy cập tới các nguồn tài nguyên (resources) đã được định nghĩa và các
lớp khác. Có thể nói Context là một lớp ở mức ứng dụng (Application level- liên quan
tới hệ thống).
- Hầu hết các lớp có liên quan tới UI (layout, button, textview, imageview, listview,…)
đều phải “super” tới Context vì bản thân Context đảm nhiệm việc truy cập tài nguyên
(R.id, R.layout,…). Nếu chúng ta không tham chiếu tới lớp Context thì không thể dùng
tới các tài nguyên mà chúng ta đã tạo ra.
- Tóm lại, Context giúp chúng ta dễ dàng truy cập và tương tác tới các tài nguyên của hệ
thống, các thông tin, các dịch vụ (services), các thông số cấu hình, dữ liệu, danh bạ,
cuộc gọi, kết nối, chế độ rung (vibrator), ...
1.8. Notification
- Thành phần cho phép gửi các thông báo đến người dùng mà không chiếm quá nhiều
việc điều khiển của người dùng trên thiết bị. Ví dụ, khi nhận được một tin nhắn hay một
thư điện tử , thiết bị sẽ sử dụng Notification để thông báo người dùng thông qua nhạc
chuông, đèn nền, thể hiện biểu tượng trên thanh tác vụ…
- Notification được xây dựng cho mục đích gửi các thông báo đến người dùng thông qua
thanh trạng thái.
- Giao diện Notification không thuộc giao diện ứng dụng, nhưng có thể tuỳ chỉnh giao
diện Notification thông qua các phương thức có sẵn.

Hình 2.2. Notification.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 31


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2. TƯƠNG THÍCH THIẾT BỊ


- Ứng dụng Android được viết bằng ngôn ngữ Java và biên dịch, đóng gói cùng các tập
tin tài nguyên thành tập tin *.apk.
- Cài đặt trên thiết bị theo đường dẫn data/app/<Tên đóng gói>, được chứa trong
Sandbox và được hiểu:
o Mỗi ứng dụng là một dạng “người dùng” khác nhau.
o Mỗi ứng dụng được cấp một ID, do đó chỉ duy nhất ứng dụng mới có thể truy
xuất các tập tin liên quan đến ứng dụng đó.
o Ứng dụng thực thi riêng biệt trên từng máy ảo.
o Tiến trình Linux được cấp phát khi bất cứ thành phần ứng dụng được gọi thực
thi, và thu hồi khi chấm dứt hoạt động.
o Các ứng dụng có cùng ID và chứng chỉ (Cerfiticate) có thể truy xuất tài nguyên
của nhau, hoặc xin quyền nếu truy xuất hệ thống.
- Tính tương thích ứng dụng với thiết bị bao gồm:
o Trang bị tính năng của thiết bị.
o Phiên bản hệ điều hành.
o Kích thước màn hình.
- Trang bị tính năng của thiết bị:
o Mỗi tính năng phần cứng và phần mềm trên thiết bị Android được cung cấp một
ID, qui định thiết bị đó có được trang bị tính năng đó hay không.Ví dụ:
 FEATURE_SENSOR_COMPASS: tính năng la bàn.
 FEATURE_APP_WIDGET: tính năng gắn Widget.
- Phiên bản hệ điều hành:
o Mỗi phiên bản kế tiếp được bổ sung hoặc lược bỏ các phương thức API, cần
thực thi khai báo các thông tin phiên bản để sử dụng đầy đủ các tính năng cho
ứng dụng.
o Ví dụ:
 Android ICS 4.0: bổ sung API cho Calendar
 Android Kit Kat 4.4: bổ sung API cho WirelessPrint
- Kích thước màn hình:
o Ứng dụng Android cần tương thích với nhiều kích cỡ thiết bị, được phân chia
thành hai thuộc tính:
 Kích thước vật lý màn hình.
 Độ phân giải (mật độ điểm ảnh).

3. ACTIVITY VÀ ĐỘ ƯU TIÊN ỨNG DỤNG


3.1. Xây dựng Activity
Trong một ứng dụng Android thì người dùng thao tác với các Activity, và một ứng dụng thì
không thể chỉ có một Activity mà cần có nhiều Activity. Và trong lập trình, bạn cần chuyển

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 32


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

đổi qua lại giữ các Activity với nhau đồng thời truyền dữ liệu trừ Activity trước sang Activity
mới để có thể xử lý.

- Mỗi Activity đại diện cho một màn hình ứng dụng. Ta sẽ thực hiện tạo Activity cho
ứng dụng theo các bước sau:
o Tạo mới lớp kế thừa từ lớp Activity.
o Thực thi các phương thức quản lý trạng thái Activity.
o Xây dựng giao diện trong tài nguyên res/layout.
o Khai báo Activity trong tập tin AndroidManifest.xml.
Ví dụ:
public class MyFirstActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

- Đăng kí Activity trong tập tin AndroidMannifest.xml:

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >

<activity android:name="com.your-company.MyFirstActivity" >


<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

3.2. Quản lý trạng thái Activity (Managing the Activity Lifecycle)


- Activity là thành phần quan trọng nhất và đóng vai trò chính trong xây dựng ứng dụng
Android. Hệ điều hành Android quản lý Activity theo dạng stack: khi một Activity mới
được khởi tạo, nó sẽ được xếp lên đầu của stack và trở thành running activity, các
Activity trước đó sẽ bị tạm dừng và chỉ hoạt động trở lại khi Activity mới được giải
phóng.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 33


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Activity Stack là gì?


o Tương tự như các ngôn ngữ lập trình khác, Activity Stack hoạt động theo cơ chế
LIFO (LAST IN FIRST OUT).
o Mỗi một Activity mới được mở lên nó sẽ ở bên trên Activity cũ, để trở về
Activity thì bạn chỉ cần nhấn nút “Back” để trở về hoặc viết lệnh. Tuy nhiên nếu
bạn nhấn nút Home rồi thì sẽ không thể dùng nút “Back” để quay lại màn hình
cũ được.

Hình 2.3. Activity Stack


- Một Activity cơ bản có 4 trạng thái:
o Active: Activity đang hiển thị trên màn hình (foreground).
o Paused: Activity vẫn hiển thị (visible) nhưng không thể tương tác (lost focus).
VD: một activity mới xuất hiện hiển thị giao diện đè lên trên activity cũ, nhưng
giao diện này nhỏ hơn giao diện của activity cũ, do đó ta vẫn thấy được 1 phần
giao diện của activity cũ nhưng lại không thể tương tác với nó.
o Stopped: Activity bị thay thế hoàn toàn bởi Activity mới sẽ tiến đến trạng thái
stopped.
o Inactive: Khi hệ thống bị thiếu bộ nhớ, nó sẽ giải phóng các tiến trình theo
nguyên tắc ưu tiên. Các Activity ở trạng thái stopped hoặc paused cũng có thể bị
giải phóng và khi nó được hiển thị lại thì các Activity này phải khởi động lại
hoàn toàn và phục hồi lại trạng thái trước đó.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 34


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

3.3. Vòng đời của Activity (Activity Lifecycle)


- Entire lifetime:
o Từ phương thức onCreate() cho tới onDestroy(): từ lúc Activity được gọi ra cho
đến lúc bị huỷ.
- Visible liftetime:
o Từ sau khi gọi onStart() cho tới lúc gọi onStop() : trong trường hợp này ta vẫn
có thể thấy màn hình Activity.
- Foreground lifetime:
o Xảy ra từ khi gọi onResume() cho tới lúc gọi onPause(): trong suốt thời gian này
Activity luôn nằm ở trên cùng và ta có thể tương tác được với nó.

Hình 2.4. Vòng đời của Activity.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 35


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

3.4. Độ ưu tiên trong ứng dụng


- Android quản lý các Ứng dụng dựa trên độ ưu tiên.
- Nếu hai ứng dụng có cùng trạng thái thì ứng dụng nào đã chạy lâu hơn sẽ có độ ưu tiên
thấp hơn.
- Nếu ứng dụng đang chạy một Service hay Content Provider do một ứng dụng khác hỗ
trợ thì sẽ có cùng độ ưu tiên với ứng dụng đó.
- Các ứng dụng sẽ bị đóng mà không có sự báo trước.

Hình 2.4. Cách phân định độ ưu tiên.

o Foreground process: là process của ứng dụng hiện thời đang được người dùng
tương tác.
o Visible process: là process của ứng dụng mà activity đang hiển thị đối với người
dùng (onPaused() của activity được gọi).
o Service process: là Service đang chạy.
o Background process: là process của ứng dụng mà các activity của nó không
hiển thị với người dùng (onStoped() của activity được gọi).
o Empty process: process không có bất cứ 1 thành phần nào active.

- Theo chế độ ưu tiên thì khi cần tài nguyên, Android sẽ tự động kill process, trước tiên
là các empty process.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 36


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 3
GIAO DIỆN NGƯỜI DÙNG
VÀ XỬ LÝ SỰ KIỆN

1. GIAO DIỆN NGƯỜI DÙNG


Giao diện người dùng là một trong những yếu tố quan trọng, quyết định sự thành công của một
ứng dụng Android. Ứng dụng Android muốn thành công thì phải có giao diện trực quan, dễ hiểu
và dễ sử dụng. Ở bài này, chúng ta sẽ tìm hiểu cấu trúc giao diện, các thành phần trên giao diện
và các thuộc tính của chúng.
Giao diện được tạo bởi nhiều tài nguyên như: layout, các diều khiển (control), tài nguyên hình
ảnh, màu sắc, v.v... Và tất cả các tài nguyên dùng để thiết kế giao diện sẽ được lưu trong thư
mục res/.
1.1. Layout
- Các tài nguyên layout được lưu trữ trong thư mục res/layout.
- Có thể có nhiều thư mục layout theo từ hạn định khác nhau:
- Ví dụ: layout-land, layout-xhdpi…
- Truy xuất: bao gồm 2 cách thức:
o Java: R.layout.<tên tài nguyên>.
o XML: @[pakage:]layout/<tên tài nguyên>.
- Các định dạng Layout
Layout bao gồm những lớp được mở rộng từ lớp ViewGroup mà ở đó ta có thể sắp xếp
và bố trí các điều khiển cho một giao diện. Tùy thuộc vào cách bố trí của mỗi người mà
sẽ có các giao diện khác nhau và tất nhiên cần cân bằng giữa tính tiện dụng và tính thẩm
mỹ. Android cũng cấp một số các lớp Layout cho phép chúng ta có thể sử dụng hoặc tùy
chỉnh tùy thuộc vào từng ứng dụng.
Bao gồm các lớp kế thừa từ ViewGroup: AbsoluteLayout (Deprecated), AdapView
(ListView, Gridview…), DrawerLayout, FragmentBreadCrumbs, FrameLayout,
GridLayout, LinearLayout, PagerTitleStrip, RelativeLayout, SlidingDrawer,
SlidingPaneLayout, SwipeRefreshLayout, ViewPager.
1.1.1. Frame Layout
- Sử dụng trong các trường hợp xây dựng bố cục tổ chức hiển thị một đối tượng duy nhất.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 37


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Đối tượng mặc định vị trí top-left trên FrameLayout, có thể sử dụng thuộc tính Gravity
để thiết lập lại vị trí.
- Frame Layout có thể chứa nhiều View và các View này có thể sắp chồng lên nhau. Và
các View nằm dưới có thể bị các View nằm trên che khuất. Vì vậy, thường Frame Layout
chỉ chứa một View.
- Ví dụ khai báo:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent”" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/android" />
</FrameLayout>

Hình 3.1. FrameLayout.

- Các đối tượng kế thừa phổ biến của FrameLayout:


o ViewFlipper: đối tượng cho phép thực hiện hiển thị các đối tượng ở chế độ phân
trang, chỉ hiển thị một đối tượng ở một thời điểm.
 Ví dụ khai báo:
<ViewFlipper
android:layout_width="match_parent"

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 38


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

android:layout_height="match_parent”" >
</ViewFlipper>

 Các phương thức sử dụng:


 startFlipping
 setAutoStart
 showNext
 showPrevious

o ScrollView: đối tượng cho phép thực hiện hiển thị các đối tượng ở chế độ cuộn
màn hình, chỉ cho phép chứa một đối tượng ở một thời điểm.
 Ví dụ khai báo:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent” >
</ScrollView>

- Các phương thức sử dụng:


o setFillViewPort
o scrollBy
o scrollTo
o smoothScrollBy
o smoothScrollTo
1.1.2. Linear Layout
- Giao diện một hướng, có nghĩa là các View sẽ được sắp xếp lên Layout theo một hướng
nhất định hoặc theo chiều ngang (từ trái qua phải) hoặc theo chiều dọc (từ trên xuống
dưới). Thuộc tính weight của Layout sẽ cho phép điều chỉnh kích thước của các View
dựa trên mối quan hệ của chúng (cùng một hàng chẳng hạn).
- Được xem dạng là Layout dễ sử dụng nhất, chúng cho phép chúng ta tạo ra các giao diện
đơn giản bằng cách sắp xếp các View theo một chiều duy nhất. Điều này gây khó khăn
khi chúng ta cần thiết kế các giao diện phức tạp, do đó LinearLayout thường được sử
dụng trong một Layout khác. Ví dụ, ở đây ta thiết kế khác LinearLayout lồng nhau, một
Layout dạng Horizontal để chứa hai Button và một Layout dạng Vertical cho phép hai
Button nằm trên ListView.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 39


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.2. Các dạng LinearLayout.


- Ví dụ khai báo:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent”
android:orientation=“vertical” >
</LinearLayout>

1.1.3. Table Layout


- Table Layout là đối tượng layout kế thừa từ LinearLayout, cho phép hiển thị các đối
tượng theo nhiều dòng (TableRow).
- Mỗi dòng có thể chứa nhiều View, mỗi View được xem là một cột.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 40


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.3. TableLayout.


- Ví dụ khai báo:
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent” >
<Tablerow>
<Button/>
</Tablerow>
<Tablerow>
<Button/>
</Tablerow>

</TableLayout>

- Có thể kéo dãn độ rộng một cột với thuộc tính: android: layout_span.

1.1.4. Relative Layout


- Các View khi được đặt lên Layout sẽ có vị trí phụ thuộc vào View đã đặt vào trước nó,
do đó khi thay đổi vị trí của một View sẽ làm thay đổi vị trí của các View còn lại.
- Đối với các giao diện phức tạp hơn thì việc dùng Relative Layout sẽ dễ dàng hơn. Các
View khi được đặt lên Layout sẽ có vị trí phụ thuộc vào vị trí các View đã đặt vào trước
đó và đối tượng đang chứa nó.
- Ví dụ ở đây ta có thể xây dựng Layout cho TextView nằm phía trên ba Button theo vị trí
tuỳ ý.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 41


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.4. RelativeLayout.


Chúng ta có thể kết hợp các loại layout lại với nhau để thiết kế giao diện. Tuy nhiên, việc tổ
chức nhiều layout lồng nhau trên một giao diện sẽ tạo ra độ phức tạp và có thể làm giảm tốc độ
xử lý. Vì vậy, khi tạo giao diện, chúng ta nên chú ý và tránh sử dụng nhiều layout chồng nhau.

2. VIEW VÀ VIEWGROUP
2.1. Tổng quan
Trong Android, để tạo giao diện, chúng ta phải sử dụng hai lớp cốt lõi là: View và ViewGroup.
Chúng rất quan trọng và được sử dụng thường xuyên trong quá trình phát triển ứng dụng
Android.
View và ViewGroup là hai lớp Java kế thừa từ lớp Java Object.
View là một lớp cha trên cùng. ViewGroup, TextView, AnalogClock, ImageView,… là các lớp
con kế thừa từ lớp cha View. Và các lớp: Frame Layout, Linear layout và Relative Layout lại
kế thừa từ ViewGroup. Tương tự, TextView cũng có 3 lớp con: EditText, Button và
CheckedTextView.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 42


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

DataPicker
FrameLayout
View TimePicker

CalendarView

ViewGroup TableLayout
LinearLayout
RadioGroup
RelativeLayout

EditText
CheckBox
TextView Button CompoundButton
View RadioButton
AnalogClock ChekedTextView

RatingBar
ProgressBar AbsSeekBar
SeekBar
ImageButton
ImageView
QuickContactBadge

SurfaceView VideoView

Hình 3.5. Các đối tượng View trong thư viện Android.
- View được sử dụng để tạo ra các điều khiển trên màn hình cho phép nhận các tương tác
từ người dùng cũng như hiển thị các thông tin cần thiết.
- View bao gồm hai dạng:
o View: các điều khiển đơn lẻ .
o ViewGroup: tập hợp nhiều điều khiển đơn lẻ.

Hình 3.6. Một số View và ViewGroup.

- Các đối tượng View được thể hiện trên màn hình giao diện như một hình chữ nhật tuỳ
thuộc vị trí, kích thước, màu sắc và nhận vào cũng như xử lý các tương tác có liên quan.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 43


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Một số thể hiện của lớp View: TextView, ImageView, SurfaceView…


- ViewGroup cũng là một thể hiện của View.
- Có thể xây dựng đối tượng View theo 2 cách:
o Kéo thả và tuỳ chỉnh thuộc tính trong XML.
o Thiết lập thông số và truy xuất trực tiếp trong Java Code.
- Thao tác với View
o Các đối tượng View được xây dựng và thiết lập với bốn thao tác chính:
 Hiển thị nội dung thông qua phương thức set<TT>(TS).
 Ví dụ: TextView hiển thị văn bản, ImageView hiển thị hình ảnh…
 Yêu cầu tương tác
 Ví dụ: sử dụng requestFocus để yêu cầu tương tác với điều khiển.
 Thiết lập chế độ hiển thị thông qua phương thức setVibility (hoặc thuộc
tính visibility: trong XML)
 VISIBLE: Trạng thái hiển thị
 INVISIBLE: Trạng thái ẩn (vẫn giữ lại vị trí trên màn hình)
 GONE: Trạng thái mất đi (mất vị trí trên màn hình)
 Xây dựng phương thức “lắng nghe”
Một số sự kiện lắng trên đối tượng View:
 OnClickListener
 OnTouchListener
 OnLongClickListener
 OnDragListener
 OnKeyListener
- Ví dụ: bắt lại các sự kiện nhấn xảy ra trên điều khiển:
view.setOnCLickListener(new OnClickLisntener() {
@Override
public void onClick(View v) {
Log.i(“View”, “onClick”);
}
});

2.2. Các thuộc tính của View


2.2.1. Id:
- Khai báo kiểu số nguyên int, đánh dấu vùng nhớ của đối tượng View.
- Id có thể giống nhau cho các điều khiển khác nhau trong cùng một tập tin giao diện.
- Phương thức thiết lập
setId()
- Phương thức truy xuất
getId()

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 44


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Thuộc tính Id được đi kèm với đối tượng View khi khai báo trong XML cho phép truy
xuất trong Java Code khi cần. Ví dụ:

Khai báo id trong XML


<Button
android:id="@+id/btnAdd"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_below="@+id/edtClass"
android:layout_centerHorizontal="true"
android:layout_marginTop="42dp"
android:background="#4696BE"
android:textColor="#FFFFFF" />

Truy xuất trong JavaCode


Button myBtn = (Button)findViewById(R.id.btnAdd);

2.2.2. Thuộc tính vị trí: cho biết toạ độ hiển thị cho View trên giao diện.
- Phương thức thiết lập :
o layout
o setLeft
o setTop
o setRight
o setBottom
- Phương thức truy xuất:
o getLeft
o getTop
o getRight
o getBottom
- Vị trí của View tuỳ thuộc vào thuộc tính của đối tượng Layout.
o Kích thước: bao gồm chiều ngang và chiều cao của một đối tượng View. Kích
thước của đối tượng View có thể thiết lập qua các thông số:
 WRAP_CONTENT
 MATCH_PARENT (API 8 trở lên)
 FILL_PARENT
Các thông số trên là một con số bất kỳ (tính theo dp/px/dip).
- Phương thức thiết lập:
o Thiết lập thông qua đối tượng LayoutParams
 Thuộc tính thiết lập trong XML:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 45


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 layout_width
 layout_height
 Phương thức truy xuất:
 getWidth
 getHeight
 getMeasuredWidth
 getMeasureHeight
o Canh lề nội dung trong JavaCode:
 Phương thức thiết lập:
 setPadding
 Phương thức truy xuất:
 getPaddingTop
 getPaddingLeft
 getPaddingRight
 getPaddingBottom

3. CÁC ĐIỀU KHIỂN CƠ BẢN


3.1. TextView:
- TextView là đối tượng cho phép hiển thị các nội dung văn bản ở 4 dạng:
o Normal: : dạng văn bản kích thước font chữ mặc đinh.
o SmallText: dạng văn bản kích thước font chữ nhỏ.
o MediumText: dạng văn bản kích thước font chữ vừa.
o LargeText: dạng văn bản kích thước font chữ to.

Hình 3.7. Ví dụ về TextView.


- Thiết lập nội dung hiển thị:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 46


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Trong Java code:


textView.setText(“Đối tượng TextView”);

Trong XML:
android:text="Đối tượng TextView"

- TextView được hổ trợ các phương thức để thực hiện các siêu liên kết (Linkify). Cơ chế
tự động thiết lập hành động cho các siêu liên kết, bao gồm:
o Web
o Email
o Phone
o Map
- Phương thức thiết lập:
Trong Java code:
textView.setAutoLinkMask(Linkify.PHONE_NUMBERS);

Trong XML:
android:autoLink="phone"

- TextView cho phép hiển thị hình ảnh theo văn bản ở hai dạng:
o Theo bố cục văn bản: Left, Top, Right, Bottom.
o Theo đoạn văn bản: Start, End.
- Phương thức thiết lập:
Trong Java code:
textView.setCompoundDrawables(Left,Top, Right, Bottom);

Trong XML:
android:drawableLeft=“@drawable/ic_launcher”

- Một số phương thức quan trọng khác:


o setTextColor – android:textColor: thiết lập màu chữ.
o setTextSize – android:textSize: thiết lập kích cỡ chữ.
o setTypeFace – android:typeface: thiết lập các tuỳ chọn khác về font hay áp dụng
một định dạng font ngoài cho TextView.
3.2. EditText:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 47


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- EditText là lớp kế thừa từ TextView, được dùng thay đổi nội dung text, chứa tất cả thuộc
tính của TextView.

Hình 3.8. EditText.


3.3. Button:
- Đối tượng Button được xây dựng từ TextView, cho phép thể hiện các nội dung văn bản,
hình ảnh – nhận và phản hồi tương tác nhấn từ người dùng.

Hình 3.9. Button.


- Các dạng Button:
o Button
o CompoundButton:
 CheckBox
 RadioButton
 ToggleButton
 Switch
- Bắt sự kiện khi người dùng ấn vào Buton: có 3 cách chính như sau:
o Cách 1:
Button btnHello = (Button) findViewById(R.id.btnHello);
btnHello.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
//do something
}
});

o Cách 2: Cho Activity implement OnClickListener của android.view.View


import android.view.View.OnClickListener;

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 48


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

public class MainActivity extends ActionBarActivity implements OnClickListener


{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnHello = (Button) findViewById(R.id.btnHello);
btnHello.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnHello:
//do something
break;
default:
break;
}
}
}

o Cách 3: Thêm thuộc tính onClick vào thẻ Button:


<Button
android:id="@+id/btnHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doHello"
android:text="Hello" />

- Viết phương thức public void doHello() trong MainActivity


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void doHello(View v){
switch (v.getId()) {
case R.id.btnHello:
//do something
break;

default:
break;
}
}

3.4. Checkbox:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 49


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- CheckBox là đối tượng nút bấm hai trạng thái “được chọn” và “bỏ chọn”.
- Phương thức lắng nghe sự kiện thay đổi trạng thái:
checkBox.setOnCheckedChangeListener(new OnCheckedChangeLisntener() {
@Override
public void onCheckedChangeListener(CompoundButton v, boolean isChecked)
{
Log.i(“CompoundButton”, “onChecked”);
}
});

3.5. RadioButton: đối tượng nút bấm hai trạng thái “được chọn” và “bỏ chọn”, không thể
“bỏ chọn” khi đã “được chọn”.
- Thường xử lý trên nhóm nút nhiều trạng thái.
- Phương thức lắng nghe sự kiện thay đổi trạng thái trên nhóm nút:
radioGroup.setOnCheckedChangeListener(new OnCheckedChangeLisntener() {
@Override
public void onCheckedChangeListener(RadioGroup group, int checkedId)
{
Log.i(“CompoundButton”, “Checked at id:” + checkedId);
}
});

3.6. ToggleButton: đối tượng nút bấm hai trạng thái “bật” và “tắt”, thể hiện trạng thái
trên đối tượng.
- Thuộc tính quan trọng:
o textOn: trạng thái nút đang bật
o textOff: trạng thái nút đang tắt
- Phương thức lắng nghe sự kiện thay đổi trạng thái trên nhóm nút:
toggleButton.setOnCheckedChangeListener(new OnCheckedChangeLisntener() {
@Override
public void onCheckedChangeListener(CompoundButton v, boolean isChecked)
{
Log.i(“CompoundButton”, “onChecked”); }
});

3.7. Switch: đối tượng nút bấm hai trạng thái “bật” và “tắt”, có thể thao tác bằng cách
trượt ngón tay trên đối tượng.
- Thuộc tính quan trọng:
o textOn: trạng thái nút đang bật
o textOff: trạng thái nút đang tắt
- Phương thức lắng nghe sự kiện thay đổi trạng thái trên nhóm nút:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 50


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

switchButton.setOnCheckedChangeListener(new OnCheckedChangeLisntener() {
@Override
public void onCheckedChangeListener(CompoundButton v, boolean isChecked)
{
Log.i(“CompoundButton”, “onChecked”);
}
});

Ngoài cách thiết lập các thuộc tính cho layout và các điều khiển trong tập tin xml như các ví
dụ trên, chúng ta có thể điền các giá trị muốn thiết lập vào giao diện được hổ trợ sẵn.

Hình 3.10. Minh họa thiết lập giá trị layout width trên giao diện tương tác.

4. KIỂM TRA LỖI VÀ TỐI ƯU LẠI GIAO DIỆN


Để kiểm tra lỗi và tối ưu lại giao diện, Android Studio có hỗ trợ công cụ Heirarchy Viewer
giúp chúng ta làm việc này.
- Để sử dụng Heirarchy Viewer, chúng ta chọn biểu tượng Android Device Monitor
trên thanh công cụ hoặc chọn Tools → Android → Android Device Monitor. Sau đó,
xuất hiện màn hình Android Device Monitor, chúng ta tìm đến và chọn biểu tượng
Open Perspectives → chọn Hierarchy Viewer → chọn OK.
- Chúng ta có thể sử dụng Hierarchy Viewer để xem cấu trúc giao diện như sau:
o Kết nối thiết bị thật hoặc khởi động thiết bị ảo.
o Mở Hierarchy Viewer.
o Khi ứng dụng vừa chạy ta sẽ thấy danh sách các thiết bị đang kết nối. Lựa chọn
thiết bị muốn kiểm tra và nhấn đôi vào tên gói của ứng dụng muốn xem cấu trúc
giao diện để thấy cấu trúc cây của giao diện ứng dụng đang chạy trên thiết bị.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 51


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.11. Minh họa sử dụng công cụ Hierarchy Viewer

Ngoài ra, ta còn có thể khảo sát được sự phóng to, thu nhỏ của màn hình ( sử dụng công cụ
Pixel Perfect). Công cụ này có ích trong việc phát triển giao diện ứng dụng dòi hỏi độ chính
xác cao về hình ảnh hay tinh chỉnh lại hình ảnh, màu sắc, độ trong suốt cho hợp lý hơn.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 52


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 4
TÀI NGUYÊN ỨNG DỤNG
TRONG ANDROID

1. TỔNG QUAN
1.1. Tài nguyên
- Tài nguyên là một dạng dữ liệu được xây dựng nhằm đáp ứng các yêu cầu về hiển thị
bao gồm hình ảnh, âm thanh, văn bản, các bố cục…tương thích cho từng thiết bị riêng
biệt. Cho phép khai báo một lần và sử dụng trong phạm vi toàn ứng dụng, dễ dàng thay
đổi theo ngữ cảnh.
- Android cung cấp cho chúng ta khá nhiều cách thức để có thể sử dụng đa dạng tài
nguyên như hình ảnh, các chuỗi hằng, chuyển hoạt, bố cục giao diện…mà không cần
phụ thuộc quá nhiều vào các dòng mã lệnh. Điều này giúp chúng ta đơn giản hóa lưu
trữ, quản lý và cập nhật. Trong thiết kế cũng giúp chúng ta linh động hơn trong việc
điều chỉnh cho nhiều thiết bị phần cứng khác nhau.
- Hệ thống tự động tạo thư mục /res dùng để chứa các thư mục của từng loại tài nguyên.
- Các file tài nguyên sẽ được chứa trong các thư mục tùy thuộc vào định dạng của tài
nguyên đó.
- Chúng ta cần tạo ra các thư mục tài nguyên theo đúng định dạng của một ứng dụng
Android. Tài nguyên ứng dụng được định nghĩa trong thư mục res của dự án, bao gồm
các dạng tài nguyên sau:
o Animator: Các dạng tài nguyên chuyển hoạt. (property animation)
o Anim: Các dạng tài nguyên chuyển hoạt. (property animation)
o Color: Các dạng tài nguyên màu sắc.
o Drawable: Các dạng tài nguyên hình ảnh.
o Layout: Các dạng tài nguyên giao diện.
o Menu: Các dạng tài nguyên chỉ mục.
o Raw: Các dạng tài nguyên không biên dịch.
o Values: Các dạng tài nguyên cơ bản. Ví dụ: String, Integer, Boolean…
o XML: Các dạng tài nguyên xml khác.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 53


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.1. Thư mục chứa tài nguyên ứng dụng Android.
1.2. Định nghĩa tài nguyên
- Có quá nhiều thiết bị có cấu hình khác nhau về kích thước màn hình, độ phân giải,
phím vật lý…
- Mỗi thiết bị có thể hoạt động ở nhiều chế độ khác nhau: nằm ngang, nằm đứng, thay
đổi ngôn ngữ…
- Từ hạn định: dùng để tạo ra các tài nguyên khác nhau cho nhiều thiết bị có cấu hình
khác nhau hoạt động ở các chế độ khác nhau. Khi vừa tạo mới một Project, trong thư
mục res ta sẽ thấy có đến bốn thư mục drawable và ba thư mục values chỉ khác nhau ở
phần ngăn cách bởi “-“. Phần hậu tố này chúng ta gọi là từ hạn định, dùng để phân biệt
tài nguyên dành cho các cấu hình khác nhau. Khi ứng dụng được cài lên thiết bị hệ
thống sẽ tự tìm các tài nguyên phù hợp với phần cứng thiết bị đó.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 54


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.2. Ví dụ về từ hạn định.


- Tất cả thư mục tài nguyên đều có thể sử dụng từ hạn định. Bao gồm các từ hạn định
sau:
o MCC/MNC (Mobile Country Code – Mobile Network Code) - các tài nguyên
trong thư mục có từ hạn định này chỉ được dùng cho quốc gia hay nhà cung cấp
dịch vụ mạng nào đó. Để sử dụng chỉ cần khai báo mmc theo sau là chữ số của
quốc gia, hoặc chữ số nhà mạng nếu là mnc. Ví dụ mmc452-mnc04 là Việt Nam
và mạng Viettel, (có thể tham khảo thêm tại trang
http://en.wikipedia.org/wiki/Mobile_network_code ).
o Language/Region – các từ hạn định phân biệt tài nguyên cho các thiết bị các
thiết lập ngôn ngữ khác nhau.Các từ hạn định này bao gồm hai kí tự thường tiêu
chuẩn ISO 639-1 và ISO 3166-1-alpha-2. Ví dụ vn; en; hoặc en-rUS cho tiếng
Anh ở Mĩ, en-rGB tiếng anh ở Anh.
o Smallest Screen Width – từ hạn định cho chiều ngắn nhất của màn hình thiết bị
dùng trong việc thiết kế nhiều giao diện. Ví dụ sw600dp, sw320dp hoặc
sw720dp.
o Available Screen Width/Height – từ hạn định cho chiều ngang và chiều cao tối
thiểu để chứa các tài nguyên được sử dụng khi quay màn hình. Ví dụ w600dp,
h720dp…
o Screen size – được dùng cho để chỉ định các kích thước màn hình khác nhau bao
gồm small (từ HVGA trở xuống), medium (từ HVGA đến VGA), large (VGA
trở lên).
o Screen Aspect Ratio – bao gồm 2 lựa chọn long và notlong để chỉ định các màn
rộng. Ví dụ WVGA là long và QVGA là notlong.
o Screen Orientation – từ hạn định cho biết hướng cầm của thiết bị bao gồm port
(portrait) khi thiết bị đứng và land (landscape) khi thiết bị nằm ngang.
o Dock Mode – bao gồm car chế độ thiết bị dùng cho tình trạng lái xe và desk ở
chế độ thường.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 55


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Screen Pixel Density – mật độ điểm ảnh trên một inch (dpi – dot per inch ).
Dùng để phân biệt các dạng tài nguyên cho các màn hình có độ phân giải khác
nhau bao gồm ldpi (low - 120dpi), mdpi (medium - 160dpi), hdpi (high - 240dpi)
và xhdpi (extra high – 320dpi).
o Touchscreen Type – từ hạn định dành cho các tài nguyên liên quan đến điều
khiển cảm ứng gồm notouch (không hỗ trợ cảm ứng), stylus (dùng bút vẽ) và
finger (cảm ứng điện dung).
o Keyboard Availability - từ hạn định dành cho các tài nguyên liên quan đến bàn
phím nhập liệu gồm keyexposed (bàn phím cứng), keyshidden (bàn phím trượt)
và keysoft (bàn phím ảo).
o Keyboard Input Type - từ hạn định dành cho các tài nguyên liên quan đến kiểu
nhập liệu bao gồm nokeys (không bàn phím), qwerty (bàn phím máy tính cá
nhân) và 12key (bàn phím số).
o Navigation Key Availability – từ hạn định dành cho các tài nguyên liên quan đến
phím điều hướng bao gồm navexposed (phím cứng) và navhidden (phím trượt).
o UI Navigation Type - từ hạn định dành cho các tài nguyên liên quan đến kiểu
điều hướng bao gồm nonav (không hỗ trợ điều hướng), dpad (bàn rê), trackball
(bi lăn) và wheel (bánh xe).
o Platform Version – cho phép chỉ định các tài nguyên chạy trên các phiên bản có
API khác nhau. Ví dụ: v7 chỉ định các phiên bản có API 7 (Android 2.1).
- Chúng ta có thể sử dụng cùng lúc nhiều từ hạn định cho các thư mục tài nguyên khác
nhau và ngăn cách bởi dấu “-“. Tuy nhiên cần lưu ý là các từ hạn định phải theo độ ưu
tiên (trong tài liệu này độ ưu tiên từ trên xuống dưới) và không được phép sử dụng hai
từ hạn định cùng loại ở cùng một thư mục.
- Ví dụ: các thư mục tài nguyên sau là không được phép:
o layout-rUS-en (không theo thứ tự)
o layout-vn-en (hai từ hạn định cùng loại)

- Quy tắc đặt tên thư mục có từ hạn định:


o Có thể sử dụng nhiều từ hạn định trong thư mục lựa chọn, ngăn cách bởi dấu “-”.
 Ví dụ: drawable-en-rUS-land.
o Phải tuân theo quyền ưu tiên từ trên xuống dưới.
 Ví dụ:
 drawable-hdpi-port (Sai)
 drawable-port-hdpi (Đúng)
o Thư mục tài nguyên được lựa chọn không được lồng vào nhau.
 Ví dụ: Không được phép /res/drawable/drawable-en.
o Chỉ một giá trị cho loại từ hạn định được hỗ trợ cho một thư mục.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 56


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Ví dụ: Không được phép drawable-hdpi-mdpi.


o Không phân biệt chữ hoa, chữ thường.

2. TÍNH TƯƠNG THÍCH


- Để có thể tối ưu hóa tính tương thích thiết bị tài nguyên được chia làm hai dạng:
o Tài nguyên mặc định: không quan tâm đến cấu hình của thiết bị hoặc không có
tài nguyên để lựa chọn.
o Tài nguyên đặc trưng: được sử dụng trên thiết bị riêng biệt thông qua các từ hạn
định và đường dẫn.
o Trong quá trình chạy ứng dụng, hệ thống sẽ dò ra cấu hình hiện thời của thiết bị
để lựa chọn tài nguyên phù hợp cho ứng dụng với điều kiện trong ứng dụng có
khai báo nguồn tài nguyên cho thiết bị đó.

Hình 4.3. Lựa chọn tài nguyên thích hợp.

3. TRUY XUẤT TÀI NGUYÊN


- Tất cả tài nguyên ứng dụng được truy xuất thông qua lớp R.
3.1. Lớp R:
- Lớp tĩnh.
- Chứa trong thư mục gen, tự động tạo các định danh cho tài nguyên (ID) thông qua
AAPT (Android Application Project Tool).
- Chứa các lớp tài nguyên, mỗi dạng tài nguyên là một lớp tĩnh.
o Ví dụ:
 Truy xuất tài nguyên hình ảnh:
 Java code: R.drawable.ic_launcher
 XML: @drawable/ic_launcher
- Cú pháp dùng chung khi truy xuất:
o Java Code:
[<package_name.>]R.<resource_type>.<resource_name>

o XML:
@[<package_name.>:]<resource_type>/<resource_name>

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 57


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Trong đó:
 Package_name: tên gói ứng dụng
 Resource_type: dạng tài nguyên
 Resource_name:
 Tên tài nguyên cần truy xuất không bao gồm phần mở rộng tập tin
 Thuộc tính android:name dành cho các tài nguyên cơ bản (string,
color…).
3.2. Tài nguyên Alias
- Tài nguyên Alias cho phép tạo ra tài nguyên từ tài nguyên có sẵn, phục vụ cho nhiều
cấu hình thiết bị nhưng không phải là tài nguyên mặc định.
- Ví dụ:
Vấn đề: tạo biểu tượng ứng dụng khác nhau cho các ngôn ngữ khác nhau, đối với tiếng
Anh và tiếng Việt thì cùng biểu tượng.
o Giải quyết vấn đề (không dùng Alias):
 Tạo thư mục tài nguyên cho từng ngôn ngữ.
 Chép hình ảnh khác nhau cho từng thư mục, hai thư mục có từ hạn định
en và vi có hình ảnh giống nhau.
o Giải quyết vấn đề (dùng Alias):
 Tạo thư mục tài nguyên cho từng ngôn ngữ.
 Chép hình ảnh khác nhau cho từng thư mục.
 Thư mục có từ hạn định en tạo tài nguyên Alias từ thư mục vi.

4. CÁC TÀI NGUYÊN ỨNG DỤNG CƠ BẢN


- Các tài nguyên cơ bản được lưu trữ trong thư mục res/values.
- Định danh tài nguyên được khởi tạo thông qua thuộc tính name, không phải tên tập tin.
- Có thể lưu trữ nhiều tài nguyên vào trong một tập tin.
- Một số tên tập tin đề xuất trong values: string.xml, arrays.xml, colors.xml, dimens.xml,

- Tất cả các tập tin xml trong values, được mở đầu và kết thúc bằng cặp thẻ
<resource></resource>.
4.1. String
- Cung cấp tài nguyên dạng văn bản cho ứng dụng, cho phép thực hiện các thao tác định
dạng và thiết kế khác nhau, bao gồm ba dạng:
o String.
o StringArray.
o QuantityString (Plural).
- Khai báo:
<string name=“string_name”>Text_string</string>

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 58


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Trong đó:
o string_name: định danh dùng để truy xuất trong XML và Java Code.
o text_string: nội dung lưu trữ.
 Ví dụ: tạo tập tin strings.xml
<resource>
<string name=“hello”>Hello world!</string>
</resource>

- Truy xuất và sử dụng:


Khai báo TextView và gắn văn bản cho thuộc tính text.
o Truy xuất trong XML:
<TextView

android:text=“@string/hello” />

o Truy xuất trong Java Code:


 Truy xuất trực tiếp:
textView.setText(R.string.hello);

 Dùng phương thức getString:


textView.setText(getString(R.string.hello));

4.2. Bool
- Cú pháp
<?xml version="1.0" encoding="utf-8"?>
<resources>
<boolname="bool_name">[true | false]</bool>
</resources>

- Ví dụ: res/values-small/bools.xml
<resources>
<bool name="screen_small">true</bool>
<bool name="adjust_view_bounds">true</bool>
</resources>

4.3. Color
- Thư mục tài nguyên:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 59


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

/res/values/filename.xml

- Cú pháp khai báo:


<resources>
<color name=“color_name”>Hexa_color</color>

</resources>

- Tham chiếu tài nguyên trong xml


[pakage]:@color/color_name

- Tham chiếu tài nguyên trong Java code


Resources res = getResources();
int color = res.getColor(R.color.color_name);

4.4. Id
- Thư mục tài nguyên:
/res/values/filename.xml
- Cú pháp khai báo:
<resources>
<item type=“id” name=“id_name”/>

</resources>

- Tham chiếu tài nguyên trong xml:


[package]:@id/id_name

- Tham chiếu tài nguyên trong Java code


TextView tv = (TextView) findViewById(R.id.id_name);

4.5. Dimen
- Khai báo tài nguyên sử dụng cho các đại lượng kích thước trong ứng dụng.
- Có thể sử dụng các đại lượng kích thước sau: dp – dip, sp, pt, px, mm, in.
- Khai báo:
<dimen name=“dimen_name”>size</dimen>

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 60


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Trong đó:
o dimen_name: định danh dùng để truy xuất trong XML và Java Code.
o size: đại lượng đi kèm định dạng
- Ví dụ: tập tin dimens.xml
<?xml version=“1.0” encoding=“utf-8”?>
<resource>
<dimen name=“text_size”>20sp</dimen>
</resource>

- Ví dụ truy xuất và sử dụng: Khai báo Button và thiết lập kích thước văn bản thông qua
thuộc tính textSize.
o Truy xuất trong XML:
<TextView

android:textSize=“@dimen/text_size” />

o Truy xuất trong Java Code: Dùng phương thức getDimension:


Resources res = getResources();
float textSize = res.getDimension(R.dimen.text_size);
textView.setTextSize(textSize);

4.6. Integer
- Thư mục tài nguyên:
/res/values/filename.xml

- Cú pháp khai báo:


<resources>
<integer name=“name”>value</integer>

</resources>

- Tham chiếu tài nguyên trong Java code


Resource res = getResources();
int value = res.getIntegers(R.integer.name);

4.7. Integer Array


- Thư mục tài nguyên:
/res/values/filename.xml

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 61


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Cú pháp khai báo:


<resources>
<integer-array name=“integer_name”>
<item>value1</item>

</integer>
</resources>

- Tham chiếu tài nguyên trong Java code


Resource res = getResources();
int[] value = res.getIntArray(R.array.integer_name);

4.8. Typed Array


- Cú pháp
<resources>
<array name="integer_array_name">
<item>resource</item>
</array>
</resources>

- Ví dụ: res/values/arrays.xml
<resources>
<array name="icons">
<item>@drawable/home</item>
<item>@drawable/settings</item>
<item>@drawable/logout</item> </array>
<array name="colors">

<item>#FFFF0000</item>
<item>#FF00FF00</item>
<item>#FF0000FF</item>
</array>
</resources>

- Tham chiếu tài nguyên trong Java code


Resources res = getResources();
TypedArray icons = res.obtainTypedArray(R.array.icons);
Drawable drawable = icons.getDrawable(0);
TypedArray colors = res.obtainTypedArray(R.array.colors);
int color = colors.getColor(0,0);

5. CÁC TÀI NGUYÊN ỨNG DỤNG NÂNG CAO


5.1. Tài nguyên hình ảnh

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 62


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

5.1.1. Thư mục lưu trữ:


- Các tài nguyên hình ảnh được lưu trữ trong thư mục res/drawable.
- Có thể có nhiều thư mục drawable theo từ hạn định khác nhau.
- Ví du: drawable-hdpi, drawable-xhdpi…
5.1.2. Định dạng:
- Tài nguyên hình ảnh bao gồm cả định dạng *.xml và định dạng hình ảnh (.png, .gif,
.jpg).
5.1.3. Truy xuất: bao gồm 2 cách thức:
- Java: R.drawable.<tên tài nguyên>.
- XML: @[pakage:]drawable/<tên tài nguyên>.
- Ví dụ: truy xuất tài nguyên hình ảnh
o Trong Java Code:
Resources res = getResources();
Drawable drawable = res.getDrawable(R.drawable.ic_launcher);

o Trong XML:
<ImageView
android:layout_width=“50dp”
android:layout_height=“50dp”
android:src=“@drawable/ic_launcher” />
<ImageButton
android:layout_width=“50dp”
android:layout_height=“50dp”
android:background=“@drawable/ic_launcher” />

5.2. Các dạng tài nguyên hình ảnh


5.2.1. Bitmap
- Các thực thi của Bitmap bao gồm:
o Sử dụng như tài nguyên thông qua R.drawable.filename
o Tham chiếu biên dịch tài nguyên thông qua đối tượng BitmapDrawable.
- Các thuộc tính thường sử dụng của Bitmap trong XML:
o AntinAlias (XML)
o Dither
o Filter
o Gravity
o Mipmap
o Tilemode
o Automirrored
- Ví dụ: xây dựng Bitmap trong XML: mipmap.xml

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 63


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:mipMap="false"
android:src="@drawable/caro"
android:tileMode="repeat" > </bitmap>

- Truy xuất trong Java code:


BitmapDrawable drawable = (BitmapDrawable)getResources().
getDrawable(R.drawable.mipmap);

5.3. Shape
- Tài nguyên hình ảnh cho các đối tượng đa giác được vẽ bằng XML, bao gồm:
o Rectangle
o Oval
o Line
o Ring
- Tham chiếu biên dịch tài nguyên thông qua đối tượng GradientDrawable.
- Sử dụng các thuộc tính để cấu tạo đối tượng:
o Corners (Rectangle) - Integer
 radius
 topLeftRadius
 topRightRadius
 bottomLeftRadius
o bottomRadius Padding (Rectangle) – Integer
 left
 top
 right
 bottom
o Gradient
 angle - integer
 centerX - integer
 centerY - integer
 centerColor - integer
 endColor - color
 gradientRadius – integer
 startColor – color
 type – linear | radial | sweep
 useLevel – true | false
o Size – integer
 width – integer

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 64


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 height – integer
 Solid – integer
 color – color
o Stroke – integer
 width - integer
 color – color
 dashWith – integer
 dashGap – integer
o Một số thuộc tính chỉ sử dụng cho đối tượng Ring:
 innerRadius
 innerRadiusRatio
 thickness
 thicknessRatio
 useLevel (false)
- Ví dụ:
<shape xmlns:android=http://schemas.android.com/apk/res/android
android:shape="rectangle" >
<gradient
android:angle="90"
android:startColor="@android:color/holo_blue_bright"
android:type="linear" />
<corners android:radius="20dp"/>

<size
android:height="80dp"
android:width="80dp" />
</shape>

5.4. LayerList
- Tài nguyên hình ảnh cho phép quản lý mảng các đối tượng hình ảnh được vẽ chồng lên
nhau, mỗi đối tượng hình ảnh được qui ước là một item.
- Mỗi item bao gồm:
o drawable – resource
o Id – resource id
o top - integer
o right - integer
o bottom - integer
o left - integer
- Tham chiếu biên dịch tài nguyên thông qua đối tượng LayerDrawable.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 65


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.4. LayerList.


- Ví dụ:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/caro"
android:left="10dp"
android:top="10dp"> </item>
<item android:drawable="@drawable/my_shape"
android:left="30dp"
android:top="30dp"></item>
<item android:drawable="@drawable/chrysanthemum"
android:left="50dp"
android:top="50dp"></item>
</layer-list>

5.5. StateList
- Tài nguyên hình ảnh cho phép quản lý mảng các đối tượng hình ảnh được vẽ theo trạng
thái của đối tượng thể hiện.
- Một item bao gồm: drawable – resource
- Tập các trạng thái có thể có:
o Pressed
o Focused
o Hovered
o Selected
o Checkable
o Enable
o Activated
o Window focused

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 66


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.5. Ví dụ về các trạng thái có thể có của một Checkbox.


- Tham chiếu biên dịch tài nguyên thông qua đối tượng StateListDrawable.
- Ví dụ:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/on"
android:state_pressed="true"></item>
<item android:drawable="@drawable/off" ></item>
</selector>

5.6. LevelList
- Tài nguyên hình ảnh cho phép quản lý mảng các đối tượng hình ảnh, mỗi đối tượng
hình ảnh được qui ước là một item, hiển thị ảnh theo cấp độ tương ứng đã khai báo.
- Một item bao gồm:
o drawable – resource
o maxLevel
o minLevel
- Tham chiếu biên dịch tài nguyên thông qua đối tượng LevelListDrawable.
- Ví dụ:
<?xml version="1.0" encoding="utf-8"?>
<level-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/status_off" android:maxLevel="0" />
<item android:drawable="@drawable/status_on" android:maxLevel="1" />
</level-list>

5.7. Transition
- Tài nguyên hình ảnh cho phép thực hiện chuyển đổi (hiệu ứng “biến bóng”) giữa hai
đối tượng hình ảnh.
- Mỗi item bao gồm:
o drawable – resource

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 67


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Id – resource id
o top - integer
o right - integer
o bottom - integer
o left – integer
- Các phương thức xử lý chính:
o startTransition
o reverserTransition
o resetTransition.
- Ví dụ:
<?xml version="1.0" encoding="utf-8"?>
<transition
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/on" />
<item android:drawable="@drawable/off" />
</transition>

5.8. Inset
- Tài nguyên hình ảnh cho phép thực hiện lồng đối tượng hình ảnh theo một ví trí cho
trước.

Hình 4.6. Inset Drawable.

- Các thuộc tính bao gồm:


o drawable – resource
o insetTop - integer
o insetRight - integer

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 68


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o insetBottom - integer
o insetLeft – integer
- Tham chiếu biên dịch tài nguyên thông qua đối tượng InsetDrawable.
5.9. Clip
- Tài nguyên hình ảnh cho phép thực hiện cắt một đối tượng hình ảnh theo thông số vị trí
cho trước, có thể thay đổi thông số cắt trong quá trình hoạt động.
- Tham chiếu biên dịch tài nguyên thông qua đối tượng ClipDrawable.
- Các thuộc tính bao gồm:
o drawable – resource
o clipOrientation – integer
o Gravity
- Các phương thức xử lý chính:
o setLevel (min:0 – max: 10.000)
o getLevel

Hình 4.7. Ví dụ dùng Clip Drawable để tạo thanh ProgressBar.


5.10. Scale
- Tài nguyên hình ảnh cho phép thực hiện phóng to hoặc thu nhỏ một đối tượng hình ảnh
theo thông số tỉ lệ cho trước, có thể thay đổi thông số tỉ lệ trong quá trình hoạt động.

Hình 4.8. Scale Drawable.


- Các thuộc tính bao gồm:
o drawable – resource
o scaleGravity – integer

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 69


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o scaleWidth - %
o scaleHeight - %
- Tham chiếu biên dịch tài nguyên thông qua đối tượng ScaleDrawable.
5.11. Nine-Patch
- Tài nguyên hình ảnh cho phép thực hiện tạo đối tượng hình ảnh (PNG) có kích thước co
dãn theo tỉ lệ đối tượng thể hiện.

Hình 4.9. Một số hình Nine-Patch.


- Các thuộc tính bao gồm:
o src– resource
o dither– integer
- Tham chiếu biên dịch tài nguyên thông qua đối tượng NinePatchDrawable.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 70


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 5
INTENT

1. KHÁI NIỆM VỀ INTENT


1.1. Cơ chế hoạt động
- Intent được sử dụng để truyền tải thông điệp, yêu cầu một hành động xử lý từ thành
phần được gọi.
- Intent được sử dụng trong ba trường hợp chính:
o Khởi động Activity thông qua phương thức startActivity.
o Khởi động Service thông qua phương thức startService.
o Chuyển thông điệp đến BroadcastReceiver thông qua phương thức
sendBroadcast.
- Intent được chia làm hai dạng:
o Explicit Intent: (Intent tường minh) chỉ định rõ thành phần xử lý thông qua tên
lớp, thường được dùng để gọi đến các thành phần trong cùng ứng dụng.
o Implicit Intent:(Intent không tường minh) không chỉ định rõ thành phần xử lý,
thay vào đó bổ sung các thuộc tính như: mô tả hành động, dạng dữ liệu…
1.2. Xây dựng và truy xuất Intent
- Đối tượng Intent khởi động các thành phần trong ứng dụng đồng thời mang các thông
tin về dữ liệu được xử lý, bao gồm các thành phần sau:
o Component: tên thành phần nhận và xử lý Intent
o Action: hành động yêu cầu thực thi
o Data: dữ liệu yêu cầu nhận và xử lý
o Category: mô tả lĩnh vực hoạt động
o Extras: bộ key/value cho phép gửi nhận thông tin
o Flag: biến cờ mô tả cách thức hoạt động
o Explicit Intent: chỉ cần sử dụng thuộc tính Component.
- Khai báo:
Intent intent = new Intent(this, <Component>);

- Ví dụ: khởi động Activity có tên SecondActivity từ MainActivity


Intent intent = new Intent(MainActivty.this, SecondActivity.class);
startActivity(intent);

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 71


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Implicit Intent: chỉ cần sử dụng thuộc tính Action.


- Khai báo:
Intent intent = new Intent(<Action>);

- Ví dụ: khởi động Activity có thể thực hiện ACTION_VIEW.


Intent intent = new Intent(Intent.ACTION_VIEW);
startActivity(intent);

- Action: một số Action thường dùng trong Intent.


o ACTION_VIEW
o ACTION_DIAL
o ACTION_CALL
o ACTION_EDIT
o ACTION_DELETE
o ACTION_SEND
o ACTION_SENDTO
- Data: một dạng đường dẫn URI, cho phép trỏ đến bảng dữ liệu và truy xuất thông tin
bao gồm:
o type
o scheme
o authority
o path
- Data có thể chỉ định thông qua ba phương thức:
o setData
o setType
o setDataAndType
- Ví dụ: thực hiện cuộc gọi thông qua dữ liệu số điện thoại
Intent callPhone = new Intent(Intent.ACTION_CALL);
callPhone.setData(Uri.parse(“tel:01234-56789”));
startActivity(callPhone);

- Extras: bao gồm biến Bundle chứa các giá trị bổ sung cần thiết cho thành phần nhận xử
lý Intent.
- Có hai cách gửi dữ liệu vào Intent:
o Trực tiếp: dùng phương thức putExtra(Key, Value) thiết lập trực tiếp vào Intent.
o Thông qua Bundle: tạo một đối tượng Bundle, dùng phương thức
set<KDL>(Key, Value) vào đối tượng Bundle. Sau dó, ta dùng phương thức
putExtras() gửi Bundle vào Intent.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 72


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ: gửi số nguyên x vào Intent


o Trực tiếp:
Intent intent = new Intent();
intent.putExtra(“SoNguyenX”, x);

o Thông qua Bundle:


Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt(“SoNguyenX”, x);
intent.putExtras(bundle);

- Truy xuất:
o Truy xuất dữ liệu trực tiếp Extras:
 Dùng phương thức get<KDL>Extra(Key, DefaultValue) để truy xuất dữ
liệu Intent.
o Thông qua Bundle:
 Dùng phương thức getExtras() để truy xuất đối tượng Bundle trong Intent.
 Dùng phương thức get<KDL>(Key, DefaultValue) để truy xuất dữ liệu
trong Bundle.
o Ví dụ: truy xuất số nguyên được gửi trong Intent
 Trực tiếp:
Intent intent = getIntent();
int soNguyenX = intent.getIntExtra(“SoNguyenX”, 0);

 Thông qua Bundle:


Intent intent = getIntent();
Bundle bundle = intent.getExtras();
int soNguyenX = bundle.getInt(“SoNguyenX”, 0);

- Gửi và Phản hồi Intent trong Activity


o Việc gửi và phản hồi Intent trong Activity được chia làm 3 bước
 Bước 1: Gửi Intent thông qua phương thức startActivityForResult() bao
gồm 2 tham số:
 Intent: dữ liệu cần gửi để xử lý.
 requestCode: mã yêu cầu xử lý từ phía gửi.
 Bước 2: Nhận và xử lý Intent, sau đó xác nhận thông tin phản hồi thông
qua phương thức setResult() trong thành phần ứng dụng phản hồi.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 73


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Khởi tạo đối tượng Intent, thiết lập các thuộc tính cần thiết: action,
category…
 Gửi dữ liệu phản hồi trực tiếp vào Intent hoặc thông qua biến
Bundle.
 Gọi phương thức setResult với tham số truyền vào là Intent.
 Bước 3: Gọi phương thức onActivityResult() truy xuất ba tham số:
 requestCode: mã yêu cầu giải quyết với intent tương ứng.
 resultCode: mã kết quả nhận về từ phía phản hồi.
 Intent: dữ liệu nhận về từ phía phản hồi.

Hình 5.1. Gửi và phản hồi Intent.

2. INTENT FILTER
2.1. Mô tả
- Thực hiện mô tả cấu trúc Intent, cho phép thực hiện chỉ nhận các Intent theo đúng cấu
trúc đã mô tả.
- Có thể lọc Intent theo ba thuộc tính:
o Action
o Data (type, scheme, authority & path)
o Category
2.2. Quy tắc thiết lập
- IntentFilter thực hiện lọc Intent theo thứ tự ưu tiên khi có nhiều thuộc tính được thiết
lập và có những qui tắc nhất định:
o Nếu không thiết lập Action, chỉ nhận các Intent không có Action.
o Nếu thiết lập thuộc tính Action và không thiết lập thuộc tính Data, chỉ cho phép
lọc các Intent không có Data.
- IntentFilter cho phép nhận các Intent có bất kỳ dữ liệu nào có liên quan đến thuộc tính
Action.
2.3. Xây dựng IntentFilter
- Có thể khởi tạo đối tượng IntentFilter như sau:
- Trong java Code:
o Các phương thức khởi tạo:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 74


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 IntentFilter()
 IntentFilter(String Action)
 IntentFilter(String Action, URI data)
 IntentFilter(IntentFilter o)
- Trong tập tin AndroidManifest.xml:
o Khai báo thẻ cặp thẻ <intentfilter><intentfilter/>
o Trong cặp thẻ có thể chứa các thẻ sau: <action/>, <data/>, <category/>
2.3.1. Action:
- Các thuộc tính:
<action android:name=“string” />

o Trong đó:
 android:name: sử dụng các thuộc tính trong lớp Intent.ACTION_string
hoặc tự định nghĩa chuỗi action.

- Ví dụ: khai báo:


<action android:name=“android.intent.action.MAIN” />
<action android:name=“com.nghialt.t3h.action.ShowImage” />

2.3.2. Data:
- Các thuộc tính:
<data
android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string" />

- Ví dụ: khai báo:


<data
android:scheme=“http” android:mimeType=”video/mpeg” />
<data android:mineType=“image/*” />
<data android:mineType=“*/*” />

2.3.3. Category
- Các thuộc tính:
<category android:name=“string” />

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 75


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Trong đó:
 android:name: Intent.CATEGORY_string. Khai báo theo cấu trúc
android.intent.category.string

- Ví dụ khai báo:
<category android:name=“android.intent.category.DEFAULT” />
<category android:name=“android.intent.category.LAUNCHER” />

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 76


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 7
CÁC ĐIỀU KHIỂN HIỂN THỊ DANH SÁCH

1. KHÁI NIỆM CƠ BẢN


- Adapter giữ vai trò như cầu nối giữa các đối tượng điều khiển dạng danh sách
(AdapterView) và các dữ liệu bên dưới, cung cấp các phương thức truy xuất dữ liệu.
Cho phép thực hiện quản lý giao diện, số lượng chỉ mục trên AdapterView và thực hiện
truy vấn dữ liệu, sắp xếp dữ liệu. Bên cạnh đó, Adapter cũng chịu trách nhiệm tạo ra
các View con trong tập các dữ liệu.
- AdapterView là các đối tượng điều khiển dạng tập hợp, cho phép hiển thị thông tin cơ
bản theo dạng danh sách và thực hiện quản lý thông tin theo từng mục riêng biệt.

2. CÁC DẠNG ADAPTER


- Bao gồm các lớp thực thi giao thức Adapter:
o ArrayAdapter
o BaseAdapter
o CursorAdapter
o HeaderViewListAdapter
o ResourceCursorAdapter
o SimpleAdapter
o SimpleCursorAdapter
o SpinnerAdapter
- Các phương thức xử lý quan trọng trên Adapter:
o getCount - int
o getItems(int position) - Objects
o getItemsId(int position) – long
o getView(int position, View convertView, ViewGroup parent) – View

2.1. BaseAdapter
- BaseAdpater là lớp adpater cơ sở cho các Adapter thường dùng khác như
ArrayAdapter<T>, CursorAdapter, SimpleAdapter…
- Ví dụ:
o Tạo một ArrayAdapter chứa các dữ liệu chuỗi.
String arr[]={"One","Two","Three","Four"};
ArrayAdapter<String> adapter = new
ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, arr));

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 85


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Trong đó:
 android.R.layout.simple_list_item_1: là layout mặc định do Android xây
dựng sẵn cho 1 item của ListView.
- Tuy nhiên, nếu muốn sử dụng với những giao diện phức tạp hơn như ImageView, hoặc
nhiều TextView ta nên ghi đè lại getView (int, View, ViewGroup) để trả lại kiểu giao
diện mà bạn muốn.
2.2. SimpleCursorAdapter
- SimpleCursorAdapter là lớp Adapter lấy dữ liệu từ một Cursor ra một điều khiển hiển
thị ví dụ ListView, GridView, ... Cursor phải có chứa tên định danh cho các cột, nếu
không sẽ không thực hiện được.

3. CÁC ĐIỀU KHIỂN DANH SÁCH


3.1. AbsListView
- AbsListView: đối tượng điều khiển hiển thị danh sách các danh mục với thông tin cơ
bản, cho phép thực hiện các thao tác khác nhau trên từng danh mục. Bao gồm hai chế
độ hiển thị:
o ListView
o GridView
- Thuộc tính XML quan trọng:
o listSelector: drawable
o choiceMode: none | singleChoice | multipleChoice | multipleChoiceModal
o smoothScrollBar: boolean
o fastScrollEnable: boolean
- Một số Interface đã được khai báo sử dụng :
o TextWatcher
o ViewTreeObserver.OnGlobalLayoutListener
o ViewTreeObserver.OnTouchModeChangeListener
o Filter.FilterListener
3.2. Listview
- ListView là một dạng điều khiển nâng cao có chức năng hỗ trợ hiển thị dữ liệu theo
dạng từng dòng. ListView cần một đối tượng Adapter để quản lý và giúp hiển thị dữ
liệu.
- ArrayAdapter là gì?
o ArrayAdapter được hiểu như cái modem mạng. Nó giúp ListView có thể “đọc và
hiểu” dữ liệu từ mảng dữ liệu để hiện lên giao diện.
o ArrayAdapter là một lớp kế thừa từ BaseAdapter và được hỗ trợ bởi một mảng
các đối tượng tùy ý. Mặc định lớp này sẽ được cung cấp Id tham chiếu đến một
TextView duy nhất để làm điều khiển hiển thị dữ liệu.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 86


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Các bước để tạo một ListView


o Bước 1: Đưa dữ liệu cần hiển thị lên ListView vào một mảng hoặc danh sách
(ArrayList, mảng thông thường, mảng đối tượng,…).
o Bước 2: Tạo một ListView trên giao diện.
o Bước 3: Tạo một đối tượng ArrayAdapter để liên kết giữ ListView và mảng hoặc
danh sách dữ liệu.
- Các xử lý trên ListView
o Cách lấy ListView thông qua Id của ListView
ListView lvTenLV=(ListView)findViewById(R.id.idcuaListView);

o Cách tạo ArrayAdapter và đưa dữ liệu từ mảng vào ArrayAdapter


ArrayAdapter<[Kiểu mảng]>[Tên mảng adapter]
= new ArrayAdapter<Kiểumảng>
(this,android.R.layout.simple_list_item_1, [tenMangDuLieu]);

- Dữ liệu từ mảng chứa dữ liệu sẽ được gắn vào ArrayAdapter, ArrayAdapter sẽ gắn vào
ListView.
- Giải thích ý nghĩa các đối số trong phương thức ArrayAdapter:
o Đối số thứ 1: this
 Đại diện cho context của Activity hiện tại, bạn có thể viết
MainActivity.this (nếu bạn viết như thế này thì ở bất kỳ vị trí nào nó cũng
hiểu là context của MainActivity).
o Đối số thứ 2: android.R.layout.simple_list_item_1
 Là layout Listview mà được Android xây dựng sẵn. Nó được lưu trong
SDK/ platforms/ android-api(x)/ data/ res/ layout/
simple_list_item_1.xml.
o Đối số thứ 3: [tenMangDuLieu]
 Là mảng chứa dữ liệu cần hiển thị lên ListView.
- Thuộc tính XML quan trọng:
o listSelector: drawable
o divider: drawable
o dividerHeight: dimen
o entries: string-array
- Một số phương thức quan trọng:
o setAdapter(Class Extends <T implements Adapter>)
o addHeaderView(View) – removeHeaderView(View)
o addFooterView(View) – removeFooterView(View)
o setSelection(int)
o smoothScrollToPosition(int)

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 87


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ: Tạo ListView hiển thị danh sách tên các quốc gia.
Bước 1: Tạo dữ liệu
- Chúng ta tạo mảng dữ liệu để hiển thị trên listview thông qua một tập tin xml bằng cách
tạo mới một tập tin list_data.xml trong / res/ values với nội dung sau:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="countries">
<item>Sri Lanka</item>
<item>Tokelau</item>
<item>United Kingdom</item>
<item>Uruguay</item>
<item>Vatican</item>
<item>Vietnam</item>
</string-array>
</resources>

Bước 2: Tạo một ListView trên giao diện


- Kéo vào một ListView trong thẻ tab Composite hoặc khai báo 1 cặp thẻ <listview>
trong file giao diện xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lvCountry"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>

Bước 3: Đưa dữ liệu vào mảng, tạo đối tượng ArrayAdapter, đưa dữ liệu từ mảng vào
ArrayAdapter, hiển thị nội dung lên ListView
- Chúng ta vào Activity để thao tác như sau:
//Đưa dữ liệu v{o mảng
String[] countries = getResources().getStringArray(R.array.countries);
//lấy listview thông qua id của listview
ListView lvCountry=(ListView)findViewById(R.id.lvCountry);
//Tạo đối tượng ArrayAdapter v{ đưa dữ liệu từ mảng v{o ArrayAdapter
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(this,android.R.layout.simple_list_item_1, countries);
//đổ dữ liệu lên listview
lvCountry.setAdapter(adapter);

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 88


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bước 4: Thiết lập sự kiện cho ListView


- Sau khi dữ liệu đã được hiển thị lên ListView, tiếp theo, để bắt sự kiện khi click lên
mỗi dòng của listview, chúng ta gán sự kiện setOnItemClickListener cho ListView
như sau:
lvCountry.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> adapterView, View v, int position,long
id) {
//Ghi Log vị trí của Item được click v{o trên ListView
Log.d("ListView","onItemClick-POS:"+position+ "+ID+"+id);
}
});

Cách khác: chúng ta còn có thể thiết lập sự kiện trên cho listView bằng cách cho Activity kế
thừa lớp ListActivity để trở thành một Activity dạng list:
public class ListViewActivity extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] countries =getResources().getStringArray(R.array.countries);
setListAdapter(new ArrayAdapter<String>
(this,android.R.layout.simple_list_item_1,android.R.id.text1,countries));
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {
// Ghi log
Log.d("ListView","onItemClick- POS :" +position+"+ ID : " +id);
}
});
}
}

3.3. GridView
- GridView giống với ListView nhưng có chức năng hỗ trợ hiển thị dữ liệu theo dạng
lưới. GridView cũng cần một đối tượng Adapter để quản lý và giúp hiển thị dữ liệu.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 89


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 7.1. Ví dụ về Custom GridView.

- Gridview cũng dựa vào Adapter để gắn kết các dữ liệu bên dưới.
String[] adobe_products =
getResources().getStringArray(R.array.adobe_products);
GridView gvAdobe = (GridView) findViewById(R.id.gvAdobe);

ArrayAdapter<String> adapter = new ArrayAdapter<String>


(ListViewActivity.this,android.R.layout.simple_list_item_1, adobe_products);
gvAdobe.setAdapter(adapter);

- Điểm khác nhau là GridView có thiết lập số cột. Dữ liệu luôn đưa vào dưới dạng hình
ống (mảng, list một chiều), nhưng dựa vào số cột ta thiết lập mà nó tự động ngắt hàng
dựa vào thuộc tính numColums trong layout.
<GridView
android:id="@+id/gvAdobe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="3" >
</GridView>

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 90


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Thuộc tính XML quan trọng:


o columnWidth: dimen
o gravity: Gravity
o horizontalSpacing: dimen
o verticalSpacing: dimen
o numColumns: integer
o strecthMode: none | spacingWidth | columnWidth | spacingWidthUniform
- Một số phương thức quan trọng:
o setColumnWidth(int) – getColumnWidth()
o setNumColumn(int) – getNumColumn()
o setSelection(int)
o smoothScrollToPosition(int)

3.4. Spinner
- Spinner là đối tượng điều khiển hiển thị một danh mục ở một thời điểm, người dùng có
thể lựa chọn một trong nhiều danh mục để hiển thị.
- Bao gồm hai chế độ hiển thị pop-up lựa chọn (spinnerMode):
o Dialog
o Dropdown

Hình 7.2. Hai chế độ hiển thị dữ liệu vời Spinner.


- Thuộc tính XML quan trọng:
o spinnerMode: dialog | dropdown
o prompt: string
o popupBackground: drawable | color
o gravity
o entries: string-array

- Một số phương thức quan trọng:


o setAdapter(SpinnerAdapter)
o setPrompt(CharSequence) – setPrompt(int resId) (Dialog Mode)

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 91


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o setPopupBackgroundResource(int)
o setPopupBackgroundDrawable(Drawable)

- Ví dụ: xây dựng Spinner:


// X}y dựng Adapter thông qua dữ liệu t{i nguyên v{ giao diện mẫu
SpinnerAdapter adapter = new ArrayAdapter.createFromResource(this,

R.array.countries,

android.R.layout.simple_dropdown_item_1line);
// Tham chiếu điều khiển
Spinner spinner = (Spinner)findViewById(R.id.spinner);
// Thiết lập Adapter cho điều khiển
spinner.setAdapter(adapter);

3.5. Tạo Custom ListView


- Trong thực tế, các ứng dụng Android có liên quan đến ListView thì đa phần chúng ta
phải điều chỉnh lại layout cho đúng với yêu cầu của khách hàng. Và cách điều chỉnh lại
layout là tạo Custom Layout cho ListView. Vì vậy, học cách tạo Custom Layout cho
ListView là cần thiết và thực thế.
- Sự khác nhau giữa ListView thông thường và ListView có layout được điều chỉnh lại là
ở việc khởi tạo Adapter.
- Sau khi đã có ListView trên giao diện, chúng ta có thể tạo Custom Layout cho
ListView như sau:
Bước 1: Tạo thêm một layout cho một item của ListView.
Bước 2: Tạo lớp Custom Adapter kế thừa từ lớp ArrayAdapter.
Bước 3: Tạo một lớp dùng để quản lý dữ liệu.
Bước 4: Hiển thị dữ liệu lên ListView.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 92


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Sri Lanka

Tokelau

United Kingdom

Uruguay

Vatican

VietNam

Hình 7.3. Minh họa Custom ListView.

Sau đây là ví dụ về cách tạo Custom Layout cho ListView (lấy ví dụ ở phần III.1).
- Tạo layout trong Activity như sau:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="nghialt.demo.democustomlistview.MainActivity" >

<ListView
android:id="@+id/lvCountries"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</RelativeLayout>

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 93


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Tạo layout cho một item của ListView gọi là list_row.xml


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

<ImageView
android:id="@+id/imgvFlag"
android:layout_width="80dp"
android:layout_height="80dp"
android:contentDescription="@null"
android:src="@drawable/flag_japan" />

<LinearLayout
android:layout_width="120dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="20dp"
android:padding="10dp" >

<TextView
android:id="@+id/tvEnName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@null"
android:textColor="#357B6A"
android:textAppearance="?android:attr/textAppearanceMedium" />

<TextView
android:id="@+id/tvViName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@null"
/>
</LinearLayout>

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >

<CheckBox
android:id="@+id/checkBox1"
android:layout_width="wrap_content"

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 94


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp" />

</RelativeLayout>

</LinearLayout>

- Custom lại Adapter bằng cách tạo một class kế thừa từ class ArrayAdapter gọi là
CountryAdapter
public class CountryAdapter extends ArrayAdapter<Country> {

Context context;
int resId;
ArrayList<Country> countries;

public CountryAdapter(Context context, int resId,


ArrayList<Country> countries) {
super(context, resId, countries);
this.context = context;
this.resId = resId;
this.countries = countries;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

view = inflater.inflate(resId, null);

TextView tvEnName = (TextView) view.findViewById(R.id.tvEnName);


TextView tvViName = (TextView) view.findViewById(R.id.tvViName);
ImageView imgvFlag = (ImageView) view.findViewById(R.id.imgvFlag);

Country c = countries.get(position);
if (c != null) {
tvEnName.setText(c.getEnName());
tvViName.setText(c.getViName());
imgvFlag.setImageResource(c.getImg_id());
}
return view;
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 95


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Xây dựng đối tượng Country:


public class Country {
private String enName;
private String viName;
private int img_id;
public String getEnName() {
return enName;
}
public void setEnName(String enName) {
this.enName = enName;
}
public String getViName() {
return viName;
}
public void setViName(String viName) {
this.viName = viName;
}
public int getImg_id() {
return img_id;
}
public void setImg_id(int img_id) {
this.img_id = img_id;
}
public Country(String enName, String viName, int img_id) {
this.enName = enName;
this.viName = viName;
this.img_id = img_id;
}
public Country() {
// TODO Auto-generated constructor stub
}
}

- Tạo class CountryModel để quản lý dữ liệu:


public class CountryModel {

public static String[] en_countries = new String[] { "Vietnam", "France",


"Belgium", "Italy", "Germany", "Spain", "Japan", "Laos" };

public static String[] vi_countries = new String[] { "Việt Nam", "Ph|p",


"BỈ", "Ý", "Đức", "T}y Ban Nha", "Nhật Bản", "L{o" };

public static int[] img_ids = new int[] { R.drawable.flag_vietnam,


R.drawable.flag_france, R.drawable.flag_belgium,
R.drawable.flag_italy, R.drawable.flag_germany,
R.drawable.flag_spain, R.drawable.flag_japan, R.drawable.flag_laos };

private static ArrayList<Country> countries;

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 96


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

public static ArrayList<Country> getCountries() {


if (countries == null) {
CountryModel countryModel = new CountryModel();
countryModel.initCountryList();
}
return countries;
}

private void initCountryList() {

countries = new ArrayList<Country>();


for (int i = 0; i < en_countries.length; i++) {
Country c = new Country(en_countries[i], vi_countries[i],
img_ids[i]);
countries.add(c);
}}
}

- Tạo và setAdapter cho ListView trong MainActivity


public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ListView lvCountries = (ListView) findViewById(R.id.lvCountries);

ArrayList<Country> countries = CountryModel.getCountries();

CountryAdapter countryAdapter = new CountryAdapter(this,


R.layout.my_item_layout, countries);
lvCountries.setAdapter(countryAdapter);
}
}

3.6. AutoCompleteTextView
- Đối tượng kế thừa từ EditText.
- Cho phép xây dựng dữ liệu mẫu hỗ trợ người dùng hoàn chỉnh quá trình nhập liệu trên
EditText.
- Thực hiện xây dựng AutoCompleteTextView:
- Khai báo dữ liệu mẫu.
- Khai báo giao diện hiển thị cho dữ liệu.
- Xây dựng Adapter thông qua phương thức khởi tạo tương ứng với dữ liệu và giao diện
hiển thị.
- Thiết lập Adapter cho đối tượng AutoCompleteTextView

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 97


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 7.4. Minh họa AutoComplexTextView.

- Ví dụ xây dựng AutoCompleteTextView:


// Khởi tạo dữ liệu mẫu
private static final String[] COUNTRIES = new String[]
{“VietNam”, “Belgium”, “France”, “Italy”, “Germny”, “Spain”};
// X}y dựng Adapter thông qua dữ liệu mẫu v{ giao diện mẫu
ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
android.R.layout.simple_dropdown_item1line, COUNTRIES);
// Tham chiếu điều khiển
AutoCompleteTextView editCountry = (AutoCompleteTextView)
findViewById(R.id.editCountry);
// Thiết lập Adapter cho điều khiển
editCountry.setAdapter(adapter);

3.7. MultiAutoCompleteTextView
- Đối tượng kế thừa từ đối tượng AutoCompleteTextView.
- Cho phép xây dựng dữ liệu mẫu hỗ trợ người dùng hoàn chỉnh quá trình nhập liệu trên
EditText.
- Dữ liệu được hỗ trợ hoàn chỉnh nhiều lần, cách nhau bằng một Tokenizer.
- Thực hiện xây dựng MultiAutoCompleteTextView:
- Khai báo dữ liệu mẫu.
- Khai báo giao diện hiển thị cho dữ liệu.
- Xây dựng Adapter thông qua phương thức khởi tạo tương ứng với dữ liệu và giao diện
hiển thị.
- Thiết lập Adapter cho đối tượng MultiAutoCompleteTextView.
- Thiết lập đối tượng Tokenizer.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 98


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ xây dựng MultiAutoCompleteTextView:


// Khởi tạo dữ liệu mẫu
private static final String[] COUNTRIES = new String[]
{“VietNam”, “Belgium”, “France”, “Italy”, “Germny”, “Spain”};
// X}y dựng Adapter thông qua dữ liệu mẫu v{ giao diện mẫu
ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
android.R.layout.simple_dropdown_item1line, COUNTRIES);
// Tham chiếu điều khiển
MultiAutoCompleteTextView editCountry = (MultiAutoCompleteTextView)
findViewById(R.id.editCountry);
// Thiết lập Adapter cho điều khiển
editCountry.setAdapter(adapter);
// Thiết lập Tokenizer
editCountry.setTokenize(new MultiCompleteTextView.CommaTokenizer());

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 99


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 6
QUẢN LÝ ASSET –
SHARED PREFERENCES –
BỘ NHỚ THIẾT BỊ

1. BỘ QUẢN LÝ ASSET
1.1. Giới thiệu
- Asset là thư mục chứa dữ liệu đầu vào. Ví dụ: âm thanh, hình ảnh, tập tin CSDL hoặc
tập tin có đuôi khác ... Những tập tin này sẽ không được biên dịch khi ứng dụng được
đóng gói.

Hình 6.1. Thư mục assets.

- Truy xuất đối tượng quản lý: getAssets() – AssetManager


- Các phương thức xử lý chính:
o list(String path) – String[]
o open(String fileName) – InputStream
o open(String fileName, int mode) – InputStream
o close()
- Các chế độ mở Asset
o ACCESS_BUFFER
o ACCESS_RANDOM
o ACCESS_STREAMING
o ACCESS_UNKNOWN
- Để truy xuất được những tập tin trong thư mục assets, ta phải sử dụng bộ quản lý asset
do Android cung cấp. Lớp này tên là AssetManager.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 77


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- AssetManager là lớp cung cấp quyền truy cập vào các tập tin không biên dịch của ứng
dụng. AssetManager cho phép bạn mở và đọc file nguyên gốc dưới dạng một luồng
byte.
- Cú pháp khởi tạo AssetManager:
AssetManager assetManager = Context.getAssets();

- Để truy xuất phông chữ thông qua thư mục Asset ta sử dụng phương thức
createFromAsset.
- Ví dụ:
Typeface arial = Typeface.createFromAsset(getAssets(), “font/arial.ttf”);
textView.setTypeface(arial);

1.2. Đọc dữ liệu Asset


- Ví dụ sau đây sẽ cho ta cái nhìn tổng quát về cách thức sử dụng bộ quản lý asset để truy
xuất tài nguyên tập tin trên thư mục dự án.
- Ta có thư mục assets với các tập tin như Hình 6.1.
- Xây dựng Activity với giao diện layout như sau:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
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"
android:id="@+id/txtContent" />
<ImageView
android:layout_width="fill_parent"

android:layout_height="wrap_content"
android:id="@+id/imgAssets"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/txtFileName" />
</LinearLayout>
</ScrollView>

- Trong Activity tiến hành đọc dữ liệu asset:


public class ReadFileAssetsActivity extends Activity {
@Override

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 78


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

public void onCreate(Bundle savedInstanceState) {


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

TextView txtContent = (TextView) findViewById(R.id.txtContent);


TextView txtFileName = (TextView) findViewById(R.id.txtFileName);
ImageView imgAssets = (ImageView) findViewById(R.id.imgAssets);

AssetManager assetManager = getAssets();

// To get names of all files inside the "Files" folder


try {
String[] files = assetManager.list("Files");
for(int i=0; i<files.length; i++){
txtFileName.append("\n File :"+i+" Name => "+files[i]);}
} catch (IOException e1) {
e1.printStackTrace();
}
// To load text file
InputStream input;
try {
input = assetManager.open("helloworld.txt");
int size = input.available();
byte[] buffer = new byte[size];
input.read(buffer);

input.close();
// byte buffer into a string
String text = new String(buffer)
txtContent.setText(text);
} catch (IOException e) {
e.printStackTrace();
}
// To load image
try {
InputStream ims = assetManager.open("android_logo_small.jpg");

// create drawable from stream


Drawable d = Drawable.createFromStream(ims, null);
// set the drawable to imageview
imgAssets.setImageDrawable(d);
}catch(IOException ex) {
return;
}
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 79


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2. SHARED PREFERENCES
2.1. Giới thiệu
- Shared Preferences là một dạng lưu trữ nhanh bằng file XML.
- SharedPreferences dùng lưu trữ dữ liệu dạng cơ bản.
- Chỉ hỗ trợ một số kiểu dữ liệu cơ bản : booleans, float, int, long, string.
- Hoạt động theo kiểu lưu trữ cũng như truy xuất thông qua cặp giá trị key/value.
- Dữ liệu vẫn được bảo toàn ngay cả khi ứng dụng bị đóng hoàn toàn.
- Các dữ liệu được lưu trữ và truy xuất qua từng phiên (Session) tương tác của ứng dụng
với người dùng.
- Lưu trữ và truy xuất trạng thái ứng dụng
2.2. Lưu trữ
- Sử dụng đối tượng của lớp SharedPreferences thông qua phương thức:
GetSharedPreferences(String, int);
- Tạo đối tượng SharedPreferences: sử dụng phương thức getSharedPreferences().

SharedPreferences sharedPre = getSharedPreferences(PREFS_NAME,mode);

o Trong đó:
 PREFS_NAME: tên của sharedPreference cần tạo
 Mode: kiểu ghi dữ liệu
 MODE_PRIVATE: mode ghi mặc định, chỉ có duy nhất ứng dụng tạo ra
tập tin được phép truy cập vào.
 MODE_WORLD_READABLE: cho phép các ứng dụng khác truy cập
vào.
 MODE_WORLD_WRITEABLE: cho phép các ứng dụng khác truy cập
và sửa đổi.
 MODE_MULTI_PROCESS: cho phép nhiều tiến trình trên ứng dụng
cùng truy xuất vào cùng một thời điểm.
- Bổ sung thông tin cho đối tượng SharedPreferences: thông qua đối tượng Editor và
put<Type> tùy theo dữ liệu.
- Tạo đối tượng Editor từ phương thứ edit() của Preference.
- Các giá trị lưu trữ được truy xuất thông qua phương thức get<KDL>:
o getBoolean(Key, DefValue)
o getFloat(Key, DefValue)
o getInt(Key, DefValue)
o getLong(Key, DefValue)
o getString(Key, DefValue)

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 80


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ:
SharedPreferences.Editor editor = sharedPre.edit();
editor.putBoolean(“isTrue”, true);
editor.putFloat(“lastFloat”, 1f);
editor.putInt(“number”, 2);
editor.putLong(“aNumber”, 3l);
editor.putString(“textEntryValue”, “Not Empty”);
//Sau cùng, để lưu SharedPreference dùng lệnh commit()
editor.commit();

2.3. Truy xuất


- Các định dạng mở tập tin khi truy xuất Preference:
o MODE_PRIVATE
o MODE_APPEND
o MODE_WORLD_READABLE (Deprecated in API 17)
o MODE_WORLD_WRITEABLE (Deprecated in API 17)
o MODE_MULTI_PROCESS
- Các giá trị lưu trữ được truy xuất thông qua phương thức get<KDL>:
o getBoolean(Key, DefValue)
o getFloat(Key, DefValue)
o getInt(Key, DefValue)
o getLong(Key, DefValue)
o getString(Key, DefValue)

- Lấy dữ liệu trong SharedPreferences(): sử dụng phương thức get<Type> tùy theo từng
loại dữ liệu.
boolean isTrue = sharedPre.getBoolean(“isTrue”, false);
float lastFloat = sharedPre.getFloat(“lastFloat”, 0f);
int number = sharedPre.getInt(“number”, 1);
long aNumber = sharedPre.getLong(“aNumber”, 0);
String stringPreference = sharedPre.getString(“textEntryValue”, “”);

- Giá trị mặc định: là giá trị sẽ được trả về mặc định khi get<Type> không trả về được
value thích hợp từ key truyền vào.
o Ví dụ:
//Nếu không tìm thấy giá trị tương ứng với từ khóa “number” truyền vào thì
Default Value là 1
int number = sharedPre.getInt(“number”, 1);

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 81


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

3. BỘ NHỚ THIẾT BỊ
3.1. Bộ lưu trữ trong
- Lưu dữ liệu riêng trên bộ nhớ thiết bị.
- Khi ứng dụng được cài đặt, hệ thống cung cấp 1 vùng bộ nhớ trong dành cho việc lưu
trữ dữ liệu cho mỗi ứng dụng riêng (sandbox).
- Khi người dùng gỡ bỏ ứng dụng, vùng bộ nhớ này sẽ được xóa.
- Chỉ có ứng dụng mới có thể truy xuất được bộ nhớ của ứng dụng đó.

- Đường dẫn các tập tin được lưu trữ:


data/data/<pakage_name_app>/files

- Phương thức truy xuất:


getFilesDir - File

- Tạo và lưu trữ file vào bộ lưu trữ trong


o Gọi openFileOutput() với tên file và chế độ truy cập file.
o Ghi lên file sử dụng phương thức write().
o Đóng stream với phương thức close().
o Đọc file từ bộ lưu trữ trong.
o Gọi openFileInput() với tên file cần đọc.
o Đọc nội dụng từ file sử dụng phương thức read().
o Đóng stream với phương thức close()
o Ví dụ:
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStreamfos = openFileOutput(FILENAME,Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

3.2. Bộ lưu trữ ngoài


- Mỗi thiết bị Android cung cấp bộ nhớ ngoài cho phép người dùng có thể lưu trữ và truy
xuất trực tiếp trên thiết bị hoặc thông qua máy tính khi kết nối USB Storage. Hay nói
cách khác, mỗi thiết bị Android có thể hỗ trợ bộ lưu trữ ngoài sử dụng lưu file (như là
SDcard).
- Lưu trữ dữ liệu public trên bộ nhớ ngoài.
- Bộ lưu trữ ngoài bao gồm hai dạng:
o Bộ nhớ thiết bị (non-removable)
o Bộ nhớ ngoài (sd-card, usb…)

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 82


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Cần xin cấp quyền để truy xuất bộ nhớ này:


android.permission.WRITE_EXTERNAL_STORAGE

- Ứng dụng được cấp phát bộ nhớ ngoài để lưu trữ dữ liệu, mặc định không thể truy xuất
như tập tin Media.
- Địa chỉ lưu trữ:
/mnt/sdcard/Android/<package_name>/files

- Phương thức truy xuất:


o getExternalFilesDir(String) – File
o getExternalFilesDirs(String) – File[] (API 19 - KITKAT)
o ContextCompat.getExternalFilesDirs(String) – File[] (Support Library)
- Cấu hình cài đặt ứng dụng trên bộ nhớ trong hoặc ngoài thông qua cặp thẻ <manifest/>
trong AndroidManifest.
o installLocation
o internalOnly
o Auto
o preferExternal
- Dữ liệu được lưu trữ trên bộ lưu trữ ngoài có thể được thay đổi bởi người dùng, có thể
đồng bộ với máy tính cá nhân.
- Trước khi làm việc với bộ lưu trữ ngoài cần kiểm tra trạng thái của nó trước khi thực
hiện các thao tác.
- Truy xuất trạng thái bộ nhớ ngoài thông qua phương thức getExternalStorageState
trong đối tượng Environment.
- Các thông số được trả về bao gồm:
o MEDIA_UNKNOWN
o MEDIA_REMOVED
o MEDIA_UNMOUNTED
o MEDIA_CHECKING
o MEDIA_NOFS
o MEDIA_MOUNTED
o MEDIA_MOUNTED_READ_ONLY
o MEDIA_SHARED
o MEDIA_BAD_REMOVAL
o MEDIA_UNMOUNTABLE

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 83


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ: kiểm tra trạng thái bộ lưu trữ ngoài


public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if( Environment.MEDIA_MOUNTED.equals(state))
return true;
return false;
}

- Một số phương thức hỗ trợ duyệt tập tin trong bộ nhớ:


o isFile() – boolean
o isDirectory() – boolean
o getAbsolutePath() - String
o getPath() - String
o list() – String[]
o mkdir() - boolean
o mkdirs() – boolean
o delete() – boolean

- Một số thư mục dùng chung:


o Thư mục:
 DIRECTORY_ALARMS
 DIRECTORY_DCIM
 DIRECTORY_DOCUMENTS (API 19)
 DIRECTORY_DOWNLOADS
 DIRECTORY_MOVIES
 DIRECTORY_MUSIC
 DIRECTORY_NOTIFICATIONS
 DIRECTORY_PICTURES
 DIRECTORY_POSTCASTS
 DIRECTORY_RINGTONES

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 84


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 8
XÂY DỰNG GIAO DIỆN VỚI FRAGMENT
VẤN ĐỀ ACTIVITY VÀ FRAGMENT

1. NỆ N
1.1. r gment v phi n n h tr
- r gment đư c giới thiệu trong phiên b n Android 3.0 Honeycom , tuy nhi n do đư c
h tr trong gói Android Support Library nên ta có thể sử dụng trong các phiên b n từ
Android 1.6 trở lên.
- r gment l đối tư ng đư c nhúng trong Activity, cho phép thực hiện nhận tương tác,
có vòng đời riêng và thực hiện trao đổi thông tin với Activity và các Fragment khác.
- Yếu tố chính trong việc sử dụng Fragment là nó có thể giúp chúng ta xây dựng các giao
diện một cách chủ động và linh hoạt để có thể thích ứng với các kiểu màn hình có kích
thước khác nhau từ điện thoại cho đến máy tính b ng, nói chính xác hơn l tối ưu hó
giao diện cho từng loại thiết bị, kích thước v độ phân gi i.

Hình 8.1. Xây dựng giao diện ứng dụng trên điện thoại với Fragment.

- Tính linh động của Fragment cho phép chúng ta bố cục lại các phần giao diện của một
ứng dụng theo cách h p lý nhất.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 100
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 8.2. Xây dựng giao diện ứng dụng trên máy tính bảng với Fragment.

- M i Fragment sẽ không bị bó buộc trong một Activity nhất định và có thể tái sử dụng
nhiều lần, giúp chủ động hơn trong việc xây dựng giao diện từ việc thêm hoặc xóa các
thành phần vào các cửa sổ khác nhau.
- Các lớp Fragment:
- Fragment
o ListFragment
o DialogFragment
o PreferenceFragment
o WebViewFragment

- Trong bộ Android SDK tích h p một số lớp con từ lớp r gment cho phép đóng gói v
thực thi một số r gment thường dùng. Ta có thể liệt kê một số lớp như s u:
- DialogFragment – Fragment cho phép thể hiện ở dạng hộp thoại trên Activity. Chúng ta
có thể thực hiện các tùy chỉnh về giao diện cho Fragment dạng này thông qua các
phương thức có sẵn trong lớp Fragment.
- ListFragment – dạng Fragment tích h p sẵn điều khiển ListView v các phương thức
dùng để thực kết nối dữ liệu.
- WebViewFragment – dùng để hiện các kết nối và hiển thị nội dung tr ng we tr n đối
tư ng WebView.
1.2. i o diện
- Để tạo mới đối tư ng Fragment ta cần tạo lớp kế thừa từ lớp Fragment, khai báo các
điều khiển và thực thi các chức năng.
- Hầu như khi l m việc với Fragment, ta cần tạo ra các giao diện cho nó bằng cách gắn
các điều khiển, tuy nhi n t cũng có thể cung cấp giao diện cho Fragment một cách trực
tiếp từ XML giống như t l m việc với Activity bằng phương thức setContentView().
- Các thuộc tính quan trọng:

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 101
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o class: <Class extends Fragment> (Pakage Name + Class Name).


o name: <Class extends Fragment> (Pakage Name + Class Name).
o id: Identifier Resource.
o tag: String Resource.
o layout_width – layout_height: Dimen.
o layout_weight: Integer.
o lauout_gravity: Gravity.
o layout_margin<Postion>: Dimen.

Ở đây, t có thể dùng phương thức onCre teView() để thực hiện điều tương tự.
public class MyFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container,Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_main, container, false);
}
}

- Ví dụ: giao diện Fragment trong XML:


fragment_layout.xml:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
class=“com.htsi.demofragment.ImageFragment”
android:id=“@+id/imageFragment”
android:tag=“ImageFramgent”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:layout_margin=“@dimen/marginFragment” />

- Sử dụng trong M inActivity.j v như một l yout ình thường:


setContentView(R.layout.fragment_layout);

- Chúng ta hoàn có thể xây dựng giao diện trong mã J v thông qu đối tư ng
ViewGroup, tuy nhiên cách tốt hơn hết là dùng xây dựng tập tin giao diện XML và gán
vào Fragment.
- Không giống như Activity, r gment không cần ph i khai báo trong Manifest bởi vì
Fragment chỉ tồn tại khi nhúng nó vào một Activity v vòng đời sống cũng phụ thuộc
Activity này.
1.3. Vòng đời củ một r gment

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 102
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Vòng đời của một Fragment sẽ đư c qu n lý bởi các phương thức giống như một
Activity. Chúng cũng có các phương thức khởi tạo (created), bắt đầu thực thi (started),
phục hồi trạng thái (resumed), tạm dừng tương tác (p used), đóng (stopped) v hủy
(destroyed). Bên cạnh đó các phương thức đư c gọi thực thi lại từ lớp Activity sẽ đư c
dùng để cho biết việc kết nối và hủy kết nối r gment đến Activity, khởi tạo và hủy
khởi tạo các điều khiển trên Fragment, thông báo việc hoàn thành việc khởi tạo Activity
chứa Fragment. Có thể xem lư c đồ s o để hiểu thêm chi tiết.

Hình 8.3. Vòng đời của Fragment.

- Hầu hết các phương thức n y đều khá giống so với các phương thức qu n lý vòng đời
củ Activity m t đã tìm hiểu trong chương 3. Chúng có v i trò chỉ định cách thức hoạt
động củ r gment v cách r gment đư c gắn vào một Activity.
- Vòng đời của một Fragment bắt đầu từ lúc chúng đư c gắn lên một Activity và kết thúc
khi đư c gỡ bỏ. Hai sự kiện này sẽ đư c giám sát bởi h i phương thức tương ứng là
onAttach và onDetach.
- Tất c phương thức qu n lý sẽ đư c gọi sau khi Fragment/Activity vào trạng thái tương
tác, tuy nhi n Phương thức onDetach có thể sẽ không đư c gọi lên nếu Activity chứa
Fragment bị hủy m chư ho n th nh vòng đời của nó.
- Phương thức onAtt ch đã đư c gọi l n trước khi giao diện r gment đư c khởi tạo,
trước c sự khởi tạo của Fragment và Activity chứ r gment. Thường thì phương thức
n y đư c dùng để tạo có tham chiếu đến Activity để chuẩn bị các khởi tạo xử lý khác.
- Việc tạo ra một Fr gment đư c thực hiện bởi phương thức onCreate và kết thúc bằng
phương thức onDestroy. Khi dùng trong Activity, chúng ta nên khởi tạo Fragment trong
onCreate của Activity.
1.4. Lưu trữ Fragment (BackStack)
- Việc lưu trữ Fragment bao gồm h i gi i đoạn:
o Lưu trữ trạng thái Fragment thông qua biến Bundle:
 Truy xuất biến Bundle trong phương thức onSaveInstanceState
 Truyền các thông tin cần lưu trữ vào biến Bundle

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 103
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Đư r gment v o St ck:
 Thực hiện khai báo Fragment
 Cho phép nhúng Fragment vào Activity
 Dùng phương thức ddToB ckSt ck(String T g) trong đối tư ng qu n lý
r gment để đư r gment v o St ck.
 Có thể truy xuất lại đối tư ng Fragment thông qua Tag, hoặc khi phím
“B ck” tr n thiết bị đư c nhấn.

2. ỰN N N
2.1. Thực hiện xây dựng Fragment:
- Khai báo lớp kế thừa từ lớp Fragment
o Gọi phương thức onCreateView thực hiện tạo giao diện cho Fragment.
o Ví dụ về tạo lớp Fragment và giao diện:
public class ImageFragment extends Fragment {
public View onCreateView(LayoutInflater inflater,ViewGroup parent, Bundle b )
{
View rootView = inflater.inflat(R.layout.fragment_main, null);
return rootView;
}
}

2.2. Sử dụng r gment


- Sử dụng Fragment trong Activity, bao gồm hai cách:
o Thực hiện tham chiếu Fragment từ giao diện XML của Activity.
o Kh i áo đối tư ng FragmentManger, cho phép nhúng Fragment vào Activity từ
JavaCode.
- M i Activity sẽ có một r gment M n ger dùng để qu n lý các Fragment chứa trong
nó. Để sử dụng ta cần gọi phương thức getFragmentManager.
FragmentManager frManager = getFragmentManager();

- Đối tư ng này sẽ cung cấp một số phương thức như th m, gỡ bỏ và cập nhật Fragment
vào Activity, qu n lý các phiên làm việc củ r gment…
- Các đơn gi n nhất để thêm một vào một Activity là khai báo thẻ fragment trong tập tin
giao diện củ Activity đó. r gment đư c xem như một đối tư ng View roup khi đư c
gắn v o trong L yout. Thường chúng ta sẽ sử dụng cách n y để định nghĩ một tập các
giao diện tĩnh cho các m n hình có kích cỡ khác nhau.
- Trong trường h p ta cần th y đổi giao diện dựa trên trạng thái của ứng dụng thì cách tốt
nhất ta nên sử dụng các giao diện động dựa trên FragmentTransaction.

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 104
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Lớp FragmentTransaction h tr chúng ta trong việc thêm, gỡ bỏ hoặc thay thế các
Fragment trên Activity ngay khi ứng dụng đ ng thực thi. Dự v o các tương tác củ người
dùng mà ta có thể xây dựng các giao diện h p lý. Ngo i r , để giúp cho ứng dụng có thể
đáp ứng các tr i nghiệm người dùng, các chuyển hoạt cũng đư c sử dụng giữa các phiên
làm việc của Fragment Transaction và các Transaction sẽ đư c lưu trữ trong st ck để tái sử
dụng.

- M i phiên làm việc củ r gmentTr ns ction đư c khởi tạo bằng phương thức
beginTransaction. Các hoạt động của Fragment sẽ đư c định nghĩ ằng các phương
thức add, remove hoặc repl ce. S u đó chúng t có thể tùy chỉnh các chuyển hoạt hoặc
cách thức hoạt động trong st ck trước khi thực hiện phương thức commit để thêm
Tr ns ction v o h ng đ i.

FragmentTransaction frTransaction = frManager.beginTransaction();

//Thiết lập add,remove hoặc replace, addToBackStack…


//Thiết lập các Animation cho Fragment

//Cuối cùng gọi phương thức commit()


frTransaction.commit()

- Ví dụ, để thực hiện thêm một Fragment mới đơn gi n ta chỉ cần chỉ định Fragment cần
th m v đối tư ng sẽ chứa Fragment này.
FragmentTransaction frTransaction = frManager.beginTransaction();
frTransaction.add(R.id.ui_container, new MyFragment());
frTransaction.commit()

- Đối với các phương thức remove và replace t cũng thực hiện tương tự.
- Để thực hiện các chuyển hoạt cho các Fragment trong một Transaction ta có 2 cách,
một l dùng phương thức setTransaction và truyền vào các tham số có sẵn trong lớp
FragmentTransaction. Ví dụ:
frTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

- Cách thứ hai là chúng ta sẽ sử dụng phương thức setCustomAnimations và thực hiện
tạo các chuyển hoạt ở các tập tin XML . Phương thức yêu cầu truyền vào hai tham số,
một d nh cho khi r gment đư c thêm vào và một cho r gment đư c gỡ bỏ. Ví dụ:
frTransaction.setCustomAnimations(android.R.animatior.fade_in,
android.R.animator.fade_out);

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 105
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Trong lớp Fragment h tr phương thức getActivity cho phép chúng có thể truy cập vào
các đối tư ng củ Activity m chúng đư c nhúng v o. Điều này giúp chúng ta có thể
lấy về các View mà ta cần tương tác ng y trong lớp Fragment. Ví dụ:
TextView textView = (TextView) getActivity().findViewById(R.id.fragEdit);
- Mặc dù chúng ta vẫn có dùng lớp r gmentM n ger để liên lạc giữa Fragment với
Activity nhưng cách tốt hơn l xây dựng một Interface mà ở đó Activity như một thành
phần trung gian và các Fragment sẽ không phụ thuộc v o Activity m nó đư c nhúng
v o. Thường thì chúng ta sẽ thực hiện tạo kết nối Interf ce trong phương thức onAttach
của Fragment. Có thể xem ví dụ s u để hiểu thêm.
o Xây dựng Interface
public interface OnNewItemAddedListener{
public void OnNewItemAdded(String newItem);
}

o Thực hiện lấy Activity l m trung gi n trong phương thức onAttach.

@Override
public void onAttach(Activity activity){
super.onAttach(activity);
try{
onNewItemAddedListener = (OnNewItemAddedListener) activity;
}catch(ClassCastException e){
Throw new ClassCastExeption(activity.toString() + “ must
implement onNewItemAddedListener.”);
}
}

o Thực thi Interface trong Activity

@Override
public void onNewItemAdded(String newItem){
//Do Something with newItem
}

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 106
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Mục lục

Bài 1: Tổng quan về Lập trình Android và môi trường phát triển ................................ 1

1. Tổng quan Android ............................................................................................................ 1

2. Kiến trúc Android .............................................................................................................. 8

3. Môi trường phát triển ứng dụng Android .......................................................................... 9

Bài 2: Các thành phần ứng dụng Android ........................................................................ 29

1. Các thành phần trong ứng dụng Android .......................................................................... 29

2. Tương thích thiết bị ........................................................................................................... 32

3. Activity và độ ưu tiên ứng dụng ........................................................................................ 32

Bài 3: Giao diện người dùng và xử lý sự kiện ................................................................... 37

1. Giao diện người dùng ........................................................................................................ 37

2. View và Viewgroup ........................................................................................................... 42

3. Các điều khiển cơ bản ........................................................................................................ 46

4. Kiểm tra lỗi và tối ưu lại giao diện .................................................................................... 51

Bài 4: Tài nguyên ứng dụng trong Android ...................................................................... 53

1. Tổng quan .......................................................................................................................... 53

2. Tính tương thích ................................................................................................................ 57

3. Truy xuất tài nguyên .......................................................................................................... 57

4. Các tài nguyên ứng dụng cơ bản........................................................................................ 58

5. Các tài nguyên ứng dụng nâng cao .................................................................................... 62

Bài 5: Intent .......................................................................................................................... 71

1. Khái niệm về Intent............................................................................................................ 71

2. Intent filter ......................................................................................................................... 74

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 107
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 6: Quản lý Asset – Shared Preferences – Bộ nhớ thiết bị .......................................... 77

1. Bộ quản lý Asset ................................................................................................................ 77

2. Shared Preferences ............................................................................................................. 80

3. Bộ nhớ thiết bị ................................................................................................................... 82

Bài 7: Các điều khiển hiển thị danh sách .......................................................................... 85

1. Khái niệm cơ bản ............................................................................................................... 85

2. Các dạng Adapter............................................................................................................... 85

3. Các điều khiển danh sách .................................................................................................. 86

Bài 8: Xây dựng giao diện với Fragment – Vấn đề Activity và Fragment ..................... 100

1. Các khái niệm cơ bản......................................................................................................... 100

2. Xây dựng và sử dụng Fragment ......................................................................................... 104

Tài liệu Lập trình thiết bị di động trên Android – Module 2 | 108
TRUNG TÂM TIN HỌC - ĐẠI HỌC KHOA HỌC TỰ NHIÊN

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH

CHƯƠNG TRÌNH ĐÀO TẠO

LẬP TRÌNH VIÊN CHUYÊN NGHIỆP TRÊN THIẾT BỊ DI ĐỘNG

TÀI LIỆU

LẬP TRÌNH THIẾT BỊ DI ĐỘNG TRÊN


ANDROID
MODULE 03:
LẬP TRÌNH CƠ SỞ DỮ LIỆU, TIẾN TRÌNH
VÀ CHUYỂN ĐỘNG TRONG ỨNG DỤNG

Tháng 06/2015
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 1
LƢU TRỮ, TRUY VẤN
VÀ SẮP XẾP DỮ LIỆU VỚI SQLITE

1. KHÁI NIỆM CƠ SỞ DỮ LIỆU (DATABASE CONCEPTS)


- Dữ liệu là những sự kiện có thể ghi lại được và có ý nghĩa.
- Một cơ sở dữ liệu (CSDL) là một tập hợp dữ liệu có liên quan với nhau, được lưu trữ
trên máy tính, có nhiều người sử dụng và được tổ chức theo một mô hình.
- Một CSDL biểu thị một khía cạnh nào đó của thế giới thực. Thông tin được đưa vào
trong CSDL tạo thành một không gian CSDL hoặc một “thế giới nhỏ” (miniworld).
- Một CSDL là một tập hợp dữ liệu liên kết với nhau một cách logic và mang một ý
nghĩa nào đó. Một CSDL được thiết kế và được phổ biến cho một mục đích riêng. Một
hệ quản trị cơ sở dữ liệu là một tập chương trình giúp cho người sử dụng tạo ra, duy trì
và khai thác CSDL. Người ta gọi cơ sở dữ liệu và hệ quản trị cơ sở dữ liệu bằng một
thuật ngữ chung là hệ cơ sở dữ liệu.
- Hệ quản trị cơ sở dữ liệu (tiếng Anh: Database Management System - DBMS), là
phần mềm hay hệ thống được thiết kế để quản trị một cơ sở dữ liệu. Cụ thể, các chương
trình thuộc loại này hỗ trợ khả năng lưu trữ, sửa chữa, xóa và tìm kiếm thông tin trong
một CSDL. Có rất nhiều loại hệ quản trị CSDL khác nhau: từ phần mềm nhỏ chạy trên
máy tính cá nhân cho đến những hệ quản trị phức tạp chạy trên một hoặc nhiều siêu
máy tính.
- Tuy nhiên, đa số hệ quản trị CSDL trên thị trường đều có một đặc điểm chung là sử
dụng ngôn ngữ truy vấn theo cấu trúc mà tiếng Anh gọi là Structured Query Language
(SQL). Các hệ quản trị CSDL phổ biến được nhiều người biết đến là MySQL, Oracle,
PostgreSQL, SQL Server, DB2, Infomix, v.v... Phần lớn các hệ quản trị CSDL kể trên
hoạt động tốt trên nhiều hệ điều hành khác nhau như Linux, Unix và MacOS ngoại trừ
SQL Server của Microsoft chỉ chạy trên hệ điều hành Windows.

2. GIỚI THIỆU SQLITE


- SQLite là cơ sở dữ liệu mở được viết dưới dạng thư viện tích hợp nhúng vào Android,
hỗ trợ các đặc điểm về quan hệ chuẩn của cơ sở dữ liệu như cú pháp, transaction, các
câu lệnh. SQLite được sử dụng rộng rãi trong các ứng dụng di động trên Android, iOS,
… Mozilla Firefox cũng sử dụng SQLite để lưu trữ các dữ liệu về cấu hình.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |1


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Với bộ thư viện được tích hợp sẵn SQLite sẽ giúp các lập trình viên có thể lưu trữ và
phục hồi dữ liệu bất cứ lúc nào. Tuy chỉ là phiên bản rút gọn nhưng SQLite có thể đáp
ứng được hầu hết các nhu cầu về xử lý dữ liệu. Tính linh động trong SQLite cũng giúp
ta thể kiểm soát được các thông tin dữ liệu.
- Sử dụng SQLite không yêu cầu về thiết lập bất cứ cơ sở dữ liệu hoặc đòi hỏi quyền
admin.
- SQLite hỗ trợ các kiểu dữ liệu : TEXT, INTEGER, REAL.
- Đường dẫn của cơ sở dữ liệu:
DATA/data/<PACKAGE_NAME>/databases/FILENAME
- Thể hiện dữ liệu ở dạng bảng quan hệ:
o Cột: thể hiện trường dữ liệu (hoặc thuộc tính dữ liệu).
o Dòng: một thể hiện dữ liệu.

word app id frequency Locale _ID


mapreduce user1 100 en_US 1
precompiler user14 200 fr_FR 2
applet user2 225 fr_CA 3
const user1 255 pt_BR 4
Int user5 100 en_UK 5

- Mặc định mỗi ứng dụng sẽ được cấp phát một thư mục cho việc lưu trữ cơ sở dữ liệu và
nó chỉ có thể được dùng bởi ứng dụng đó. Nếu muốn chia sẻ dữ liệu dùng chung giữa
các ứng dụng ta có thể sử dụng Content Provider.

3. XÂY DỰNG CƠ SỞ DỮ LIỆU VỚI SQLITE


3.1. Tạo Cơ sở dữ liệu
- Tạo cơ sở dữ liệu thông qua lớp SQLiteOpenHelper.
o SQLiteOpenHelper là một lớp ảo, SQLiteOpenHelper giúp tạo các cơ sở dữ
liệu dùng SQLite (vì SQLite không hỗ trợ các phương thức khởi tạo cơ sở dữ
liệu). Vậy làm sao để sử dụng được SQLiteOpenHelper? Vì SQLiteOpenHelper
là một lớp ảo nên ta cần khai báo một lớp khác kế thừa lớp này.
o SQLiteOpenHelper thực hiện các phương thức cần thiết cho phép khởi tạo, nâng
cấp cơ sở dữ liệu. Tạo đối tượng để truy cấp cơ sở dữ liệu (Read và Write).
o SQLiteDatabase cung cấp phương thức insert(), update(), delete(), hoặc
execSQL() cho phép thực hiện truy xuất dữ liệu.
- Override phương thức onCreate() để tạo cơ sở dữ liệu.
- Override phương thức onUpgrade() để nâng cấp cơ sở dữ liệu.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |2


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Lớp SQLiteOpenHelper cung cấp 2 phương thức getReadableDatabase() và


getWriteableDatabase() để trả về đối tượng SQLiteDatabase.
Ví dụ:
- Tạo một CSDL có tên: COUNTRY_DB
- Trong đó:
o Tạo một Table có tên: COUNTRY.
o Table COUNTRY có 3 cột là: _id, enName và viName với _id là khóa chính và
có giá trị tự động tăng.
public class MySQLiteHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "COUNTRY_DB";
public static final String TABLE_NAME = "COUNTRY ";
public static final String COL_ID = "_id";
public static final String COL_EN_NAME = "enName";
public static final String COL_VI_NAME = "viName";
public static final String CREATE_TABLE = "CREATE TABLE "
+ TABLE_NAME + " ("
+ COL_ID + " integer primary key autoincrement, "
+ COL_EN_NAME + " text not null, "
+ COL_VI_NAME + " text not null);";.

public MySQLiteHelper(Context context) {


super(context, DB_NAME, null, 1);
}
}

- Lưu ý: Hàm khởi tạo có các thông số sau:


o Context: Biến ngữ cảnh.
o DB_NAME: Tên của cơ sở dữ liệu.
o CursorFactory: Đôi lúc chúng ta có thể extend lớp cursor để kế thừa một số
phương thức và truy vấn. Trong trường hợp đó, ta dùng một instance của
CursorFactory để tham chiếu đến lớp chúng ta tạo thay cho mặc định. Khi dùng
mặc định thì ta để nó null.
o Version: Version của cơ sở dữ liệu.
- Tiến hành tạo CSDL trong hàm onCreate():
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("SQLite", "On Create Database");

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |3


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

//Tạo Table với câu lệnh execSQL


db.execSQL(CREATE_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
}

3.2. Mở Cơ sở dữ liệu
- Dùng cú pháp getReadableDatabase() và getWriteableDatabase() để trả về đối tượng
SQLiteDatabase cần sử dụng.
- SQLiteDatabase là đối tượng để truy cập cơ sở dữ liệu (Read và Write).
- SQLiteDatabase cung cấp phương thức insert(), update(), delete(), hoặc execSQL() cho
phép thực hiện truy xuất dữ liệu.

MySQLiteHelper myHelper = new MySQLiteHelper(context);


SQLiteDatabase database;
try{
database = myHelper.getWritableDatabase();
}catch(SQLiteException ex){
database = myHelper.getReadableDatabase();
}

- Nếu cơ sở dữ liệu đã tồn tại thì lớp SQLiteOpenHelper sẽ không tạo thêm mà chỉ mở
kết nối đến cơ sở dữ liệu đó.

3.3. Đóng Cơ sở dữ liệu

public void close(){


myHelper.close();
}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |4


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

4. TRUY VẤN DỮ LIỆU


4.1. Truy vấn (Query)
4.1.1. Truy vấn với câu lệnh SQL
- Sử dụng phương thức rawQuery() của lớp SQLiteDatabase.
- Phương thức rawQuery() nhận vào một giá trị chuỗi là câu lệnh SQL dùng để truy vấn
dữ liệu và trả ra một đối tượng Cursor.
String queryStr = “SELECT * FROM COUNTRY WHERE _id=? AND
enName=?”;
Cursor cursor = database.rawQuery(queryStr, new
String[]{“1”,”Vietnam”});

- Cú pháp truy xuất dữ liệu trong câu lệnh SQL:


o Phát biểu truy vấn SQL có dạng:
SELECT {Tên trường cần truy vấn, * nếu lấy tất cả các trường}
FROM {Tên Table}
WHERE {Biểu thức điều kiện}

 SELECT dùng để đọc thông tin từ cơ sở dữ liệu theo trường hợp quy định
hay những biểu thức cho trường hợp đó.
 FROM chỉ ra tên một bảng hay những bảng có liên quan cần truy vấn
thông tin.
 WHERE để tạo nên điều kiện cần lọc mẩu tin theo tiêu chuẩn được định
nghĩa. Thông thường, WHERE dùng cột (trường) để so sánh với giá trị
cột khác, hay biểu thức chứa cột (trường) bất kỳ có trong bảng (table).

Hình 3 1. Ví dụ truy vấn với câu lệnh SELECT.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |5


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Các phép toán so sánh trong câu lệnh SQL:

> Lớn WHERE _id>10; < : nhỏ hơn WHERE _id<10;


>= Lớn hơn hoặc bằng WHERE _id>=10;

<= Nhỏ hơn hoặc bằng WHERE _id<=10;


= Bằng WHERE _id=1;
!= Khác (ko bằng ) WHERE _id!=1;

- Các phép toán logic trong câu lệnh SQL:

AND WHERE `_id`=1 AND `enName`='admin';

OR WHERE `_id`=1 OR `enName`='admin';

NOT WHERE enName is not NULL;

NOT IN WHERE _id NOT IN( '10','20');

BETWEEN WHERE _id BETWEEN 10 And 20;

LIKE WHERE enName LIKE '%Vietnam';

NOT LIKE WHERE enName NOT LIKE '%Vietnam ;

IN WHERE _id IN ('10','20','30');

4.1.2. Truy vấn với cú pháp hàm


- Sử dụng phương thức query() của lớp SQLiteDatabase.
- Hỗ trợ lập trình viên truy xuất dữ liệu từ CSDL mà không cần biết cú pháp các câu lệnh
SQL.
- Phương thức query() cũng trả ra một đối tượng Cursor. Để lấy dữ liệu từ Cursor, trước
hết cần chuyển đến vị trí xác định với các phương thức: moveToFirst(), moveToNext(),
moveToPosition(int position)… như được giới thiệu ở Bài 2.
- Cursor:
o Đối tượng dữ liệu được trả về khi thực hiện truy vấn dữ liệu trong cơ sở dữ liệu
của SQLite hoặc Content Provider.
o Thể hiện dữ liệu ở dạng bảng quan hệ :
 Cột: thể hiện trường dữ liệu (hoặc thuộc tính dữ liệu).

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |6


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Dòng: một thể hiện dữ liệu.


Cursor cursor = database.query(String table,
String[] columns,
String selection,
String[] selectionArgs,
String groupBy,
String having,
String orderBy);

String table: tên của bảng cần truy vấn.


String[] columns: danh sách các cột sẽ trả về dữ liệu.
String selection: chứa các điều kiện truy vấn.
String[] selectionArgs: danh sách các tham số phụ cho câu điều kiện.
String[] groupBy: gom nhóm các cột kết quả.
String[] having: bộ lọc theo điều kiện.
String[] orderBy: sắp xếp theo mảng cột được chỉ định.
Ví dụ:
- Sử dụng phương thức query(), lấy ra tên tiếng Anh và tên tiếng Việt của dòng có _id là 1.
String selectedColumns = new String[]{ COL_EN_NAME, COL_VI_NAME};
Cursor c = database.query(TABLE_NAME, selectedColumns, “_id=?”,
new String[]{“1”}, null, null, null);
if (c.moveToFirst()) {
while (!c.isAfterLast())
{
String enName =
c.getString(c.getColumnIndex(selectedColumns[0]));
String viName =
c.getString(c.getColumnIndex(selectedColumns[1]));
c.moveToNext();
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |7


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

4.2. Quản lý
- Lớp SQLiteDatabase cung cấp các phương thức như: insert(), update(), delete() hoặc
execSQL() cho phép người dùng có thể quản lý và truy xuất dữ liệu.
4.2.1. Insert
- Tạo một dòng mới để insert dữ liệu:
ContentValues newValues = new ContentValues();

- Gán giá trị vào mỗi cột trong dòng vừa tạo:
newValues.put(COLUMN_NAME,values);

- Ví dụ:
newValues.put(COL_EN_NAME, “Germany”);
newValues.put(COL_VI_NAME, “Đức”);
//Thêm dòng đó vào database
database.insert(TABLE_NAME, null, newValues);

4.2.2. Update
- Tạo một dòng mới để update dữ liệu:
ContentValues newValues = new ContentValues();

- Gán giá trị vào mỗi cột trong dòng vừa tạo:
newValues.put(COLUMN_NAME, values);

- Ví dụ:
newValues.put(COL_EN_NAME,”Germany2”);

o Cập nhật lại dòng vừa tạo với đúng mệnh đề WHERE:
String where = “_id=” + rowId;
database.update(TABLE_NAME, newValues, where, null);

4.2.3. Delete
- Sử dụng câu truy vấn delete truyền vào tên bảng và chỉ số của hàng cần xóa trong mệnh
đề WHERE.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |8


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Nếu mệnh đề WHERE không có sẽ thực hiện xóa tất cả các dòng:
database.delete(TABLE_NAME, “_id=” + rowID, null);

5. SẮP XẾP DỮ LIỆU


5.1. Truy vấn sắp xếp
- Thông thường trong khi truy vấn mẩu tin từ bảng dữ liệu, kết quả hiển thị sắp xếp theo
chiều tăng hay giảm dựa trên ký tự ALPHABET. Nhưng bạn cũng có thể sắp xếp theo
một tiêu chuẩn bất kỳ .
- Cú pháp cho mệnh đề ORDER BY cùng với trạng thái tăng dần (ASCENDING) hoặc
giảm dần (DESCENDING):

5.1.1. Tăng dần (ASCENDING)


ORDER BY columnName ASC
ORDER BY columnName1 + columnName2 ASC
- Ví dụ:
o Truy vấn với câu lệnh SQL:
SELECT * FROM COUNTRY ORDER BY enName ASC

o Truy vấn với cú pháp hàm:


String orderBy = myHelper.COL_EN_NAME + " ASC";
database.query(TABLE_NAME, null, null, null, null, orderBy);

5.1.2. Giảm dần (DESCENDING)


ORDER BY columNname DESC
ORDER BY columNname1 + columnName2 DESC

- Ví dụ:
o Truy vấn với câu lệnh SQL:
SELECT * FROM COUNTRY ORDER BY enName DESC

o Truy vấn với cú pháp hàm:


String orderBy = myHelper.COL_VI_NAME + " DESC";

Tài liệu Lập trình thiết bị di động trên Android – Module 3 |9


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

database.query(TABLE_NAME, null, null, null, null, orderBy);

5.2. Truy vấn gom nhóm


- Ví dụ minh họa:
o Ta có CSDL như sau:

Hình 1.1. CSDL mẫu.

o Gom nhóm các bài hát có MaSo lớn hơn 55500 bằng cú pháp GROUP BY và
mệnh đề HAVING với cú pháp:
SELECT column1, column2
FROM table1, table2
WHERE [ conditions ]
GROUP BY column1, column2
HAVING [ conditions ]

o Có thể truy vấn với câu lệnh SQL:


SELECT * FROM BAIHATCUTHE GROUP BY TenBaiHat HAVING MaSo>55500
o Hoặc truy vấn với cú pháp hàm:
String groupBy = “BAIHATCUTHE”;
String having = “Maso>55500”

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 10


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

database.query(TABLE_NAME, null, null, groupBy, having, null);

o Kết quả:

Hình 1.2. Kết quả sau khi gom nhóm dữ liệu.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 11


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 2
QUẢN LÝ DỮ LIỆU
VỚI CONTENT PROVIDER

1. GIỚI THIỆU CONTENT PROVIDER


1.1. Content Provider
- Content Provider là một dạng lưu trữ cơ sở dữ liệu - nơi mà ta có thể tương tác với dữ
liệu dạng SQLite và chia sẻ dữ liệu cho các ứng dụng khác. Trong các thiết bị Android
cũng có sẵn một số Content Provider dùng chung như danh bạ, các tập tin đa phương
tiện, …
- Nói cách khác, Content Provider là nơi đóng gói các dữ liệu cho phép các thành phần
trong ứng dụng hoặc các ứng dụng khác truy cập và sử dụng.
- Thể hiện dữ liệu ở dạng bảng quan hệ:
o Cột: thể hiện trường dữ liệu (hoặc thuộc tính dữ liệu).
o Dòng: một thể hiện dữ liệu.
- ContentProvider được cung cấp sẵn trong hệ thống:
o Hệ thống báo thức (Alarm).
o Nội dung trình duyệt (Browser).
o Danh bạ (Contacts).
o Lịch (Calendar).
o Tập tin tài liệu (Document).
o Tập tin đa truyền thông (Media Store).
o Tùy chỉnh hệ thống (Setting).
o Điện thoại (Telephony).
o Từ điển người dùng (UserDictionary).
o Hộp thư thoại (VoiceMailContract).
- Cách thức hoạt động c a Content Provider
o Mô hình dữ liệu theo định dạng cột và dòng giống như cơ sở dữ liệu. Với mỗi
cột là trường dữ liệu và mỗi dòng là một record.
o Cách thức hoạt động giống giao thức REST trong web.
o Sử dụng chuỗi URI để thực hiện việc rút trích cũng như lưu dữ liệu trong content
provider.
Ví dụ: content://com.android.book.BookProvider
content://com.android.book.BookProvider/7

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 12


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Android cung cấp một số các gói Content Provider dùng cho việc lưu trữ chung như
- Browser.
- CallLog.
- Contact (people, phones, photos, group ).
- MediaStore (music, video, image).
- Setting.
Cần khai báo trong file AndroidManifest.xml cho biết ứng dụng sử dụng những Content
Provider nào.

<provider
android:name= “SomeProvider”
android:authorities= “com.your-company.SomeProvider”>
<provider
android:name= “NotePadProvider”
android:authorities= “com.your-company.NodePad”>

1.2. Content URI


- Đối tượng cho phép định nghĩa cách thức truy xuất dữ liệu trên Content Provider, bao
gồm:
o Authority Tên đầy đ c a Provider.
o Path: tên bảng tồn tại trong Provider
- Ví dụ về Content URI truy xuất dữ liệu danh bạ:
o ContactsContract.Data.CONTENT_URI
o content://com.android.contact/data
 Trong đó
 content: scheme.
 com.android.contact: authority.
 data: tên bảng.
1.3. ContentResolver
- Đối tượng cho phép truy xuất dữ liệu và thao tác trên Content Provider, bao gồm:
o Query.
o Insert.
o Update.
o Delete.
- Truy xuất đối tượng ContentResolver thông qua phương thức:
o getContentResolver();
- Phương thức Query:
Cú pháp:
o query(Uri, projection, selection, selectionArgs, sortOrder)

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 13


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Uri đường dẫn truy xuất dữ liệu. – URI.


 Projection: mảng tên các trường dữ liệu (cột) cần truy xuất. – String[]
 Selection câu điều kiện truy vấn. – String.
 SelectionArgs: mảng biến tham số cho câu điều kiện truy vấn. – String[]
 SortOrder: tiêu chí sắp xếp dữ liệu truy vấn (tên cột). - String
Kết quả trả về:
o Cursor: chứa bảng dữ liệu kết quả truy vấn.
Ví dụ truy xuất tất cả dữ liệu danh bạ trên thiết bị:

// Định nghĩa đường dẫn truy xuất


Uri uri = ContactsContract.Data.Content_URI;
// Định nghĩa tham số truy vấn
String projection = null; // Lấy ra tất cả các cột
String selection = null; // Không có điều kiện truy vấn
String selectioArgs = null; // Không có tham số truy vấn
String sortOrder = null; // Sắp xếp mặc định
// Đối tượng truy vấn
ContentResolver cr = this.getContentResolver();
Cursor cursor = cr.query(Uri, projection, selection, selectionArgs,
sortOrder);

Ví dụ truy xuất dữ liệu danh bạ trên thiết bị có tên bắt đầu bằng “M” và sắp xếp theo theo ID.

Uri uri = ContactsContract.Data.Content_URI; //Định nghĩa đường dẫn


truy xuất
// Định nghĩa tham số truy vấn
String projection = null; // Lấy ra tất cả các cột
String selection = Data.DISPLAY_NAME + “ like ?”; // điều kiện truy vấn
String selectioArgs = { “M%”}; // Tham số truy vấn
String sortOrder = Data._ID; // Sắp xếp theo ID
// Đối tượng truy vấn
ContentResolver cr = this.getContentResolver();
Cursor cursor = cr.query(Uri, projection, selection, selectionArgs,
sortOrder);

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 14


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Phương thức Insert, Update được thực hiện thông qua tham số dữ liệu ContentValues:
o ContentValues: cho phép định nghĩa dữ liệu khi thao tác, thông qua phương thức
put(Key, Value).
o Trong đó
 Key tên trường dữ liệu (cột). - String
 Value: dữ liệu tương ứng với trường dữ liệu – String, Float, Long…
- Phương thức Insert:
Cú pháp:
o insert(Uri, ContentValues)
 Uri đường dẫn truy xuất dữ liệu. – URI.
 ContentValues: dữ liệu cần thêm vào. - ContentValues.
Kết quả trả về:
o URI đường dẫn đến dữ liệu vừa thêm vào.
- Phương thức Update:
Cú pháp:
o update(Uri, ContentValues, where, selectionArgs)
 Uri đường dẫn truy xuất dữ liệu. – URI.
 ContentValues: dữ liệu cần cập nhật. – ContentValues.
 Where điều kiện dữ liệu được cập nhật. – String.
 SelectionArgs: mảng tham số cho câu điều kiện. – String[].
Kết quả trả về:
o int: số lượng dòng dữ liệu đã được cập nhật.
- Phương thức Delete:
Cú pháp:
o delete(Uri, ContentValues, where, selectionArgs)
 Uri đường dẫn truy xuất dữ liệu. – URI.
 Where điều kiện dữ liệu được xóa. – String.
 SelectionArgs: mảng tham số cho câu điều kiện. – String[].
Kết quả trả về:
o int: số lượng dòng dữ liệu đã được xóa.

2.
2.1. Vấn đề xây dựng ContentProvider
- Việc sử dụng ContentProvider trong ứng dụng khi cần xây dựng những tính năng sau
o Cung cấp các dữ liệu hoặc tập tin đặc trưng, phức tạp cho những ứng dụng khác.
o Cho phép người dùng sao chép các dữ liệu vào các ứng dụng khác.
o Sử dụng và tùy chỉnh tính năng tìm kiếm dữ liệu trong ứng dụng.
- Thực hiện xây dựng ContentProvider:
o Xây dựng dữ liệu:
 Dữ liệu tập tin (not recommended).

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 15


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Dữ liệu có cấu trúc (SQLite).


o Thiết kế các biến truy xuất dữ liệu (Contract class):
 Authority – Content URI (required).
 Biến đại diện cho các trường dữ liệu (tên cột).
o Tạo lớp kế thừa và thực hiện các phương thức truy vấn dữ liệu
 ContentProvider (required)
 onCreate.
 query - delete - insert – update.
- Khai báo lớp sử dụng trong Manifest thông qua thẻ <provider/>
o Khai báo Permission.

2.2. Authority & UriMatcher


2.2.1. Authority:
- Định nghĩa đường dẫn truy xuất vào ContentProvider.
o Định nghĩa đề xuất: <pakage_name>.<app_name>.provider
Ví dụ:
com.htsi.t3h.onlineshop.provider
- Định nghĩa đường dẫn truy xuất vào từng bảng riêng biệt trong ContentProvider.
o Định nghĩa đề xuất: <authority>/<table_name>
Ví dụ:
com.htsi.t3h.onlineshop.provider/accessory
com.htsi.t3h.onlineshop.provider/clothes
2.2.2. UriMatcher:
- Đối tượng cho phép kiểm tra các Content URI truy xuất vào Content Provider.
o Sử dụng dấu đại diện:
* : Cho phép truy xuất vào tất cả các dạng dữ liệu.
# : Cho phép truy xuất vào một dòng trong một bảng.

Ví dụ định nghĩa Content URI truy xuất dữ liệu:


- Truy xuất tất cả các bảng trong ContentProvider:
content://com.htsi.t3h.onlineshop.provider/*
- Truy xuất tất cả các dữ liệu trong bảng accessory:
content://com.htsi.t3h.onlineshop.provider/accessory/*
- Truy xuất dòng dữ liệu có id = # trong bảng accessory:
content://com.htsi.t3h.onlineshop.provider/accessory/#

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 16


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

3. TRUY VẤN DỮ LIỆU HỆ THỐNG VỚI CONTENT PROVIDER


3.1. Các phương thức điều khiển Cursor
- Sử dụng Cursor để thực hiện các thao tác trên bảng dữ liệu c a provider.

Hình 2.1. Error! No text of specified style in document - 1. Mô tả về Cursor.

- Một số các phương thức để điều khiển Cursor thao tác trên dữ liệu:
o movetoFisrt(): trở về hàng đầu, false nếu cursors rỗng.
o movetoNext(): chuyển đến hàng tiếp theo, false nếu đang ở hàng cuối cùng.

o movetoPrevious(): chuyển đến hàng trước đó, false nếu đang ở đầu.
o movetoPosition(int position): chuyển đến vị trí xác định, false nếu vị trí không
thể tới.
o getColumnName(int columnIndex): trả về tên cột nếu biết chỉ số cột.
o getColumnIndex(String columnName): trả về chỉ số cột nếu biết tên cột.
o moveToLast(): chuyển đến vị trí cuối cùng, false nếu danh sách rỗng.
o getString(int columnIndex): lấy giá trị ở cột có chỉ số truyền vào.
o Ngoài ra thì còn một số hàm kiểm tra khác như boolean isAfterLast(),
isBeforeFirst(), isNull(columnIndex) …
Ví dụ:

if(cursor.moveToFirst() == false){
//không có dữ liệu
return;
}
//Cursor đã ở dòng dữ liệu đầu tiên.
//Thử truy xuất vào một cột nào đó để lấy dữ liệu
int columnIndex = cursor.getColumnIndex(People.NAME);

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 17


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

String name = cursor.getString(columnIndex);


while(cursor.moveToNext()){
//tiến hành truy cập vào các trường khác trong bảng
cursor.moveToNext();}

3.2. Truy vấn dữ liệu hệ thống


- Sử dụng Content Provider để truy xuất vào dữ liệu c a SMS trên điện thoại:
o Sử dụng Uri : content://sms/inbox.
o Tạo mảng chứa tên cột cần truy xuất dữ liệu.
o Duyệt Cursor qua bảng dữ liệu để lấy những thông tin cần thiết.

public void getInboxMess(ContentResolver content) {


String[] projection = { "address", "body" }
Cursor cursor = content.query(Uri.parse("content://sms/inbox"),
projection, null, null, null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
String address =
cursor.getString(c.getColumnIndex(projection[0]));
String body =
cursor.getString(c.getColumnIndex(projection[1]));
Log.d("SMS", "Adress: " + address + " - Body: " + body);
cursor.moveToNext();
}
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 18


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 3
MENU - ACTION BAR – TOOLBAR

1. MENU
Menu là dạng Widget chứa các chức năng phụ hoặc các tùy chỉnh dành riêng cho từng ứng
dụng. Bao gồm các dạng cơ bản:
1.1. Option Menu
- Là menu chính trong ứng dụng chứa các thao tác cơ bản cho một ứng dụng được gọi
khi người dùng nhấn phím Menu.
- Từ phiên bản Android 2.3 trở xuống, thao tác gọi Menu được thực hiện bằng phím
Menu trên thiết bị.

Hình 1.1. OptionMenu.

- Từ phiên bản Android 3.0 trở đi, Option Menu được tích hợp vào thanh Action Bar.
o Tạo Menu từ trong tập tin XML:

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 19


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

<menu
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="ifRoom "
android:title="@string/action_settings"/>
<item
android:id="@+id/action_help"
android:title="@string/action_help"/>
</menu>

o Sử dụng trong Java code qua hàm onCreateOptionMenu():


@Override
public void onCreateOptionMenu(Menu menu) {
MenuInflater inflate = get MenuInflater;
Inflate. inflate (R.menu.game_menu, menu);
return true;
}

o Xử lý sự kiện trong OptionMenu:


@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_setting:
//show Setting
break;
case R.id.action_help:
break;
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 20


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

1.2. Context Menu


- Dạng menu xuất hiện khi người dùng tương tác với các Item trên ViewGroup, thường
là ListView hoặc GridView.
- Bao gồm 2 dạng:
o Floating Context Menu: dạng menu hiển thị khi người dùng nhấn và giữ một
item trên ViewGroup (giống như Dialog).

Hình 1.2. Floating Context Menu.

o Contextual Action Mode (API level 11): một thanh công cụ hiển thị phía trên ứng
dụng, nó cho phép người thực hiện nhiều thao tác khác nhau trên Item được lựa
chọn, hoặc thực hiện một thao tác trên nhiều Item nếu ứng dụng có hỗ trợ.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 21


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.3. Contextual Action Mode.

- Tạo Floating Context Menu


o Đăng ký đối tượng View sẽ sử dụng bằng phương thức
registerForcontextMenu(View)
o Thực hiện override phương thức onCreateContextMenu()
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.context_menu, menu);
}

o Xử lý sự kiện trên Floating Context Menu bằng cách override phương thức
oncontextItemSelected()

@Override
public boolean onContextItemSelected(MenuItem item) {

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 22


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

AdpterContextMenuInfo info = (AdapterContextMenuInfo)


item.getMenuInfo();
switch (item.getItemId()) {
case R.id.edit:
editItem(info.id);
break;
case R.id.delete:
deleteItem(info.id);
break;
}
}

o Khai báo và sử dụng Contextual Action Mode (API level 11)


 Có 2 kiểu khai báo:
 Khai báo dành cho đối tượng View: khai báo biến ActionMode
call back để khởi tạo hàm onCreateActionMode()
private ActionMode.Callback mActionModeCallback = new
ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu)
{

MenuInflater inflater = mode.getMenuInflater();


inflater.inflate(R.menu.context_menu, menu);
return true;
}
}

 Thực hiện override hàm onActionItemClicked() để nhận biết các


item nào trên menu được gọi thực hiên.
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem
item) {

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 23


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

switch (item.getItemId()) {
case R.id.menu_share:
//Các hàm xử lý
return true;
default:
return false;
}
}

o Gọi thực hiện hàm setOnLongClickListener() nếu người dùng nhấn và giữ lâu
trên đối tượng nào đó (someView).
someView.setOnLongClickListener(new View.OnLongClickListener() {
// Called when the user long-clicks on someView
public boolean onLongClick(View view) {
if (mActionMode != null) {
return false;
}

mActionMode=
this.getActivity().startActionMode(mActionModeCallback);
view.setSelected(true);
return true;
}
});

o Khai báo dành cho đối tượng ViewGroup


ListView listView = getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

listView.setMultiChoiceModeListener(new
MultiChoiceModeListener().
{
@Override
public boolean onActionItemClicked(ActionMode mode,
MenuItem item) {
}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 24


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

@Override
public boolean onCreateActionMode(ActionMode mode, Menu
menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context, menu);
return true;
}
});

1.3. PopUp Menu


- Dạng menu hiển thị khi người dùng nhấn và giữ lâu trên một đối tượng.

Hình 1.4. PopupMenu.

- Ví dụ về tạo một Popup Menu:


o Tạo đối tượng cần show Popup Menu
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_overflow_holo_dark"
android:contentDescription ="@string/descr_overflow_button"
android:onClick="showPopup" />

o Tạo xử lý hàm onClick cho đối tượng để hiện ra Popup Menu


public void showPopup(View v) {
PopupMenu popup = new PopupMenu(this, v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.actions, popup.getMenu());

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 25


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

popup.show(); }

o Thao tác xử lý trên từng Item của Menu:


@Override public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) {
case R.id.archive:
archive(item);
return true;
case R.id.delete:
delete(item);
return true;
default:
return false;
}
}

- Sử dụng Checkable Item Menu


o Sử dụng các Radio Checkbox trên các item của Menu

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 26


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.5. Ví dụ về Checkable Item Menu.

o Cách khai báo:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item android:id="@+id/red"
android:title="@string/red" />
<item
android:id="@+id/blue"
android:title="@string/blue" />
</group>
</menu>

o Xử lý khi người dùng click chọn lên item:


@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 27


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

case R.id.vibrate:
case R.id.dont_vibrate:
if (item.isChecked())
item.setChecked(false);
else item.setChecked(true);
return true;
default:
return super.onOptionsItemSelected(item);
}
}

2. ACTION BAR
2.1. Giới thiệu
Trong lần đầu giới thiệu chiếc Samsung Galaxy Nexus, Google đã loại bỏ nút Menu ra khỏi
cụm phím điều hướng chính của hệ thống, chỉ còn lại nút Quay về (Back), nút trở về màn hình
chính (Home) và nút liệt kê các ứng dụng đã chạy gần đây (Recents Apps). Nó biến thành một
thứ gọi là "Action Bar", nơi mà người dùng có thể khởi chạy các hoạt động tùy thuộc vào ứng
dụng.
- Action Bar có chức năng:
o Điều hướng giao diện ứng dụng.
o Hiển thị các thao tác trên toàn bộ hệ thống ứng dụng hoặc thao tác tại màn hình
hiển thị (tìm kiếm, chỉnh sửa, xóa…).
o Thao tác chuyển đến các giao diện khác nhau trong cùng một màn hình hiển thị
(tabhost, list navigation…).
- Những tính năng nào không thể hiện hết thì sẽ nằm trong dấu ba chấm dạng dọc ở cuối
Action Bar, gọi là Action Overflow.
- ActionBar có từ phiên bản Android 3.0 (API level 11).
- Các tổ hợp điều khiển trên ActionBar:
o App Icon: thường là logo của ứng dụng hoặc bất kỳ Icon nào mà bạn muốn.
o View Control: thường hiển thị Title cho nội dung màn hình hiện tại, có thể tùy
chỉnh thành một Spinner.
o Action Button: chứa một số Button để thực hiện chức năng quan trọng.
o Action Overflow: Chứa một Menu Dropdown các chức năng hiển thị.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 28


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.6. ActionBar.

2.2. Tạo ActionBar


- Tạo một tập tin menu cho ActionBar trong thư mục res/menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
>
<item
android:id="@+id/action_search"
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/ic_action_search"
android:showAsAction="ifRoom"
android:title="@string/action_search"/>
<item
android:id="@+id/action_location_found"
android:icon="@drawable/ic_action_location_found"
android:showAsAction="ifRoom"
android:title="@string/action_location_found"/>
<item
android:id="@+id/action_refresh"
android:icon="@drawable/ic_action_refresh"
android:showAsAction="ifRoom"
android:title="@string/action_refresh"/>
<item
android:id="@+id/action_help"
android:icon="@drawable/ic_action_help"
android:showAsAction="ifRoom"
android:title="@string/action_help"/>
<item

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 29


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

android:id="@+id/action_check_updates"
android:icon="@drawable/ic_action_refresh"
android:showAsAction="ifRoom"
android:title="@string/action_check_updates"/>
</menu>

- Đối với mỗi thẻ item sẽ có một số thuộc tính quan trọng sau:
o android:id - id của Action Button.
o android:icon - icon hiển thị cho chức năng.
o android:title - tiêu đề cho chức năng.
o android:showAsAction - Xác định việc hiển thị cho Action Button.

- Tiếp tục, mở MainActivity ra và thực hiện kéo tập tin Menu vừa tạo vào cho ứng dụng.
Chúng ta sẽ thực hiện việc này trong phương thức onCreateOptionsMenu():
public booleanonCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar
if it is
present.
getMenuInflater().inflate(R.menu.action_bar_menu, menu);
return true;
}

- Khai báo sử dụng ActionBar trong Java Code:


// android.support.v7.app.ActionBar
ActionBar actionBar = getSupportActionBar();
// android.app.ActionBar
ActionBar actionBar = getActionBar();

2.3. Thao tác với ActionBar


- Chúng ta sẽ kích hoạt các chức năng khi chạm vào các Action Button. Việc này sẽ được
thực hiện trong onOptionsItemSelected():
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search:
return true;

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 30


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

case R.id.action_location_found:
LocationFound();
return true;
case R.id.action_help:
return true;
case R.id.action_refresh:
return true;
case R.id.action_check_updates:
return true;
default:
return true;
}
}

- Tiếp theo, chúng ta tìm hiểu việc hiển thị và ẩn thành Action Bar. Có 2 phương thức rất
đơn giản, đó là hide() và show()
actionBar.show();
actionBar.hide();

- Lưu ý: ứng dụng sử dụng việc hiển thị - giấu ActionBar liên tục có thể thay thế bằng
chế độ Overlay trên Android 4.3 và 4.4.
- Thay đổi App Icon cho Action Bar. Chúng ta sử dụng phương thức setIcon() để thay
đổi App Icon trên Action Bar
actionBar.setIcon(R.drawable.ico_actionbar);

- SplitActionBar: cơ chế cho phép hiển thị ActionBar ở dạng chia đôi khi có nhiều item.
o Sử dụng:
 Khai báo thuộc tính uiOptions="splitActionBarWhenNarrow“ trong thẻ
<activity>.
o Ví dụ khai báo cho SplitActionBar cho các phiên bản cũ hơn: Cần khai báo thêm
thẻ <meta-data>

<manifest ...>
<activity uiOptions="splitActionBarWhenNarrow" ... >

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 31


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

<meta-data android:name="android.support.UI_OPTIONS"
android:value="splitActionBarWhenNarrow" />
</activity>
</manifest>

- Navigation Up Icon: chế độ hiển thị và tương tác với biểu tượng ActionBar cho phép
người dùng có thể quay về màn hình trước đó ứng dụng (tùy thuộc ngữ cảnh).
o Sử dụng: khai báo thông qua phương thức setDisplayHomeAsUpEnable()
o Ví dụ:
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
o Navigation Up Icon:
 Khai báo sử dụng trong AndroidManifest.xml
 Ví dụ:
<activity
android:name=“com.htsi.t3h.SecondActivity"
android:label="@string/title_activity_display_message“

android:parentActivityName="com.htsi.t3h.MainActivity”>

<!– Hỗ trợ khai báo cho các phiên bản cũ hơn-->


<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.htsi.t3h.MainActivity" />

</activity>

3. CHẾ ĐỘ ĐIỀU HƯỚNG


- NavigationMode: thực hiện khai báo chế độ điều hướng thông qua phương thức
setNavigationMode.
- NavigationMode cho phép hiển thị dữ liệu màn hình ở hai chế độ:
o Tab:
 Dữ liệu màn hình bao gồm nhiều trang, mỗi trang được điều hướng hiển
thị theo tab của ActionBar.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 32


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.7. NavigationMode - Tab.


 Khai báo:
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

 Xây dựng Tab:


 Gọi phương thức newTab(): đối tượng trả về - Tab.
 Thiết lập bộ lắng nghe – setTabListener.
 Biểu tượng – setIcon..
 Tiêu đề cho từng Tab – setText.
 Gắn Tab vào ActionBar thông qua phương thức addTab, tham số
truyền vào là một đối tượng Tab.
 Ví dụ khai báo sử dụng:
Tab tab = actionBar.newTab()
.setText(R.string.artist)
.setTabListener(new
TabListener<ArtistFragment>(
this, "artist",
ArtistFragment.class));
actionBar.addTab(tab);

tab = actionBar.newTab()
.setText(R.string.album)
.setTabListener(new
TabListener<AlbumFragment>(
this, "album", AlbumFragment.class));
actionBar.addTab(tab);

o List:
 Dữ liệu màn hình có thể bao gồm nhiều trang hoặc chế độ hiển thị, mỗi
chế độ được chọn lựa từ Spinner thiết lập trên ActionBar.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 33


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.8. NavigationMode - List.


 Khai báo:
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

 Xây dựng List:


 Tạo đối tượng SpinnerAdapter.
 Khai báo bộ lắng nghe sự kiện trên List – OnNavigationListener.
 Gọi phương thức setListNavigationCallbacks, tham số truyền vào
là một adapter và bộ lắng nghe sự kiện.
 Ví dụ khai báo sử dụng :
// Khai báo Adapter
SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource
(this, R.array.action_list,

android.R.layout.simple_spinner_dropdown_item);
// OnNavigationListner
OnNavigationListner mNavigationCallback= new
OnNavigationListener() {…}
// Thiết lập Adapter và lắng nghe sự kiện
actionBar.setListNavigationCallbacks(mSpinnerAdapter,

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 34


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

mNavigationCallback);

4. TOOLBAR
4.1. Giới thiệu
Từ phiên bản API 21 (Android 5.0 Lollipop), Android hỗ trợ Toolbar để thay thế ActionBar.
Toolbar được xem là bản cải tiến của ActionBar và được kết thừa từ ViewGroup, vẫn có thể
dùng một số thuộc tính hay phương thức của ActionBar như thêm Logo, Labels, Navigation
items… và có bổ sung thêm các phương thức để giúp thay đổi màu, tùy chỉnh kích thước hay
có thể thiết lập bất kỳ vị trí hiển thị trên giao diện… Có thể thiết lập hiển thị Toolbar cho
Activity nào đó bằng phương thức “setActionBar()”.
Toolbar cùng lúc có thể chứa các yếu tố sau:
- A Navigation Button. Nó có thể là Up arrow, navigation menu toggle, close, collapse,
done hay một số hình ảnh mà bạn tự thiết kế.
- A branded logo image. Có thể thiết lập chiều cao cho logo, thiết lập khoảng cách tùy ý.
- A title and subtitle. Thiết lập tiêu đề cho Toolbar, nhưng có thể nó sẽ bị che lấp khi ta
thiết lập logo quá lớn.
- One or more custom views. Có thể thiết lập một hoặc nhiều View do chúng ta tùy
chình. Để thiết lập vị trí hiển thị chúng ta cần thông qua lớp “Toolbar.LayoutParams”,
chẳng hạn như canh giữa theo chiều ngang thì chúng ta dùng biến cờ
CENTER_HORIZONTAL thông qua Gravity, vị trí được canh giữa trên không gian
trống còn lại (tức là nếu chúng ta đã thiết lập logo cho Toolbar rồi thì không đối tượng
View mà ta thêm vào thì sẽ nằm ở vị trí trống còn lại và được canh giữa theo chiều
ngang).
- An action menu. Cũng giống như thanh ActionBar, “menu” sẽ mằm ở vị trí cuối của
Toolbar.

4.2. Tạo ToolBar


- Xóa ActionBar cũ.
Chúng ta cần xóa ActionBar cũ ra khỏi theme. Mở thư mục res -> value -> styes.xml và
viết lại như bên dưới. Chúng ta chọn theme Theme.AppCompat.Light.NoActionBar
để không hiển thị ActionBar.
<resources>
<style name="AppTheme"
parent="Theme.AppCompat.Light.NoActionBar">
</style>
</resources>

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 35


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Đến file xml để thêm Toolbar cho giao diện. Chúng ta nên thêm vào giao diện khi
chúng ta cần. Vì Toolbar là một ViewGroup nên có thể thêm ở các ViewGroup và có
thể thiết lập các thuộc tính ID, color, width và height. Chúng ta có thể thêm thuộc tính
margins (left và right) bằng cách dùng contentInsetEnd và contentInsetStart.
<Android.support.v7.widget.Toolbar

xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="#ff696969"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
></Android.support.v7.widget.Toolbar>

- Thiết lập cho lớp Activity.


Chúng ta cần kế thừa lớp ActionBarActivity cho Activity. Và dùng thư viện
Theme.AppCompat.Light.NoActionBar và Android.support.v7.widget.Toolbar.
import android.support.v7.widget.Toolbar;
import android.support.v7.app.ActionBarActivity;
public class MainActivity extends ActionBarActivity{
}

- Truy xuất và sử dụng Toolbar.


Lấy Toolbar ở file xml đã thiết lập bằng phương thức findViewById(). Thiết lập
Toolbar giống như một ActionBar bằng phương thức setSupportActionBar().
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

4.3. Thao tác với Toolbar


- Thiết lập menu cho Toolbar.
Tạo menu thông qua phương thức “inflateMenu()”, ví dụ: toolbar.inflate(R.menu.
toolbar_menu), ta sẽ thiết kế toolbar_menu để truyền vào phương thức này như sau:
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.tqky.toolbar.MainActivity" >

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 36


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

<item android:id="@+id/action_search"
android:title="@string/action_search"
android:icon="@drawable/ic_search"
android:showAsAction="ifRoom" />

<item android:id="@+id/action_share"
android:title="@string/action_share"
android:icon="@drawable/ic_share"
android:showAsAction="ifRoom" />

<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
android:showAsAction="never" />
</menu>

Bắt lại sự kiện khi người dùng tương tác lên các item của menu.
toolbar.setOnMenuItemClickListener(new
Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {

switch (menuItem.getItemId()){
case R.id.action_share:
Toast.makeText(MainActivity.this,
"Share",
Toast.LENGTH_SHORT).show();
return true;
}

return false;
}
});

- Thiết lập Navigation Icon.


Thiết lập icon thông qua phương thức “setNavigationIcon()”. Bắt sự kiện khi nhấn vào
icon thông qua phương thức “setNavigationOnClickListener()”.
toolbar.setNavigationIcon(R.drawable.ic_launcher);
toolbar.setNavigationOnClickListener(new

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 37


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"Navigation",Toast.LENGTH_SHORT)
.show();
}
});

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 38


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 4
ACTION PROVIDER
VÀ ĐIỀU KHIỂN TÌM KIẾM

1. ACTION PROVIDER
- ActionProvider (API Level 14) là một dạng menu được đính kèm để chúng ta có thể
thao tác nhanh ngay trên ActionBar. Trong trường hợp cụ thể, chúng ta sẽ nghiên cứu
về ShareActionProvider – một dạng menu chia sẻ rất tiện lợi.
- ShareActionProvider có từ API level 14.

Hình 1.1. Chia sẻ hình với ShareActionProvider.

- Để tạo ra một ShareActionProvider chúng ta chỉ việc khai báo thuộc tính
android:actionProviderClass trong cặp thẻ <item> của file tài nguyên menu.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_item_share"
android:showAsAction="ifRoom"
android:title="Share"

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 39


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

android:actionProviderClass=
"android.widget.ShareActionProvider" />
</menu>

- Xử lý sự kiện với ShareActionProvider:


private ShareActionProvider mShareActionProvider;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate menu resource file.
getMenuInflater().inflate(R.menu.share_menu, menu);

// Locate MenuItem with ShareActionProvider


MenuItem item = menu.findItem(R.id.menu_item_share);

// Fetch and store ShareActionProvider


mShareActionProvider =

(ShareActionProvider)item.getActionProvider();

// Return true to display menu


return true;
}
// Call to update the share intent
private void setShareIntent(Intent shareIntent) {
if (mShareActionProvider != null) {
mShareActionProvider.setShareIntent(shareIntent);
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 40


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2. ĐIỀU KHIỂN TÌM KIẾM


- ActionView là dạng điều khiển hiển thị trên ActionBar cho phép thực hiện các chuỗi
thao tác trên cùng một điều khiển để thay đổi dữ liệu.
- Khai báo sử dụng thông qua hai thuộc tính:
o actionLayout.
o actionViewClass.
- SearchView: Trong ứng dụng, khi thực hiện thao tác với khối dữ liệu lớn, hoặc muốn
truy xuất ngay tức thời một tập tin nào đó, người dùng thường hay bối rối và mất nhiều
thời gian để tìm ra chúng. Ở bài này chúng ta tích hợp điều khiển tìm kiếm SearchView
như một thành phần của ActionBar.

Hình 1.2. SearchView.

Ví dụ sau đây sẽ hướng dẫn chi tiết về ứng dụng của điều khiển tìm kiếm này.
- Thực hiện kéo ListView vào tập tin activity_main.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<ListView
android:id="@+id/listCountries"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 41


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

</ListView>
</RelativeLayout>

- Sau đó trong thư mục res/menu tạo tập tin search_view.xml thực hiện khai báo như sau:

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


<menu xmlns:android="http://schemas.android.com/apk/res/android"
>
<item android:id="@+id/action_search"
android:title="@string/search"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="always"
android:actionViewClass="android.widget.SearchView" />
</menu>

- Cho lớp MainActivity thực thi giao diện onQueryTextListener và tiến hành khai báo
các biến cần thiết.

public class MainActivity extends Activity implements


OnQueryTextListener{
private SearchView mSearchView;
private ListView mListView;
String[] COUNTRIES = {"Belgium","Canada","France",
"Germany","Italy","Vietnam",
"Croatia", "Japan", "Finland",
"Venezuela", "Greek", "India"};
ArrayAdapter<String> adapter;

- Trong hàm onCreate thực hiện khởi tạo và tham chiếu giá trị cho các biến đã khai báo ở
trên:

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 42


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, COUNTRIES);
mListView = (ListView)
findViewById(R.id.listCountries);
mListView.setAdapter(adapter);
}

- Override phương thức onCreateOptionMenu để thực hiện gọi SearchView từ thanh


ActionBar và gán sự kiện.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_view, menu);
MenuItem itemSearch =
menu.findItem(R.id.action_search);
mSearchView = (SearchView) itemSearch.getActionView();
mSearchView.setOnQueryTextListener(this);
return true;
}

- Cuối cùng thực thi hai phương thức truy vấn dữ liệu khi người dùng nhập váo khung
SeachView, ở đây đơn giản ta gọi phương thức filter để Adapter tự sắp xếp dữ liệu.
@Override
public boolean onQueryTextChange(String newText) {
//Instant Search
if (TextUtils.isEmpty(newText)) {

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 43


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

adapter.getFilter().filter("");
mListView.clearTextFilter();
}else {
adapter.getFilter().filter(newText.toString());
}
return true;
}

- Thực hiện chạy ứng dụng: bấm vào biểu tượng tìm kiếm, một EditText sẽ xuất hiện,
tiến hành nhập liệu. Và ListView sẽ tự động tìm kiếm và sắp xếp dữ liệu cho chúng ta.

Hình 1.3. Hiển thị kết quả tìm kiếm với SearchView.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 44


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 5
CÁC CHUYỂN HOẠT
TRONG ỨNG DỤNG

1. PROPERTY ANIMATION
- Property Animation là dạng chuyển hoạt hổ trợ chúng ta trong việc lập trình các chuyển
hoạt cho các thuộc tính của một đối tượng nào đó bằng các thay đổi 2 giá trị 0 và 1. Ví
dụ, khi ta có thể thay đổi màu sắc, độ trong suốt để làm hiệu ứng xuất hiện và biến mất
của đối tượng, hoặc thay đổi các kích thước dòng chữ chẳng hạn.
- Được giới thiệu từ phiên bản Android 3.0 (API 11) có thể nói đây là bộ công cụ mạnh
mẽ trong việc lập trình chuyển hoạt bởi vì chúng ta có thể ứng dụng nó vào bất kỳ
thuộc tính nào chúng ta muốn.
- Mỗi chuyển hoạt sẽ được chứa trong một tập tin XML riêng biệt trong thư mục
res/animator. Giống như Layout và Drawable, tên của tập tin sẽ được sử dụng làm định
danh cho chuyển hoạt đó. Việc định nghĩa các chuyển hoạt chỉ đơn giản là gán một giá
trị cho một thuộc tính nào đó, sau đó cấp phát cho đối tượng thực hiện chuyển hoạt đó.
-

Hình 1.1. Ví dụ mô tả Property Animation.


Ví dụ sau đây mô tả việc thay đổi thuộc tính độ trong suốt của một đối tượng bằng cách thiết
lập thuộc tính alpha, tăng dần giá trị từ 0 đến 1 trong khoảng thời gian là 10 giây.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 45


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Tạo file alpha_anim.xml trong thư mục res/animator:


<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="10000"
android:propertyName="alpha"
android:valueFrom="0.0"
android:valueTo="1.0" >
</objectAnimator>

- Tham chiếu và sử dụng trong Java code:


TextView txtHello = (TextView) findViewById(R.id.txtHello);
ObjectAnimator animOb = (ObjectAnimator)
AnimatorInflater.loadAnimator(getApplicationContext(),

R.animator.alpha_anim);
animOb.setTarget(txtHello);
animOb.start();

2. VIEW ANIMATION
2.1. Tween Animation
- Mỗi chuyển hoạt được chứa trong tập tin XML trong thư mục res/anim với các hiệu
ứng sau: alpha (ẩn hiện mờ), scale (cân chỉnh tỉ lệ), translate (chuyển động) và rotate
(quay góc). Mỗi hiệu ứng bao gồm các cặp thuộc tính và giá trị như bảng sau:

Hiệu ứng Thuộc tính Giá trị


Alpha fromAlpha/toAlpha Từ 0 đến 1 (số thực)
Scale fromXScale/toXScale Từ 0 đến 1 (số thực)
fromYScale/toYScale Từ 0 đến 1 (số thực)

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 46


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

pivotX/pivotY Tỉ lệ chiều ngang và chiều dọc từ 0% đến 100%


Translate fromX/toX Từ 0 đến 1 (số thực)
fromY/toY Từ 0 đến 1 (số thực)
Rotate fromDegrees/toDegrees Từ 0 đến 360 (số thực)
pivotX/pivotY Tỉ lệ chiều ngang và chiều dọc từ 0% đến 100%

- Chúng ta có thể sử dụng cặp thẻ set để thiết lập nhiều hiệu ứng với nhau. Khi đó, các
hiệu ứng sẽ được bổ sung các một số thuộc tính để chỉnh sửa thời điểm và cách thức
mỗi hiệu ứng sẽ thực thi. Danh sách các thuộc tính như sau:
o duration – thời gian thực thi tất cả hiệu ứng, tính bằng mili giây.
o startOffset – độ trễ trước khi hiệu ứng bắt đầu.
o fillBeforetrue – cho phép biến đổi các hiệu ứng trước khi thực thi chuyển hoạt.
o fillAftertrue – cho phép biến đổi các hiệu ứng sau khi kết thúc chuyển hoạt.
o interpolator – thiết lập tốc độ của hiệu ứng thay đổi theo thời gian, để sử dụng
thuộc tính này ta sẽ tham chiếu đến tài nguyên chuyển hoạt của hệ thống
android:anim/interpolatorName.
- Nếu không thiết lập thuộc tính startOffset, tất cả hiệu ứng sẽ cùng thực thi đồng bộ với
nhau.
Ví dụ sau sẽ mô tả chuyển hoạt quay đối tượng một góc 360 độ, rung và mờ dần:
- Tạo file shrink_anim.xml trong thư mục res/anim:
<?xml version="1.0" encoding="utf-8"?>
<set android:interpolator="@android:anim/accelerate_interpolator"
xmlns:android="http://schemas.android.com/apk/res/android">

<rotate
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="0%"
android:startOffset="500"
android:duration="1000"/>

<scale
android:fromXScale="1.0"
android:toXScale="0.0"

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 47


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

android:fromYScale="1.0"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="500"
android:duration="500" />

<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:startOffset="500"
android:duration="500" />
</set>

- Tham chiếu và sử dụng trong Java Code:


AnimationSet anim_shrink = (AnimationSet)
AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.shrink_anim);
txtHello.startAnimation(anim_shrink);

2.2. Frame Animation


- Frame animation là sự kiện diễn ra một chuỗi các chuyển hoạt được lồng ghép bởi
nhiều hình ảnh khác nhau. Mỗi hình ảnh sẽ được thiết lập một thời gian để thực hiện.
Do các chuyển hoạt liên quan đến tài nguyên dạng Drawable nên các tập tin Frame-by-
Frame Animation sẽ được lưu trong thư mục tài nguyên res/drawable và tên tập tin sẽ
được dùng như định dạng để tham chiếu sử dụng.
- Có thể tạo frame animation trong thư mục res/drawable vì frame animation cũng được
xem như một dạng hình ảnh.
Ví dụ sau minh họa về chuyển hoạt đơn giản của các hình ảnh, mỗi hình ảnh sẽ được thể hiện
trong một phần tư giây.
- Tạo file fizz_utl_animation.xml trong thư mục res/drawable:
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/shark1"
android:duration="250"></item>

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 48


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

<item android:drawable="@drawable/shark2"
android:duration="250"></item>
<item android:drawable="@drawable/shark3"
android:duration="250"></item>
<item android:drawable="@drawable/shark4"
android:duration="250"></item>
<item android:drawable="@drawable/shark5"
android:duration="250"></item>
<item android:drawable="@drawable/shark6"
android:duration="250"></item>
<item android:drawable="@drawable/shark7"
android:duration="250"></item>
<item android:drawable="@drawable/shark8"
android:duration="250"></item>
<item android:drawable="@drawable/shark9"
android:duration="250"></item>
</animation-list>

- Tham chiếu và sử dụng trong Java Code:


ImageView imgFizz = (ImageView) findViewById(R.id.imgFizz);
imgFizz.setBackgroundResource(R.drawable.fizz_utl_animation);
AnimationDrawable animFizz = (AnimationDrawable)
imgFizz.getBackground();
animFizz.start();

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 49


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.2. Ví dụ mô tả Frame Animation.

3. DRAWABLE ANIMATION
- Thư mục tài nguyên: res/drawable/filename.xml.
o Khai báo các thuộc tính trong XML:
AnimationDrawable - <animation-list>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] >
<item
android:drawable="@[package:]drawabledrawable_resource_name"
android:duration="integer" />
</animation-list>

- Ví dụ khai báo Drawable Animation:


exam_drawable_anim.xml:
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false”>
<item android:drawable="@drawable/plane01”
android:duration="200" />
<item android:drawable="@drawable/plane02”
android:duration="200" />
<item android:drawable="@drawable/plane01”
android:duration="200" />
</animation-list>

- Tham chiếu và sử dụng trong Java code:


o Thực hiện truy xuất đối tượng AnimationDrawable từ đối tượng View đang hiển
thị Drawable, bằng phương thức getBackgroundResource().
o Gọi phương thức start() từ đối tượng AnimationDrawable.
Ví dụ tham chiếu AnimationDrawable:

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 50


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

ImageView planeView = (ImageView) findViewById(R.id.plane);


planeView.setBackgroundResource(R.drawable.exam_drawable_anim);
AnimationDrawable plane =
(AnimationDrawable)planeView.getBackground();
plane.start();

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 51


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 6
ASYNCTASK - THREAD – HANDLER

1. THREAD VÀ MULTITHREADING
1.1. Thread
Trong lập trình ứng dụng cho di động, một trong những vấn đề quan trọng cần giải quyết đó là
tài nguyên hạn hẹp của các thiết bị động. Các thiết bị di động hầu hết có tài nguyên rất hạn
chế, ngày nay tuy đã được cải thiện rất nhiều (nâng cấp CPU, GPU, RAM…), nhưng nhìn
chung lại, không thế chạy ứng dụng trên các thiết bị di động như trên PC, laptop… Do đó, việc
xử lí các thuật toán cần phải tinh giản và thực hiện một cách nhanh nhất có thể để có thể tiết
kiệm được chi phí tài nguyên.
Thread là đơn vị nhỏ nhất của tiến trình được định thời bởi hệ điều hành và được bao hàm
trong các tiến trình thực thi của máy tính. Mỗi một thread có một callstack cho các phương
thức, đối số và biến cục bộ của thread đó.
Android chạy trên một hệ điều hành nhân Linux. Các ứng dụng của Android được viết bằng
ngôn ngữ Java, và chúng chạy trong một máy ảo, đó không phải máy ảo Java(JVM) mà là máy
ảo Dalvik (Dalvik Virtual Machine). Mỗi một máy ảo Android khi chạy đều có ít nhất một
thread chính khi khởi động và có thể còn vài thread khác dùng để quản lý các tiến trình đang
chạy. Ứng dụng có thể tự khởi động thêm các thread phụ vào các mục đích cụ thể. Các thread
trong cùng một máy ảo tác động qua lại và được đồng bộ hóa bằng cách sử dụng các đối tượng
chia sẻ và các monitor liên quan đến các đối tượng đó.
- Mỗi Thread có một độ ưu tiên (số nguyên từ 1 - 10) dùng để xác định lượng thời gian
CPU (CPU time ) mà thread có thể sử dụng dựa vào phương thức setPriority(int).
- Các phương thức của Thread như sleep(), wait() , notify() và notifyAll()…
- Để tạo ra một thread khác ngoài thread chính trên, chúng ta có 2 cách:
o Cách 1:
 Tạo 1 lớp mới kế thừa từ lớp java.lang.Thread và ghi đè lại phương thức
run() của lớp này:
public class MyThread extends Thread{
@Override
public void run() {
//do something }}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 52


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Sử dụng Thread:
MyThread t = new MyThread();
t.start();

o Cách 2:
 Tạo 1 lớp và cho lớp này implement Interface Runnable:
public class MyRunnable implements Runnable{
@Override
public void run() {
//xử lý
}
}

 Sử dụng thread:
MyRunnable b = new MyRunnable();
MyThread t = new MyThread(b);
t.start();

1.2. Multithreading
- Multithreading có nghĩa là đa luồng, nhiều thread. Với cơ chế đa luồng, các ứng dụng
của bạn có thể thực thi đồng thời nhiều dòng lệnh cùng lúc. Có nghĩa là bạn có thể làm
nhiều công việc đồng thời trong cùng một ứng dụng của bạn. Có thể hiểu một cách đơn
giản: hệ điều hành với cơ chế đa nhiệm cho phép nhiều ứng dụng chạy cùng lúc thì ứng
dụng với cơ chế đa luồng cho phép thực hiện nhiều công việc cùng lúc.
- Ưu điểm của việc sử dụng Multithreading:
o Các thread chia sẻ tài nguyên của tiến trình nhưng vẫn có thể được thực thi một
cách độc lập. Multi-thread sẽ rất hữu dụng khi dùng lập trình đa nhiệm.
o Các ứng dụng Multi-thread chạy nhanh hơn trên các máy tính hỗ trợ xử lý đa
luồng.
- Nhược điểm:
o Khó khăn trong việc lập trình, việc sử dụng multithreading không hề dễ dàng,
đòi hỏi lập trình viên có kinh nghiệm.
o Khó khăn trong việc quản lí.
o Có khả năng tiềm tàng xảy ra tình trang deadlock.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 53


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

1.3. Handler
- Handler là đối tượng cho phép gửi, xử lí các thông điệp và các đối tương Runable có
liên quan đến hàng đợi thông điệp. Mỗi Handler có thể liên kết với một thread và hàng
đợi thông điệp của thread đó.
- Bạn có thể tạo ra một thread của riêng bạn và giao tiếp ngược với main thread của ứng
dụng thông qua một Handler. Điều này được thực hiện bằng cách gọi sendMessage
nhưng từ thread mới của bạn.
- Tạo một đối tượng Handler và ghi đè lại phương thức handleMessage để bắt và xử lý
các thông điệp liên lạc.
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//Kiểm tra message
if(msg != null){
//Xử lý message nhận được từ Thread

}
return true;
}
});

- Thread sẽ gửi tin nhắn lên Handler và Handler đóng vai trò kiểm tra tin nhắn là gì và
làm những việc tương ứng.
- Ta chú ý các phương thức sendMessage sau:
o sendMessage(): gửi tin nhắn lên Handler ngay lập tức.
o sendMessageAtFrontOfQueue(): gửi tin nhắn lên Handler và tin nhắn đó sẽ ưu
tiên giải quyết trước.
o sendMessageAtTime(): gửi tin nhắn vào thời điểm chỉ định trước.
o sendMessageDelayed(): gửi tin nhắn vào Handler sau một khoảng thời gian nhất
định.
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Message mss = new Message();
mss.arg1 = 1;
handler.sendMessage(mss);
}
});
t1.start();

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 54


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2. ASYNCTASK
- AsyncTask là đối tượng cho phép bạn thực hiện hành động xử lý phía background
(Thread ngầm) và trả kết quả lên UI thread (Thread chính) mà không cần phải xử lý
Thread hoặc Handler.
- Khi ứng dụng của bạn thực hiện một tác vụ dài, chiếm một khoảng thời gian nhất định.
Ví dụ như khi click nút Login, ứng dụng phải gửi request lên server để xử lý và trả kết
quả về. Nếu làm theo kiểu bình thường thì ứng dụng của bạn sẽ có cảm giác bị treo và
chậm, gây ảnh hưởng đến trải nghiệm người dùng. Trong tình huống này, để giải quyết
vấn đề chúng ta có thể sử dụng AsyncTask.
- Trong AsyncTask<Params, Progress, Result> có 3 đối số là các Generic Type:
o Params: Là giá trị (biến) được truyền vào khi gọi thực thi tiến trình và nó
sẽ được truyền vào doInBackground.
o Progress: Là giá trị (biến) dùng để update giao diện diện lúc tiến trình thực thi,
biến này sẽ được truyền vào hàm onProgressUpdate.
o Result: Là biến dùng để lưu trữ kết quả trả về sau khi tiến trình thực hiện xong.
 Những đối số nào không sử dụng trong quá trình thực thi tiến trình thì ta
thay bằng kiểu Void.
- Thông thường trong một AsyncTask sẽ chứa 4 hàm, đó là :
o onPreExecute(): Tự động được gọi đầu tiên khi tiến trình được kích hoạt.
o doInBackground(): Được thực thi trong quá trình tiến trình chạy nền, thông qua
hàm này để ta gọi hàm onProgressUpdate để cập nhật giao diện (gọi
lệnh publishProgress). Ta không thể cập nhật giao diện trong
hàm doInBackground().
o onProgressUpdate(): Dùng để cập nhật giao diện lúc runtime.
o onPostExecute(): Sau khi tiến trình kết thúc thì hàm này sẽ tự động xảy ra. Ta có
thể lấy được kết quả trả về sau khi thực hiện tiến trình kết thúc ở đây.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 55


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.1. Thứ tự hoạt động của các hàm trong AsyncTask.
Ví dụ:

public class MainActivity extends Activity {


long startMillis;
TextView txtHello;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtHello = (TextView)
findViewById(R.id.txtHello);
MyAsyncTask myAsyncTask = new
MyAsyncTask();
myAsyncTask.execute();
}

- Tạo lớp MyAsyncTask kế thừa từ lớp AsyncTask:


private class MyAsyncTask extends AsyncTask<String, Integer,
Void>{

@Override
protected void onPreExecute() {

super.onPreExecute();

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 56


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

startMillis = System.currentTimeMillis();
Log.d("Test", "onPreExecute");
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.d("Test", "Công việc đang làm..." + values[0]);
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Log.d("Test", "Thời gian kết thúc: "
+ (System.currentTimeMillis()-startMillis)/1000
+ " giây");
Log.d("Test", "Công việc hoàn thành.");
}
@Override
protected Void doInBackground(String... arg0) {
Log.d("Test", "doInBackground");
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(2000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
- Lưu ý:
o Đối tượng của AsyncTask chỉ được dùng trong UI thread (Thread chính của ứng
dụng).
o Các phương thúc onPostExecute, onPreExecute, onProgressUpdate chỉ là tùy
chọn.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 57


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 7
SERVICE – BROADCAST RECEIVER
VÀ NOTIFICATION

1. SERVICE
1.1. Giới thiệu
- Service được xem như một thành phần chạy ngầm phía bên dưới và hầu như không cần
giao diện để tương tác với người dùng, có thể ví dụ một số tác vụ tiêu tốn nhiều thời
gian như truy xuất, cập nhật dữ liệu, nhận và xử lý các thông báo người dùng, …
- Service giống như Activity thực hiện theo chu kỳ thời gian để quản lý sự thay đổi của
trạng thái.
- Trong AndroidManifest.xml cần phải khai báo:
<service android:name="com.your-company.MyService" />
trong cặp thẻ <application>
- Service chạy trên Main Thread nên có thể gây cản trở các tác vụ khác.
- Có 2 loại Service:
o “Started” Service: Service được gọi khi thành phần của ứng dụng gọi nó bằng
phương thức startService(). Và service sẽ chạy vô thời hạn. Loại service này
thực hiện công việc đơn lẻ như download, tính toán và service sẽ dừng một khi
công việc hòan thành.
o “Bound” Service: Service được gọi khi thành phần của ứng dụng gọi nó bằng
phương thức bindService(). Loại service đề nghị giao diện Client – Server cho
phép thành phần ứng dụng tương tác với nó, gửi yêu cầu, lấy kết quả. Một khi tất
cả thành phần ứng dụng ngừng liên kết, thì Service kết thúc .
- Vòng đời:

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 58


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.1. Mô tả vòng đời của Service.


1.2. Tạo Service
Ví dụ sau sẽ tạo một service có chức năng tính toán và trả về kết quả của phương thức cộng 2
số nguyên.
- Tạo một lớp có tên là MyService mở rộng từ lớp Service như sau:
public class MyService extends Service {
// Binder cho cac client
private final IBinder mBinder = new LocalBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
// Trả về đối tượng MyService để cho client có thể gọi
public method MyService getService() {
return MyService.this;

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 59


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

}
}
//Viết phương thức cho các client có thể gọi.
public int cong2So(int a, int b){
return a + b ;
}
}

- Trong MainActivity khai báo biến, khởi tạo các đối tượng giao diện:

Hình 1.2. Màn hình ứng dụng gọi Service cộng 2 số.

public class MainActivity extends Activity implements


OnClickListener{
TextView txtResult;
Button btnCallService;
MyService mService;
boolean mBound;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 60


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

setContentView(R.layout.activity_main);
txtResult = (TextView) findViewById(R.id.txtResult);
btnCallService = (Button)
findViewById(R.id.btnCallService);
btnCallService.setOnClickListener(this);
}
}

- Tạo một đối tượng ServiceConnection chuyên dùng quản lý việc đóng mở kết nối đến
Service. Overide 2 phương thức onServiceDisconnected() và onServiceConnected() sau
nhằm bound đến MyService:
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
@Override
public void onServiceConnected(ComponentName name, IBinder
service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
};

- Trong hàm OnStart(): chúng ta dùng phương thức bindService(parameter) để gọi đến
MyService thông qua đối tượng Intent:
@Override
protected void onStart() {

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 61


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

super.onStart();
Intent i = new Intent(this, MyService.class);
bindService(i, mConnection, Context.BIND_AUTO_CREATE);
}

- Trong hàm onStop(): Ngắt kết nối đến MyService


protected void onStop() {
super.onStop();
if(mBound){
mService.unbindService(mConnection);
mBound = false ;
}
}

- Cuối cùng trong phương thức onClick của button ta gọi đến hàm cong2so(int,int) và
hiển thị kết quả trả về ra TextView:
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnCallService:
if(mBound){
//Cho service cộng 2 số 5 5
int result = mService.cong2So(5, 5);
txtResult.setText(String.valueOf(result));}
break;
default: break;
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 62


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

1.3. IntentService
- IntentService, đây là Service chạy độc lập với Main Thread của bạn, nó sẽ chạy
Background và thực hiện nền những gì bạn cần mà không ảnh hưởng đến Main Thread.
- Ví dụ:
public class HelloIntentService extends IntentService{
public HelloIntentService() {
super("HelloIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
long endTime = System.currentTimeMillis() +
5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime -
System.currentTimeMillis());
} catch (Exception e) {}
}
}
}
}

2. BROADCAST RECEIVER
2.1. Tạo BroadcastReceiver
- Broadcast Receiver là bộ tiếp nhận và xử lý các Intent dựa trên các chỉ định của chúng
ta. Thành phần này sẽ cho phép mở các ứng dụng để xử lý các Intent tương ứng được
gửi lên từ hệ thống.
- Trong ứng dụng Android, đôi khi bạn cần phải nhận được tín hiệu nếu như một sự kiện
nào trong trên thiết bị được kích hoạt để xử lý cho các ứng dụng tốt hơn. Các sự kiện ví
dụ như là pin sắp cạn, máy vừa được khởi động hoặc một ứng dụng vừa được cài đặt

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 63


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

trên máy ..., khi đó, sử dụng Broadcast Receiver sẽ giúp chúng ta bắt được các sử kiện
này khi chúng bị kích hoạt.
- Để tạo một BroadcastReceiver, ta sẽ tạo một lớp kế thừa từ lớp BroadcastReceiver.
Ví dụ:
public class ConnectivityChangeReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Connectivity changed",
Toast.LENGTH_SHORT).show();
}
}

2.2. Đăng ký BroadcastReceiver


- Để đăng ký đối tượng của Broadcast receiver, sử dụng 2 cách:
o Đăng ký động với phương thức: Context.registerReceiver()
 Broadcast Receiver có thể được đăng ký trong Activity ở hàm
onResume() như sau:
@Override
protected void onResume() {
super.onResume();
mReceiver = new ConnectivityChangeReceiver();
registerReceiver(mReceiver,new
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
}

 Chúng ta cũng nên hủy đăng ký khi Activity trong hàm onPause():
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}

 Lưu ý: nếu tắt ứng dụng BroadcastReceive sẽ không còn lắng nghe.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 64


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Đăng ký trong Manifest.xml thông qua cặp thẻ <receiver/>


<receiver android:name="com.nghialt.ConnectivityChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

 Lưu ý: tự động lắng nghe kể cả khi đã đóng ứng dụng.

3. NOTIFICATION
- Một thông báo (Notification) là thành phần cho phép gửi các thông báo đến người dùng
mà không chiếm quá nhiều việc điều khiển của người dùng trên thiết bị. Ví dụ, khi nhận
được một tin nhắn hay một thư điện tử, thiết bị sẽ sử dụng Notification để thông báo
người dùng thông qua nhạc chuông, đèn nền, thể hiện biểu tượng trên thanh tác vụ, …

Hình 1.3. Các dạng thông báo với Notification.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 65


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Thông thường một thông báo được tự động kích hoạt nhằm thông báo tới người dùng là
ứng dụng đó đã hoàn thành một công việc nào đó. Bạn có thể kích chọn trực tiếp vào
thông báo đó để khởi chạy lại ứng dụng đó khi nó đang nằm trong trạng thái ngủ.
- Ví dụ sau đây sẽ tạo một thông báo với âm thanh và rung thiết bị.
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final int NOTIF_ID = 1234;
int icon = R.drawable.email;
long when = System.currentTimeMillis();
String title = "New E-mail";

NotificationManager notificationManager = (NotificationManager)

getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Builder(this);

Intent notificationIntent = new Intent(this,


MainActivity.class);
PendingIntent intent = PendingIntent.getActivity(this,

0,notificationIntent, 0);

buildersetSmallIcon(icon).setContentText("You have one


unread
message.").setWhen(when)
.setContentIntent(intent)
.setContentTitle(title);

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 66


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Notification notification = builder.build();


// Play default notification sound
notification.defaults |= Notification.DEFAULT_SOUND;
// Vibrate
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(NOTIF_ID, notification);
}

o Xin quyền nếu muốn rung thiết bị:


<uses-permission android:name="android.permission.VIBRATE"/>

Hình 1.4. Kết quả hiển thị Notification vừa tạo.

- Một số dạng hiển thị thông báo khác:


o Dialog:
 Dialog là dạng hộp thoại, một thành phần giao diện khá phổ biến trên các
phần mềm desktop, các trang web và cả những ứng dụng di động. Chúng
thường được sử dụng để tạo ra các tình huống cần sự xác nhận của người
dùng hoặc thể hiện các cảnh báo, lỗi khi người thao tác với ứng dụng.

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 67


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.5. Dialog.

 Có tất cả 3 kiểu hiển thị dialog:


 Sử dụng trực tiếp lớp Dialog hoặc kế thừa: ngoài lớp AlertDialog
để dùng chung Android còn xây dựng một số lớp khác để phục vụ
cho từng mục đích riêng biệt. Dialog là lớp được xây dựng và điều
khiển hoàn toàn trong Activily nên ta sẽ không cần khai báo trong
Manifest khi cần sử dụng.
 Activity sử dụng giao diện Dialog – chúng ta có thể áp đặt giao
diện Dialog cho các Activity thông thường để nó có thể hiện thị
như một Dialog chuẩn.
 Để tạo Dialog chỉ cần tạo mới thực thể thuộc lớp Dialog và thiết
lập tiêu đề cũng như giao diện cho Dialog bằng 2 phương thức
tương ứng setTitle và setContentView. Sau khi thiết lập ta chỉ cần
gọi phương thức show ở nơi mà chúng ta muốn hiện Dialog.
Ví dụ:
Dialog dialog = new Dialog(MainActivity.this);
dialog.setTitle(“Demo Dialog”);
//Thiết lập giao diện cho Dialog bằng layout
xml
dialog.setContentView(R.layout_dialog_layout);
dialog.show();
o Toast:
- Toast là một loại thông báo (message) ngắn. Hiển thị trong một khoảng thời gian nhất
định và tự động mất dần. Bạn có thể sử dụng trong trường hợp hiển thông báo trong các
mục thiết lập thông số cấu hình, hay đơn giản chỉ là hiển thị lên để xem thông tin tạm
thời nào đó (giống như để kiểm tra một vấn đề xảy ra chẳng hạn).

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 68


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Toast có thể được tạo và hiển thị trong Activity hoặc trong Servive.
- Không cho phép người sử dụng tương tác.
- Khi hiển thị sau khoảng thời gian nào đó sẽ tự đóng lại.
- Có 2 giá trị mặc định (ta nên sử dụng 2 giá trị này, không nên gõ con số cụ thể vào):
hằng số Toast.LENGTH_SHORT hiển thị trong 2 giây, Toast.LENGTH_LONG hiển
thị trong 3.5 giây.
Hình dưới đây cho bạn biết một Toast đang hiển thị:

Hình 1.6. Toast.

- Cú pháp để tạo một thông báo Toast:


Toast toast = Toast.makeText(YourActivity.this, “Hiển thị gì thì
ghi ở đây”,
Toast.LENGTH_SHORT);
toast.show();

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 69


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP. HCM

Mục lục

Bài 1: Lưu trữ, truy vấn và sắp xếp dữ liệu với SQLite................................................... 1

1. Khái niệm cơ sở dữ liệu (Database Concepts)................................................................... 1

2. Giới thiệu SQLite ............................................................................................................... 1

3. Xây dựng cơ sở dữ liệu với SQLite ................................................................................... 2

4. Truy vấn dữ liệu ................................................................................................................. 5

5. Sắp xếp dữ liệu .................................................................................................................. 9

Bài 2: Quản lý dữ liệu với Content Provider .................................................................... 12

1. Giới thiệu Content Provider ............................................................................................... 12

2. Xây dựng Content Provider cho ứng dụng ........................................................................ 15

3. Truy vấn dữ liệu hệ thống với Content Provider ............................................................... 17

Bài 3: Menu – Action Bar – ToolBar ................................................................................. 19

1. Menu .................................................................................................................................. 20

2. Action Bar .......................................................................................................................... 28

3. Chế độ điều hướng ............................................................................................................. 32

4. ToolBar .............................................................................................................................. 35

Bài 4: Action Provider và điều khiển tìm kiếm................................................................. 39

1. Action Provider .................................................................................................................. 39

2. Điều khiển tìm kiếm .......................................................................................................... 41

Bài 5: Các chuyển hoạt trong ứng dụng ............................................................................ 45

1. Property Animation............................................................................................................ 45

2. View Animation ................................................................................................................. 46

3. Drawable Animation .......................................................................................................... 50

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 70


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP. HCM

Bài 6: Asynctask – Thread – Handler ................................................................................ 52

1. Thread và Multithreading .................................................................................................. 52

2. Asynctask ........................................................................................................................... 55

Bài 7: Service – Broadcast Receiver và Notification ........................................................ 58

1. Service ............................................................................................................................... 58

2. Broadcast Receiver ............................................................................................................ 63

3. Notification ........................................................................................................................ 65

Tài liệu Lập trình thiết bị di động trên Android – Module 3 | 71


TRUNG TÂM TIN HỌC - ĐẠI HỌC KHOA HỌC TỰ NHIÊN

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH

CHƯƠNG TRÌNH ĐÀO TẠO

LẬP TRÌNH VIÊN CHUYÊN NGHIỆP TRÊN THIẾT BỊ DI ĐỘNG

TÀI LIỆU

LẬP TRÌNH THIẾT BỊ DI ĐỘNG TRÊN


ANDROID
MODULE 04:
LẬP TRÌNH ỨNG DỤNG CLIENT VÀ ỨNG DỤNG ĐA
PHƯƠNG TIỆN (SMS, Camera, …)

Tháng 06/2015
Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 1
KHAI THÁC TÀI NGUYÊN INTERNET

1. TỔNG QUAN TÀI NGUYÊN INTERNET


1.1. Tài nguyên Internet trên thiết bị di động
Ứng dụng trực tuyến trên thiết bị di động được xây dựng nhằm mục đích hiển thị dữ liệu đầu
cuối được xử lý từ các máy chủ cũng như gửi các yêu cầu về truy xuất dữ liệu. Ví dụ: ứng
dụng Goole Play Store được Google cài đặt trên thiết bị người dùng, hiển thị các ứng dụng
được phát triển bởi các lập trình viên, cho phép người dùng có thể tải và cài đặt các ứng dụng
đó ngay trên thiết bị của họ.
Khi xây dựng các ứng dụng trực tuyến cần xác định rõ nguồn tài nguyên được cung cấp:
- Định dạng tài nguyên (văn bản, hình ảnh…).
- Giao thức kết nối đến máy chủ (http, https, tcp, rtsp…).
- Sử dụng công nghệ kết nối không dây (Wifi, Internet Mobile…).
Các tài nguyên sau khi được truy xuất sẽ dựa trên loại tài nguyên và sử dụng các API tương
ứng để nhận và chuyển đổi thành dữ liệu tường minh mà người dùng có thể đọc và hiểu được
trên ứng dụng. Android cung cấp đầy đủ các phương thức thư viện cho phép lập trình viên có
thể làm việc được hầu hết các loại dữ liệu phổ biến. Ví dụ, có thể sử dụng WebView và các
phương thức tương ứng để có thể hiện thông tin của một trang Web ngay trên màn hình ứng
dụng.
1.2. Các vấn đề khi kết nối Internet
Một trong những vấn đề được đặt ra khá quan trọng là liệu có nên xây dựng một ứng dụng
hoàn chỉnh trên thiết bị di động (Native App), bởi vì chúng ta hoàn toàn có thể xây dựng một
trang web và cung cấp giao diện riêng cho thiết bị di động (Web App). Khi đó người dùng có
thể sử dụng trình duyệt trên thiết bị và truy xuất đường dẫn riêng đến trang web đó (ví dụ:
http://m.t3h.vn). Việc xây dựng Web App giúp lập trình viên có thể tiết kiệm được thời gian
xây dựng ứng dụng riêng cho từng hệ điều hành, tuy nhiên vẫn khó tránh khỏi những khuyết
điểm mà chỉ khi xây dựng ứng dụng chúng ta mới có thể giải quyết được.
- Vấn đề về băng thông: khi sử dụng trình duyệt để duyệt đến web ứng dụng, tất cả các
tài nguyên hầu như bắt buộc phải tải lại từ đầu, ví dụ: hình ảnh, giao diện, âm thanh…
điều này tạo ra một lượng băng thông lớn để truy xuất các dữ liệu tĩnh, thay vào đó
xây dựng ứng dụng có thể giúp chúng ta lưu trữ những dữ liệu này một cách dễ dàng.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |1


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Lưu Cache: các trình duyệt chỉ có thể lưu giữ một lượng thông tin nhỏ về trang web
mà chúng làm việc, trong khi đó ứng dụng hoàn toàn có thể lưu trữ bất kỳ dữ liệu nào
mà lập trình viên mong muốn từ dữ liệu truy xuất đến thao tác người dùng. Khi có sự
cố về kết nối, ứng dụng sẽ lưu trữ lại thông tin tại thời điểm mất kết nối và tự động xử
lý khi thiết bị có lại kết nối.
- Năng lượng: các kết nối Internet khi được thực hiện sử dụng một lượng lớn năng
lượng cho mỗi lần kết nối, tuy nhiên việc xây dựng ứng dụng sẽ cho phép chúng ta tổ
chức quản lý kết nối cũng như duy trì các kết nối khi cần thiết.
- Tính năng thiết bị: các ứng dụng nền web hầu như không thể nào truy xuất đến phần
cứng cũng như các đặc tính quan trọng trên một thiết bị di động. Ví dụ: định vị, máy
ảnh, cảm biến… đương nhiên, khi xây dựng ứng dụng chúng ta hoàn toàn có thể dễ
dàng truy xuất các đặc tính thiết bị thông qua các API mà bộ SDK cung cấp.
1.3. Các hình thức kết nối Internet
Các thiết bị di động ở thời điểm hiện tại hỗ trợ khá nhiều hình thức kết nối đến Internet, tuy
nhiên ta có thể quy chung về dạng sau:
- Mobile Internet: một dạng kết nối thông qua hình thức cung cấp dịch vụ băng thông
của nhà mạng, bao gồm một số chuẩn phổ biến sau: GPRS, EDGE, 3G, 4G, LTE…
- Wifi: kết nối không dây và truyền dữ liệu ra Internet thông các thiết bị mạng (router,
switch…), ngoài ra thiết bị di động Android có khả năng phát tín hiệu mạng cho các
thiết bị khác.
Việc xây dựng ứng dụng thực hiện kết nối đến Internet phụ thuộc vào khá nhiều hình thức
kết nối mà thiết bị người dùng đang sử dụng. Do đó, để tối ưu hóa kết nối và tăng trải nghiệm
người dùng cần thực hiện sử dụng hình thức kết nối một cách hợp lý. Ta có thể thấy các
mạng di động thường có băng thông thấp và chi phí cao để sử dụng, trong khi đó Wifi lại tùy
thuộc và băng thông của nguồn kết nối.
1.4. Lớp khai báo kết nối
Việc khai báo kết nối tùy thuộc vào chuẩn giao thức kết nối và địa chỉ URL của máy chủ cần
kết nối:
- URL: lớp giải quyết phân giải tên miền thành địa chỉ IP.
o Định dạng: http://username:password@host:8080/directory/file?query#ref:
o Phương thức kết nối
 openConnection
- URLConnection: lớp thực hiện kết nối đến URL được chỉ định cho việc đọc hoặc ghi
dữ liệu, hỗ trợ các giao thức:
o File: URIs
o FTP
o HTTP & HTTPS
o Jar

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |2


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- URLConnection:
o Các phương thức quan trọng:
 connect()
 getContent()
 getContentType()
 getInputStream()
 getOutputStream()
 setDoInput – getDoInput
 setDoOutput – getDoOutput
o Các lớp giao thức HTTP & HTTPS:
 HttpURLConnection
 HttpsURLConnection
 Các phương thức quan trọng:
. disconnect()
. getContentEncoding()
. getResponseCode()
. getResponseMessage()

1.4.1. Thực hiện kết nối Internet (HTTP)


- Bao gồm các bước sau:
o Thực hiện mở kết nối đến địa chỉ URL được chỉ định →
HttpURLConnection.
o Thực hiện khai báo các header, content-type, cookies, …
o Gọi phương thức setDoOutput(true) thực hiện xây dựng phần dữ liệu cần gửi
lên máy chủ, dữ liệu được thiết lập được trả thông qua phương thức
getOutputStream(). (Optional).
o Thực hiện truy xuất dữ liệu thông qua phương thức getInputStream(), để lấy
các thông tin về nội dung được trả, độ dài, thời gian…
o Gọi phương thức disconnect() để đóng các kết nối khi kết thúc phiên làm việc
và giải phóng tài nguyên.
- Một số lưu ý khi thực hiện:
o Cần thực hiện xin cấp quyền truy cập Internet cho ứng dụng trong tập tin
AndroidManifest.
<uses-permission android:name="android.permission.INTERNET"/>

o Trong một vài trường hợp cần xin cấp quyền kiểm soát trạng thái Internet
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"/>

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |3


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Không được thực hiện kết nối Internet trực tiếp trên tiến trình chính của ứng
dụng. Sử dụng AsyncTask hoặc Thread để thay thế.
o Ví dụ:
URL url = new URL(“http://t3h.vn”);
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection =
(HttpURLConnection) urlConnection;

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream =
httpURLConnection.getInputStream();
// Xử lý đọc dữ liệu từ InputStream
}

1.4.2. Thực hiện kết nối Internet (HTTPS)


- Bao gồm các bước sau:
o Khai báo KeyStore dùng để chứng thực.
o Chứng thực KeyStore thông qua X509TrustManager hoặc
SSLSocketFactory.
o Thực hiện mở kết nối đến địa chỉ URL được chỉ định →
HttpsURLConnection.
o Thực hiện gắn SSLContext cho việc chứng thực.
o Gọi phương thức setDoOutput(true) thực hiện xây dựng phần dữ liệu cần gửi
lên máy chủ, dữ liệu được thiết lập được trả thông qua phương thức
getOutputStream().
o Thực hiện truy xuất dữ liệu thông qua phương thức getInputStream(), để lấy
các thông tin về nội dung được trả, độ dài, thời gian…
o Gọi phương thức disconnect() để đóng các kết nối khi kết thúc phiên làm việc
và giải phóng tài nguyên.
- Ví dụ:
KeyStore keyStore = ...;
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(keyStore);

SSLContext context = SSLContext.getInstance("TLS");


context.init(null, tmf.getTrustManagers(), null);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |4


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

URL url = new URL("https://www.example.com/");


HttpsURLConnection urlConnection = (HttpsURLConnection)
url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();

2. SỬ DỤNG DỊCH VỤ DOWNLOAD MANAGER


2.1. Giới thiệu dịch vụ Download Manager
- Download Manager là trình quản lý các tác vụ tải trên thiết bị Android được Google
tích hợp từ phiên bản Android 2.3 (API 9). Download Manager được thiết kế hoạt
động như một dịch vụ chạy ngầm, cho phép quản lý và giám sát sự thay đổi của các
kết nối HTTP cũng như các hoạt động khởi động lại của thiết bị để đảm bảo các nội
dung được hoàn thành một cách triệt để.
- Download Manager được sử dụng trong các trường hợp cần thực hiện tải một nội
dung trong một thời gian dài ở chế độ ngầm giữa các phiên tương tác của người dùng
và việc hoàn thành nội dung tải được đặt lên hàng đầu.
- Tất cả các tập tin được tải thông qua Download Manager được quản lý bởi ứng dụng
Download trên thiết bị.

Hình 1.1. Ví dụ minh họa dịch vụ Download Manager


2.2. Khai báo và sử dụng Download Manager
Việc truy xuất Download Manager được thông qua phương thức getSystemService().

DownloadManager manager=(DownloadManager)getSystemService(DOWNLOAD_SERVICE);

Để khởi tạo yêu cầu tải một nội dung, tiến hành tạo đối tượng Request với tham số truyền
vào là một Uri, một dạng địa chỉ kết nối đến máy chủ chứa nội dung cần tải. Đối tượng này
sau đó sẽ được xếp vào hàng đợi để bắt đầu tải thông qua phương thức enqueue().

DownloadManager manager = (DownloadManager)


getSystemService(DOWNLOAD_SERVICE);
Uri uri = Uri.parse

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |5


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

("http://developer.android.com/downloads/design/roboto-1.2.zip");

Request request = new Request(uri);

long id_reference = manager.enqueue(request);

- Khi phương thức enqueue() được gọi, việc tải nội dung sẽ được bắt đầu thực hiện khi
kết nối mạng khả dụng và hàng đợi của Download Manager đang rỗng.
- Phương thức enqueue() cũng trả về một biến tham chiếu id_reference, được sử dụng
để thực hiện các thao tác liên quan đến yêu cầu tải đang được thực hiện trong hàng
đợi. Ví dụ, ta có thể thực hiện truy vấn xem trạng thái của yêu cầu tải đã hoàn thành
chưa hoặc đơn giản có thể hủy yêu cầu tải dựa trên tham chiếu này.
- Khi thực hiện tải một nội dung, chúng ta có thể cân nhắc về dung lượng của nội dung
và cho phép sử dụng các kết nối phù hợp nội dung đó thông qua phương thức
setAllowedNetworkTypes(), lựa chọn tải bằng Wi-fi hay mạng di động.
- Từ phiên bản Android 3.0, phương thức getRecommendedMaxBytesOverMobile()
được bổ sung cho phép ứng dụng có thể nhận biết dung lượng lớn nhất có thể mà thiết
bị có thể thực hiện tải thông qua kết nối của mạng di động.
- Để nhận biết việc hoàn thành tải nội dung, ta tiến hành xây dựng một
BroadcastReceiver để bắt lại hành động ACTION_DOWNLOAD_COMPLETE được
truyền thông bởi dịch vụ chạy ngầm DownloadMananager. Trong dữ liệu bắt được,
cũng bao gồm tham số EXTRA_DOWNLOAD_ID chứa biến tham chiếu đến nội
dung tải. Có thể xem đoạn code sau để hiểu thêm.

IntentFilter filter = new IntentFilter


(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
long id_reference =
intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
Log.d("HTSI", "File's id: " + id_reference);
}};
registerReceiver(receiver, filter);

2.3. Tùy chỉnh thông báo cho Download Manager


Mặc định khi thực hiện tải nội dung thông qua dịch vụ chạy ngầm Download Manager, trên
thanh trạng thái (Status Bar) của thiết bị sẽ xuất hiện một hộp thoại thông báo hoạt động hiện
tại, hiển thị các thông tin như: tên tập tin được tải, ngày giờ tải, dung lượng đã tải, …

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |6


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 1.2
Tuy nhiên chúng ta hoàn toàn có thể tùy chỉnh thông tin hiển thị trên hộp thoại thông báo này
tường minh hơn thông qua các phương thức hỗ trợ trong đối tượng Request.
Ví dụ:

request.setTitle("Android Design Icons");


request.setDescription("Zip File");

Kết quả:

Hình 1.3
Hộp thoại thông báo mặc định sẽ xuất hiện khi bắt đầu tải và tự đóng khi hoàn tất quá trình
tải, để thiết lập lại trạng thái này chúng ta có thể sử dụng phương thức
setNotificationVisibility() với các biến cờ tương ứng sau:
- Request.VISIBILITY_VISIBLE: tham số mặc định, chỉ hiển thị trong quá trình tải.
- Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED: hiển thị trong quá trình tải
và cả khi hoàn tất.
- Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION: chỉ hiển thị khi
hoàn tất quá trình tải.
- Request.VISIBILITY_HIDDEN: không hiển thị hộp thoại thông báo.
Đối với biến cờ VISIBILITY_HIDDEN cần cấp quyền trong AndroidManifest.xml

<uses-permission
android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>

2.4. Chỉ định nơi lưu trữ


Mặc định các nội dung tải được hệ thống lưu trữ trong Content Providers của ứng dụng
Download:

data/user/0/com.android.providers.downloads/cache/<Tên tập tin>

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |7


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Các tập tin trong thư mục này sẽ không thể truy xuất bằng đường dẫn của tập tin, chỉ
có thể truy xuất thông qua Uri của tập tin đó.
- Tuy nhiên ta có thể thiết lập lại vị trí lưu trữ nội dung tải thông qua các phương thức
sau:
o setDestinationUri(Uri uri): chỉ định vị trí lưu trữ bất kỳ thông qua Uri.
 Ví dụ:
File f = new File(Environment.getExternalStorageDirectory(),
uri.getLastPathSegment());
request.setDestinationUri(Uri.fromFile(f));

 Đường dẫn lưu trữ:


/storage/emulated/0/<file-name>

o setDestinationInExternalFilesDir(Context context, String dirType, String


subPath): chỉ định vị trí lưu trữ trong thư mục ứng dụng trên bộ nhớ ngoài.
 Ví dụ:
request.setDestinationInExternalFilesDir(this, "My Files",
uri.getLastPathSegment());

 Đường dẫn lưu trữ:


/storage/emulated/0/Android/data/<pakage-name>/files/My Files/<file-name>

o setDestinationInExternalPublicDir(String dirType, String subPath): chỉ định vị


trí lưu trữ trong thư mục ứng dụng trên bộ nhớ ngoài.
 Ví dụ:
request.setDestinationInExternalPublicDir
(Environment.DIRECTORY_DOWNLOADS, uri.getLastPathSegment());

 Đường dẫn lưu trữ:


/storage/emulated/0/Download/<file-name>

- Các hành động truy xuất đến bộ nhớ ngoài cần cấp quyền trong tập tin
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |8


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Mặc định, đối với các trường hợp tải tập tin đa truyền thông (ví dụ: hình ảnh, âm nhạc, video,
...) các ứng dụng đa phương tiện như Galery, Music hay Video không thể tự động quét được
các nội dung này. Tuy nhiên, chúng ta có thể cho phép tập tin được quét lại khi hoàn tất việc
tải thông qua phương thức allowScanningByMediaScanner() trong đối tượng Request.
2.5. Truy vấn nội dung tải trong DownloadManager
- Để ứng dụng có thể quản lý các thông tin của nội dung tải như: trạng thái, tiến độ,
dung lượng, ... ta có thể thực hiện truy vấn Content Provider của Download Manager
thông qua đối tượng Query, kết quả trả về là một đối tượng Cursor. Có thể xem chi
tiết ở đoạn mã sau:
Query query = new Query();
query.setFilterById(id_reference);
Cursor cursor = manager.query(query);
if (cursor.moveToFirst()) {
String path = cursor.
getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
if (path != null)
imageView.setImageURI(Uri.parse(path));
}

Trong đoạn mã trên, để thực hiện truy vấn đúng nội dung đã tải ta gọi phương thức
setFilterById() với tham số là biến tham chiếu id_reference ta truy xuất được từ phương thức
enqueue() (Xem lại phần III.1).
Việc truy vấn được thực hiện thông qua phương thức query() trong đối tượng
DownloadManager, tham số truyền vào là đối tượng Query đã thiết lập bộ lọc. Kết quả trả về
thông qua đối tượng Cursor, để truy xuất dữ liệu trong Cursor, tiến hành truyền vào tên cột
của những trường dữ liệu tương ứng cần truy xuất. Tên cột của những trường dữ liệu được
định dạng COLUMN_*.
Trong ví dụ trênm, chúng ta truy xuất trường dữ liệu COLUMN_LOCAL_FILENAME trong
Cursor để lấy đường dẫn lưu trữ nội dung tấm ảnh được tải, sau đó thiết lập cho điều khiển
ImageView.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 |9


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 2
KẾT NỐI CÁC DỊCH VỤ WEB
THAO TÁC VỚI DỮ LIỆU XML VÀ JSON

1. GIỚI THIỆU VỀ CÁC DỊCH VỤ WEB


1.1. Dịch vụ Web là gì?
Dịch vụ Web (Web Service) được coi là một công nghệ mang đến cuộc cách mạng trong
cách thức hoạt động của các dịch vụ B2B (Business to Business) và B2C (Business to
Customer). Giá trị cơ bản của dịch vụ Web dựa trên việc cung cấp các phương thức theo
chuẩn trong việc truy nhập đối với hệ thống đóng gói và hệ thống kế thừa. Các phần mềm
được viết bởi những ngôn ngữ lập trình khác nhau và chạy trên những nền tảng khác nhau có
thể sử dụng dịch vụ Web để chuyển đổi dữ liệu thông qua mạng Internet theo cách giao tiếp
tương tự bên trong một máy tính. Tuy nhiên, công nghệ xây dựng dịch vụ Web không nhất
thiết phải là các công nghệ mới, nó có thể kết hợp với các công nghệ đã có như XML, SOAP,
WSDL, UDDI… Với sự phát triển và lớn mạnh của Internet, dịch vụ Web thật sự là một
công nghệ đáng được quan tâm để giảm chi phí và độ phức tạp trong tích hợp và phát triển hệ
thống.
Theo định nghĩa của W3C (World Wide Web Consortium), dịch vụ Web là một hệ thống
phần mềm được thiết kế để hỗ trợ khả năng tương tác giữa các ứng dụng trên các máy tính
khác nhau thông qua mạng Internet, giao diện chung và sự gắn kết của nó được mô tả bằng
XML. Dịch vụ Web là tài nguyên phần mềm có thể xác định bằng địa chỉ URL, thực hiện các
chức năng và đưa ra các thông tin người dùng yêu cầu. Một dịch vụ Web được tạo nên bằng
cách lấy các chức năng và đóng gói chúng sao cho các ứng dụng khác dễ dàng nhìn thấy và
có thể truy cập đến những dịch vụ mà nó thực hiện, đồng thời có thể yêu cầu thông tin từ
dịch vụ Web khác. Nó bao gồm các mô đun độc lập cho hoạt động của khách hàng và doanh
nghiệp và bản thân nó được thực thi trên server.
Trước hết, có thể nói rằng ứng dụng cơ bản của Dịch vụ Web là tích hợp các hệ thống và là
một trong những hoạt động chính khi phát triển hệ thống. Trong hệ thống này, các ứng dụng
cần được tích hợp với cơ sở dữ liệu (CSDL) và các ứng dụng khác, người sử dụng sẽ giao
tiếp với CSDL để tiến hành phân tích và lấy dữ liệu. Trong thời gian gần đây, việc phát triển
mạnh mẽ của thương mại điện tử và B2B cũng đòi hỏi các hệ thống phải có khả năng tích
hợp với CSDL của các đối tác kinh doanh.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 10


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Các Web Services cho phép các tổ chức thực hiện truyền thông dữ liệu mà không cần phải có
kiến thức về hệ thống IT phía sau tường lửa. Một số Web Services hiện nay có sẵn miễn phí
và càng ngày càng hướng dần vào các doanh nghiệp.
Một ví dụ về Web Service sẵn có là dịch vụ được cung cấp bởi PayPal cho phép những người
có tài khoản có thể thanh toán hoặc trả một phần hoặc thực hiện các giao dịch tìm kiếm, và
lấy lại các thông tin của từng giao dịch cụ thể.
1.2. Các chuẩn dịch vụ WEB
Việc tìm hiểu về các chuẩn dịch vụ WEB giúp chúng ta có thể đưa ra các lựa chọn phù hợp
với hệ thống triển khai, dữ liệu và các thiết bị truy xuất dữ liệu đầu cuối đầu cuối. Có thể liệt
kê một số chuẩn chính sau:
- UDDI (Universal Description, Discovery and Integrated).
- WSDL (Web Services Description Language).
- WSIL (Web Services Inspection Language).
- SOAP (Simple Object Access Protocol).

2. CÁC LOẠI WEBSERVICE


2.1. Giao thức HTTP
- HTTP (Hypertext Transfer Protocol) là giao thức mạng cho phép các hệ thống thông
tin phân phối và cộng tác với nhau. HTTP là nên tảng giao tiếp dữ liệu cho WWW.
- HTTP hoạt động trên cơ chế giao thức request – response trong mô hình điện toán
client – server.

Hình 2.1. Minh họa cơ chế hoạt động của giao thức HTTP

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 11


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Các định nghĩa đi kèm:


o URI (Uniform Resource Identifier) là một chuỗi để xác định một tài nguyên
trên internet.
o URL (Uniform Resource Locator) là một URI cho biết sự tồn tại của một tài
nguyên và cách thức để nhận tài nguyên đó.
o URN (Uniform Resource Name) là một URI nhằm xác định tài nguyên bằng
tên và độc lập với vị trí lưu trữ.
- HTTP Status code :
o 2xx Success ( Trạng thái thành công)
Ví dụ :
200 – OK.
201 – Created.
o 3xx Redirection ( Báo chuyển hướng)
Ví dụ :
304 – Not Modified
o 4xx Client Error ( Báo lỗi client)
Ví dụ :
403 Forbidden
404 – Not Found
o 5xx Server Error ( Báo lỗi server)
Ví dụ :
503 – Service Unavailable
504 – Gateway Timeout

- Ví dụ về HTTP – Request
GET http://www.fit.hcmus.edu.vn/vn/ HTTP/1.1
Accept: application/x-ms-application, image/jpeg,
application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap,
application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-
powerpoint, application/msword,
Accept-Language: vi-VN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;
WOW64; Trident/4.0; GTB6.5; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT
5.1; SV1) ; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR
3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; OfficeLiveConnector.1.5;
OfficeLivePatch.1.3; InfoPath.3; AskTbGGSV5/5.8.0.12217)
chromeframe/6.0.472.63
Accept-Encoding: gzip, deflate Connection: Keep-Alive
Host: www.fit.hcmus.edu.vn
Cookie:

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 12


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

.ASPXANONYMOUS=MG6LCiuSywEkAAAANTA2ZWNiYTAtYThiNy00MDA1LTkyN
jUtYTllYzAxNTA3MTU10

- Ví dụ về HTTP – Response
HTTP/1.0 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.0
X-AspNet-Version: 2.0.50727
Set-Cookie: DotNetNukeAnonymous=7db3c001-c407-4adb-a60f-053b5dc76dc2;
expires=Thu, 30-Sep-2010 03:12:33 GMT; path=/; HttpOnly
Set-Cookie: language=vi-VN; path=/; HttpOnly X-Powered-By: ASP.NET
Date: Thu, 30 Sep 2010 02:52:33 GMT Content-Length: 24404
X-Cache: MISS from vweb.hcmuns.edu.vn
Via: 1.0 vweb.hcmuns.edu.vn:80 (squid/2.6.STABLE16) Connection: keep-alive
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> ...
// Nội dung trang web

- Các phương thức phương thức chính của HTTP

Hình 2.1. Các phương thức chính của HTTP


o Phương thức GET:
 Dùng để tải một biểu diễn của tài nguyên.
 Được sử dụng nhiều nhất.
 Biểu diễn của tài nguyên có thể bao gồm HTML, JPG, XML, ...
o Phương thức HEAD:
 Tương tự như GET thay vì tải toàn bộ thể hiện thì chỉ tải HTTP Header.
 Dùng để kiểm tra thay đổi khi muốn tải lại tài nguyên có kích thước lớn.
o Phương thức DELETE:
 Dùng để xóa tài nguyên.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 13


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Phương thức PUT :


 Dùng để lưu một biểu diễn vào một tài nguyên.
 Đăng tải một tập tin vào một vị trí xác định trên website.
 Nếu PUT thực hiện hai lần thì lần sau sẽ đè lên lần trước.
o Phương thức POST :
 Tạo một tài nguyên tương tự như PUT, nhưng server sẽ quyết định cách
lưu trữ thay vì client như PUT.
2.2. SOAP
- SOAP - Simple Object Accesss Protocol: là một giao thức giao tiếp có cấu trúc như
XML và mã hóa thành định dạng chung cho các ứng dụng trao đổi với nhau.
- SOAP là một đặc tả việc sử dụng các tài liệu XML theo dạng các thông điệp. Bản thân
SOAP không định ra các ngữ nghĩa ứng dụng hoặc cách cài đặt chi tiết. SOAP cung
cấp một cơ chế đơn giản và gọn nhẹ cho việc trao đổi thông tin có cấu trúc và định
dạng giữa các thành phần trong một môi trường phân tán sử dụng XML. SOAP được
thiết kế dựa trên những chuẩn nhằm giảm chi phí tích hợp các hệ thống phân tán xây
dựng trên nhiều nền tảng khác nhau ở mức càng thấp càng tốt. Đặc tả về SOAP định
nghĩa một mô hình trao đổi dữ liệu dựa trên 3 khái niệm cơ bản: Các thông điệp là các
tài liệu XML, chúng được truyền đi từ bên gửi đến bên nhận, bên nhận có thể chuyển
tiếp dữ liệu đến nơi khác.
- Khái niệm cơ bản nhất của mô hình SOAP là việc sử dụng các tài liệu XML như
những thông điệp trao đổi. Điều này có nhiều ưu điểm hơn các giao thức truyền dữ
liệu khác. Các thông điệp XML có thể được tổng hợp và đọc với một bộ soạn thảo text
đơn giản, ta có thể làm việc với XML trên hầu hết mọi nền tảng.
- Đặc trưng của SOAP:
o SOAP được thiết kế đơn giản và dễ mở rộng.
o Tất cả các message SOAP đều được mã hóa sử dụng XML.
o SOAP sử dùng giao thức truyền dữ liệu riêng.
o Không có garbage collection phân tán, và cũng không có cơ chế tham chiếu. Vì
thế SOAP client không giữ bất kỳ một tham chiếu đầy đủ nào về các đối tượng
ở xa.
o SOAP không bị ràng buộc bởi bất kỳ ngôn ngữ lập trình nào hoặc công nghệ
nào.
Vì những đặc trưng này, nó không quan tâm đến công nghệ gì được sử dụng để
thực hiện miễn là người dùng sử dụng các message theo định dạng XML. Tương
tự, service có thể được thực hiện trong bất kỳ ngôn ngữ nào, miễn là nó có thể xử
lý được những message theo định dạng XML.
- Khi trao đổi các thông điệp SOAP, có hai thành phần liên quan: Bên gửi và bên nhận.
Thông điệp sẽ được chuyển từ bên gửi sang bên nhận. Đây là ý niệm đơn giản nhất
trong trao đổi thông điệp SOAP. Trong nhiều trường hợp, kiểu trao đổi này không

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 14


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

cung cấp đủ chức năng. Nhưng đây là mô hình cơ bản, dựa trên đó sẽ phát triển các
mô hình trao đổi phức tạp hơn.

Sender Receiver

Transport
Hình 2.2. Hệ thống Soap đơn giản.
- Một cấu trúc SOAP được định nghĩa gồm các phần: <Envelope>, <Header> và
<Body>.

Hình 2.3. Cấu trúc thông điệp SOAP.


2.3. REST
- REST (Representational State Transfer) đã được chọn sử dụng rộng rãi thay cho Web
service dựa trên SOAP và WSDL. Bằng chứng quan trọng của sự thay đổi này chính
là việc các công ty dẫn đầu trong lĩnh vực cung cấp dịch vụ mạng 2.0 như Yahoo,
Google và Facebook đã phản đối các giao thức dựa trên SOAP hoặc WSDL và ủng hộ
phương thức hướng đến tài nguyên và dễ sử dụng đối với các dịch vụ của họ. Trong
bài viết này, chúng ta sẽ tìm hiểu các nguyên lý cơ bản của REST.
- REST (Representational State Transfer) là một kiểu kiến trúc phần mềm cho các hệ
thống phân tán siêu truyền thông như là WWW.
- Đặc trưng của REST
o Là dạng client – server.
o Phân tách giao diện của client ra khỏi dữ liệu.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 15


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Cho phép mỗi thành phần phát triển độc lập.


o Hỗ trợ đa nền tảng.
o Mỗi yêu cầu từ client phải có đủ thông tin cần thiết để server có thể hiểu được
mà không cần phải lưu trữ thêm thông tin nào trước đó.
o Tất cả tài nguyên được truy cập thông qua một interface thống nhất (HTTP
GET, PUT, POST, DELETE, ...).
2.4. RESTful Service
- Là một web service đơn giản sử dụng HTTP và tính chất của REST.
- Là một tập tài nguyên các thành phần được định nghĩa:
o URI gốc cho web service.
o MIME type hỗ trợ bởi web service.
o Tập hành động hỗ trợ bởi web service sử dụng HTTP method (GET, POST,
PUT, DELETE).

3. XÂY DỰNG ỨNG DỤNG KẾT NỐI DỊCH VỤ WEB RESTFUL


Ứng dụng trực tuyến trên thiết bị di động được xây dựng nhằm mục đích hiển thị dữ liệu đầu
cuối được xử lý từ các máy chủ cũng như gửi các yêu cầu về truy xuất dữ liệu. Ví dụ: ứng
dụng Goole Play Store được Google cài đặt trên thiết bị người dùng, hiển thị các ứng dụng
được phát triển bởi các lập trình viên, cho phép người dùng có thể tải và cài đặt các ứng dụng
đó ngay trên thiết bị của họ.
Trong phần hướng dẫn này ta sẽ truy xuất đến OnlineShop Service, một dịch vụ chuyên cung
cấp các thông tin về các mặt hàng sản phẩm như giá cả, chất liệu, tính năng…
3.1. Khai báo và kiểm soát các yêu cầu kết nối
- Việc đầu tiên cần thực hiện là xin quyền truy cập Internet cho ứng dụng, có thể bổ
sung các quyền có liên quan như kiểm soát kết nối Internet.
<uses-permission android:name= “android.permission.INTERNET”/>
<uses-permission android:name= “android.permission.ACCESS_NETWORK_STATE”/>

- Trong việc truy xuất tài nguyên Internet trên thiết bị di động cần kiểm soát được các
vấn đề về kết nối. Ví dụ: ta cần kiểm soát việc cho phép người dùng tương tác với ứng
dụng ở chế độ ngoại tuyến và thực hiện cập nhật dữ liệu khi có kết nối. Có thể xem ví
dụ về việc sử dụng Broadcast Receiver để kiểm soát vấn đề này:
BroadcastReceiver mNetworkStateIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("HTSI", "CONNECTION CHANGED");
ConnectivityManager cm = ((ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE));
if (cm.getActiveNetworkInfo() != null) {

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 16


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

// Thực hiện xử lý khi không có kết nối.


} else {// Và khi không có kết nối.}
}
};

3.2. Thực hiện kết nối


- Việc kết nối được thông qua 2 cách: sử dụng kết nối URL thông thường hoặc sử dụng
kết nối thông qua thư viện của gói org.apcahe.http.
- Sử dụng kết nối URL thông thường:
HttpURLConnection connection = null;
Url url = new URL(“http://221.132.37.130:6969/OnlineShopWebService”);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
connection.setRequestMethod("GET");

o Ở phương thức setRequestMethod ta có thể tự do thêm vào tên của cách thức
gọi phương thức từ dịch vụ RESTful như GET, POST, PUT, … Tuỳ thuộc vào
loại phương thức mà dịch vụ đó cung cấp. Ở ví dụ trên, do thực hiện gọi theo
loại phương thức GET, cũng như không có tham số truyền vào nên không khác
mấy so với cách thức mà chúng ta thực hiện ở phần đầu chương.
o Tuy nhiên hãy khảo sát cách thức để đăng nhập vào dịch vụ này. Ở đây, cần
thực hiện gửi dữ liệu người dùng cho dịch vụ theo dạng JSON và dạng sử dụng
POST để bảo mật dữ liệu.
HttpURLConnection connection = null;
Url url = new URL(“http://221.132.37.130:6969/OnlineShopWebService”);
Conn-ection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(true);
// Gửi dữ liệu thông qua OutputStream
OutputStream outputStream = new
BufferedOutputStream(connection.getOutputStream());
outputStream.write(incomingParams.getBytes());
outputStream.flush();
outputStream.close();

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 17


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Dữ liệu incomingParams được thực hiện chia thành từng byte nhỏ bằng
phương thức getBytes() trước khi được đưa vào OutputStream của kết nối. Dữ
liệu được định dạng là JSON khi dịch vụ nhận được thông qua phương thức
setRequestProperty().
- Sử dụng các lớp trong gói org.apache.http:
Đối với cách sử dụng các lớp HTTP trong Apache giúp chúng ta tường minh hơn
việc gọi đến Service. Ví dụ sử dụng hai lớp HttpGet và HttpPost:
o HttpGet: sau khi thực hiện có thể thực hiện truy xuất dữ liệu dạng InputStream
thông qua phương thức getEntity đối tượng HttpResponse.

public static InputStream getInputStreamFromUrl(String url) {


InputStream content = null;
try {
HttpGet httpGet = new HttpGet(url));
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(httpGet);
content = response.getEntity().getContent();
} catch (Exception e) {
Log.d("[GET REQUEST]", "Network exception" + e);
}
return content;
}

o HttpPost: đối với POST cần xác định dạng dữ liệu cần thực hiện gửi lên dịch
vụ, ví dụ sau đây mô tả cách thức gửi dữ liệu dạng JSON, được đóng gói vào
đối tượng NameValuePair. Dữ liệu được trả về vẫn được truy xuất thông qua
đối tượng HttpResponse.

HttpClient httpClient = new DefaultHttpClient();


HttpPost httpPost = new HttpPost(URL_CONNECT);
JSONObject jsonObject = ModuleCore.moduleCoreToJson(ModuleCore.LOGIN, params);
StringBuilder builder = new StringBuilder();
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("jsonParam", jsonObject.toString()));
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
HttpResponse httpResponse = httpClient.execute(httpPost);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 18


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

3.3. Truy xuất dữ liệu trả về


- Việc truy xuất dữ liệu không phụ thuộc vào cách thức gọi dịch vụ cho lắm, bởi dữ liệu
luôn là InputStream, chúng ta chỉ cần thực đọc dòng dữ liệu này và chuyển đội thành
dạng dữ liệu tương ứng cần tương tác. Hãy xem ví dụ về cách thức đọc dữ liệu
InputStream thành String:
HttpEntity httpEntity = httpResponse.getEntity();
InputStream inputStream = httpEntity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
inputStream.close();

4. ĐỌC GHI DỮ LIỆU XML


4.1. Định dạng XML
- XML (viết tắt từ tiếng Anh eXtensible Markup Language, "Ngôn ngữ Đánh dấu Mở
rộng") là ngôn ngữ đánh dấu với mục đích chung do W3C đề nghị, để tạo ra các ngôn
ngữ đánh dấu khác. Đây là một tập con đơn giản của SGML, có khả năng mô tả nhiều
loại dữ liệu khác nhau. Mục đích chính của XML là đơn giản hóa việc chia sẻ dữ liệu
giữa các hệ thống khác nhau, đặc biệt là các hệ thống được kết nối với Internet. Các
ngôn ngữ dựa trên XML (thí dụ: RDF, RSS,
MathML, XHTML, SVG, GML và cXML) được định nghĩa theo cách thông thường,
cho phép các chương trình sửa đổi và kiểm tra hợp lệ bằng các ngôn ngữ này mà
không cần có hiểu biết trước về hình thức của chúng.
- Cú pháp sơ lược:
<tên thẻ thuộc tính= “Giátrị”>Nội dung thẻ</tên thẻ>

- Ví dụ:
<data>
<weather>
<date>2014-06-20</date>
<tempMaxC>13</tempMaxC>
<tempMaxF>56</tempMaxF>
<tempMinC>5</tempMinC>
<tempMinF>42</tempMinF>
<windspeedMiles>13</windspeedMiles>
<windspeedKmph>20</windspeedKmph>

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 19


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

<winddirection>WNW</winddirection>
<weatherCode>113</weatherCode>
<precipMM>0.0</precipMM>
</weather>
</data>

4.2. Đọc ghi dữ liệu XML


- Để thực hiện đọc dữ liệu từ XML trong Android, ta có thể sử dụng DOM (Document
Object Model) Parser hoặc XML Pull Parser.
4.2.1. Ghi dữ liệu XML
- DOM Parser: giao diện lập trình ứng dụng (API) có dạng một cây cấu trúc dữ liệu,
các đối tượng cần khởi tạo khi sử dụng:
o Element: đại diện cho một thẻ trong XML.
o Document: tập tin tài liệu được khởi tạo từ dữ liệu XML thông qua
DocumentBuilder.
o DocumentBuilder: đối tượng hỗ trợ chuyển đổi dữ liệu XML thành cấu trúc
tập tin XML cho việc đọc ghi dữ liệu.
o DocumentBuilderFactory: khởi tạo đối tượng DocumentBuilder.
o Transformer: đối tượng cho phép thực hiện chuyển đổi dữ liệu sang nhiều
dạng XML khác nhau.
o TransformerFactory: khởi tạo đối tượng Transformer.
o DOMSource.
- Ví dụ: thực hiện tổ chức ghi dữ liệu XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.newDocument();

// Khởi tạo thẻ gốc <data>


Element rootElement = document.createElement("data");
document.appendChild(rootElement);

// Khởi tạo thẻ <weather>


Element weather = document.createElement("weather");
// Thiết lập <weather> là thẻ con trong thẻ <data>
rootElement.appendChild(weather);

// Khởi tạo thẻ <date>


Element date = document.createElement("date");
// Khởi tạo giá trị thẻ <date>
date.appendChild(document.createTextNode("20-06-2014"));
// Thiết lập <date> là thẻ con trong thẻ <weather>
weather.appendChild(date);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 20


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Element tempMaxC = document.createElement("tempMaxC");


tempMaxC.appendChild(document.createTextNode("13"));
weather.appendChild(tempMaxC);

Element tempMaxF = document.createElement("tempMaxF");


tempMaxF.appendChild(document.createTextNode("56"));
weather.appendChild(tempMaxF);

// Định dạng các thuộc tính dữ liệu XML


TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
Properties outFormat = new Properties();
outFormat.setProperty(OutputKeys.INDENT, "yes");
outFormat.setProperty(OutputKeys.METHOD, "xml");
outFormat.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
outFormat.setProperty(OutputKeys.VERSION, "1.0");
outFormat.setProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperties(outFormat);

// Chuyển đổi nguồn dữ liệu theo chuẩn DOM


DOMSource domSource = new DOMSource(document.getDocumentElement());
OutputStream output = new ByteArrayOutputStream();
StreamResult result = new StreamResult(output);
transformer.transform(domSource, result);

String xmlString = output.toString();


textXML.setText(xmlString);

- Kết quả của dữ liệu XML:

Hình 2.4.

- XML Pull Parser: cho phép trình bày các thành phần trong tập tin theo dạng chuỗi
các thẻ (tag), việc ghi dữ liệu XML được biểu diễn thông qua hai đối tượng
XmlSerializer và StringWritter.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 21


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

// Khởi tạo đối tượng XmlSerializer


XmlSerializer xmlSerializer = Xml.newSerializer();
// Khởi tạo đối tượng StringWritter
StringWriter stringWriter = new StringWriter();

xmlSerializer.setOutput(stringWriter);
xmlSerializer.startDocument("UTF-8", true);
xmlSerializer.startTag("", "data");
xmlSerializer.attribute("", "source", "weather.t3h.vn");
xmlSerializer.startTag("", "weather");

xmlSerializer.startTag("", "date");
xmlSerializer.text("20-06-2014");
xmlSerializer.endTag("", "date");

xmlSerializer.startTag("", "tempMaxC");
xmlSerializer.text("13");
xmlSerializer.endTag("", "tempMaxC");

xmlSerializer.startTag("", "tempMaxF");
xmlSerializer.text("56");
xmlSerializer.endTag("", "tempMaxF");

xmlSerializer.endTag("", "weather");
xmlSerializer.endTag("", "data");
xmlSerializer.endDocument();

textXML.setText(stringWriter.toString());

- Kết quả của dữ liệu XML:

Hình 2.5
4.2.2. Đọc dữ liệu XML
- DOM Parser: giao diện lập trình ứng dụng (API) có dạng một cây cấu trúc dữ liệu,
các đối tượng cần khởi tạo khi sử dụng:
o Element: đại diện cho một thẻ trong XML.
o NodeList: đại diện cho một thẻ có chứa nhiều thẻ con.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 22


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Document: tập tin tài liệu được khởi tạo từ dữ liệu XML thông qua
DocumentBuilder.
o DocumentBuilder: đối tượng hỗ trợ chuyển đổi dữ liệu XML thành cấu trúc
tập tin XML cho việc đọc ghi dữ liệu.
o DocumentBuilderFactory: khởi tạo đối tượng DocumentBuilder.
sample_xmlxml:
<data>
<weather>
<date>2014-06-20</date>
<tempMaxC>13</tempMaxC>
<tempMaxF>56</tempMaxF>
<tempMinC>5</tempMinC>
<tempMinF>42</tempMinF>
<windspeedMiles>13</windspeedMiles>
<windspeedKmph>20</windspeedKmph>
<winddirection>WNW</winddirection>
<weatherCode>113</weatherCode>
<precipMM>0.0</precipMM>
</weather>
</data>

- Ví dụ xử lý XML với DOM: truy xuất dữ liệu thẻ <weather> trong đoạn XML trên.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
InputStream inputStream = getAssets().open("sample_xml.xml");
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(inputStream);
Element element = document.getDocumentElement();
NodeList nodeList = element.getElementsByTagName("weather");
if (nodeList == null)
return;
for (int i=0; i<nodeList.getLength(); i++) {
Element weather = (Element) nodeList.item(i);
for (int x=0; x < weather.getChildNodes().getLength(); x++) {

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 23


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Node weatherNode = weather.getChildNodes().item(x);


Log.d("HTSI",weatherNode.getNodeName()+"="+weatherNode.getTextContent());
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();}

- XML Pull Parser: cho phép trình bày các thành phần trong tập tin theo dạng chuỗi
các thẻ (tag) và các đánh dấu (event), để làm việc với XML Pull Parser cần khảo sát
các thuộc tính và các đối tượng sau:
o XmlPullParserFactory: khởi tạo đối tượng XmlPullParser từ tập tin tài liệu
XML.
o XmlPullParer: đối tượng kiểm soát việc duyệt và truy xuất dữ liệu.
o START_DOCUMENT: điểm đánh dấu bắt đầu của tập tin XML.
o END_DOCUMENT: điểm đánh dấu kết thúc của tập tin XML.
o START_TAG: điểm đánh dấu bắt đầu cặp thẻ XML.
o END_TAG: điểm đánh dấu kết thúc cặp thẻ XML.
- Ví dụ xử lý XML với DOM: truy xuất dữ liệu các thẻ con trong thẻ <weather> đoạn
XML trên.
InputStream inputStream = getAssets().open("sample_xml.xml");
XmlPullParserFactory xmlPullParserFactory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = xmlPullParserFactory.newPullParser();
xpp.setInput(inputStream, null);
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String tagName = xpp.getName();
// Bỏ qua dữ liệu của thẻ data & weather
if (!tagName.equalsIgnoreCase("data") &&
!tagName.equalsIgnoreCase("weather"))
Log.d("HTSI", tagName + " = " + xpp.nextText());

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 24


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

} eventType = xpp.next();
}

5. ĐỌC GHI DỮ LIỆU JSON


5.1. Định dạng JSON
- JSON (JavaScript Object Notation) được định nghĩa dữ theo ngôn ngữ JavaScript, tiêu
chuẩn ECMA-262 năm 1999, cấu trúc là một định dạng văn bản đơn giản với các
trường dữ liệu được lồng vào nhau. JSON được sử dụng để trao đổi dữ liệu giữa các
thành phần của một hệ thống tương thích với hầu hết các ngôn ngữ C, C++, C#, Java,
JavaScript, Perl, Python...
- JSON được xây dựng dựa trên hai cấu trúc chính:
o Tập hợp cặp giá trị name/value, trong nhiều ngôn ngữ khác nhau cặp giá trị
này có thể là object, record, struct, dictionary, hash table, keyed list...
o Tập hợp danh sách các giá trị, có thể là array, vector, list hay sequence.
- Tuỳ thuộc vào dữ liệu cần trao đổi, JSON có thể có nhiều dạng khác nhau, tuy nhiên
có thể tổng hợp ở những hai dạng chính sau:
o Một đối tượng Object chứa các cặp giá trị string/value không cần thứ tự, được
bao trong cặp “{}”, các giá trị bên trong được định dạng “string:value” và chia
cách nhau bởi dấu “,”. Value ở đây có thể là chuỗi, số, true- false, null...Có thể
xem mô tả cùng ví dụ sau:

Hình 2.6. Minh họa cấu trúc dữ liệu JSON 1


- Ví dụ:
{"date":"20-06-2014", "tempMaxC":13, "tempMaxF":56}

o Một đối tượng mảng có bao gồm nhều phần tử con có thứ tự. Các phần từ con
được bao trong cặp “[]” và chia cách nhau bởi dấu “,”. Mỗi phần tử con có thể
là một giá trị đơn lẻ như: số, chuỗi, true-false, null hoặc một object khác, thậm
chí có thể là một mảng.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 25


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 2.7. Minh họa cấu trúc dữ liệu JSON 2


- Ví dụ 1:
[
{"source":"weather.t3h.vn"},
{"data":
[
{"date":"20-06-2014","tempMaxC":13,"tempMaxF":56},
{"date":"21-06-2014","tempMaxC":20,"tempMaxF":60}
]
}
]

- Ví dụ 2:
{
"product":"Google Nexus 5",
"color":
[
"grey","white","black"
],
"memory":
[
16,32,64
]
}

5.2. Đọc ghi dữ liệu JSON


- Việc thực hiện đọc ghi dữ liệu JSON trong Android có thể thông qua nhiều thư viện
khác nhau như GSON, Json.Smart, Jackson, … Tuy nhiên, trong tài liệu này, chúng ta
sẽ khảo sát các lớp JSON trong gói org.json được tích hợp sẵn trong Android SDK.
Trong gói này bao gồm bốn lớp chính:
o JSONObject: đối tượng quản lý JSON ở dạng một Object.
o JSONArray: đối tượng quản lý JSON ở dạng tập hợn các Object hoặc Array.
o JSONStringer: đối tượng chuyển dữ liệu JSON thành dạng chuỗi.
o JSONTokener: chuyển đổi đối tượng JSON (chuẩn RFC-4627) mã hoá chuỗi
một thành đối tượng tương ứng.
5.2.1. Ghi dữ liệu JSON

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 26


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Để thực hiện ghi dữ liệu JSON, cần xác định rõ cấu trúc của dữ liệu cần lưu trữ. Nếu
dữ liệu cần ghi là một đối tượng, dữ liệu sẽ được ghi vào một JSONObject; nếu dữ
liệu là một mảng, dữ liệu sẽ được ghi vào một JSONArray.
- Ví dụ 1: ghi dữ liệu có cấu trúc đơn giản dạng JSONObject:
{
"date":"17-06-2015",
"tempMaxC":13,
"tempMaxF":56
}
// Khởi tạo đối tượng JSONObject
JSONObject jsonObject = new JSONObject();

// Thiết lập các cặp giá trị name/value


jsonObject.put("date", "17-06-2015");
jsonObject.put("tempMaxC", 13);
jsonObject.put("tempMaxF", 56);

// Chuyển dữ liệu thành chuỗi để sử dụng


String jsonString = jsonObject.toString();

- Ví dụ 2: ghi dữ liệu có cấu trúc dạng JSONArray.


// Khởi tạo đối tượng JSONArray
JSONArray jsonArray = new JSONArray();

// Khởi tạo và đặt giá trị đối tượng JSONObject "source"


JSONObject jsonObjectSource = new JSONObject();
jsonObjectSource.put("source", "weather.t3h.vn");

// Khởi tạo đối tượng JSONArray "data"


JSONArray jsonArrayData = new JSONArray();

// Khởi tạo và đặt giá trị phần tử JSONObject 1


JSONObject jsonObjectDate1 = new JSONObject();
jsonObjectDate1.put("date", "17-06-2015");
jsonObjectDate1.put("tempMaxC", 13);
jsonObjectDate1.put("tempMaxF", 56);

// Khởi tạo và đặt giá trị phần tử JSONObject 2


JSONObject jsonObjectDate2 = new JSONObject();
jsonObjectDate2.put("date", "18-06-2015");
jsonObjectDate2.put("tempMaxC", 20);
jsonObjectDate2.put("tempMaxF", 60);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 27


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

// Đặt giá trị vào mảng "data"


jsonArrayData.put(jsonObjectDate1);
jsonArrayData.put(jsonObjectDate2);

// Đặt giá trị mảng vào "data"


JSONObject jsonObjectData = new JSONObject();
jsonObjectData.put("data", jsonArrayData);

// Đặt giá trị vào mảng


jsonArray.put(jsonObjectSource);
jsonArray.put(jsonObjectData);

// Xuất giá trị mảng


Log.d("HTSI", jsonArray.toString());

5.2.2. Đọc dữ liệu JSON


- Việc đọc dữ liệu JSON khá gần giống với việc ghi, chỉ khác nhau việc đọc dữ liệu có
nhận dữ liệu đầu vào.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 28


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 3
GOOGLE MAP

1. GOOGLE PLAY SERVICE SDK


- Google Play Service SDK (GPSDK) là bộ công cụ phát triển tích hợp các dịch vụ
Google đang sở hữu và phát triển vào trong các ứng dụng hoạt động trên các thiết bị di
động.
- GPSDK là gói API riêng biệt với bộ Android SDK.
- Phiên bản Android, GPSDK chỉ hoạt động trên các thiết bị có version từ 2.2 trở lên.
- Một số dịch vụ trong GPSDK:

Hình 3.1. Một số dịch vụ trong GPSDK

- Cài đặt GPSDK: thực hiện cài đặt gói API từ công cụ Android SDK Manager .

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 29


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.2. Cài đặt gói API từ công cụ Android SDK Manager
- GPSDK trên thiết bị, thường có 4 trạng thái:
o Google Play Store đã được cài đặt cùng các dịch vụ đi kèm (phổ biến).
o Google Play Store đã được cài đặt nhưng các dịch vụ chưa được cài đặt.
o Google Play Store chưa được cập nhật phiên bản mới nhất.
o Google Play Store không được cài đặt trên thiết bị (máy ảo).
o Google Play Store tự động cập nhật các dịch vụ khi có kết nối internet.
- Kiểm tra trạng thái của GPSDK:
o Thực hiện kiểm tra trong onResume bằng phương thức
isGooglePlayServiceAvailable().
o Kết quả trả về:
 SUCCESS
 SERVICE_MISSING
 SERVICE_VERSION_UPDATE_REQUIRED
 SERVICE_DISABLE
- Thực hiện gọi phương thức getErrorDialog() để hướng dẫn người cập nhật GPSDK
hoặc kích hoạt trong phần Setting.

2. GOOGLE MAPS ANDROID API


- Google Maps Android API (GMAA) bao gồm các dữ liệu bản đồ được phát triển bởi
Google Inc cho phép lập trình viên tích hợp vào các ứng dụng thông qua các phương
thức được cung cấp sẵn.
- GMAA hỗ trợ các thao tác với giao diện đồ họa của bản đồ bao gồm:
o Vẽ biểu tượng trên bản đồ (Marker).
o Đồ họa đường thẳng (Polylines).
o Đồ họa hình đa giác (Polygons).
o Bitmap trên bản đồ (Ground & Tile Overlay).

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 30


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2.1. Tạo dự án Google Maps (Google Maps project)


Để tạo dự án Google Maps, chúng ta tạo dự án Android nhưng ở hộp thoại “Add an activity
to mobile”, chúng ta chọn Google Maps Activity.
- Sau khi dự án Google Maps được tạo sẽ có cấu trúc như sau:

Hình 3.3. Cấu trúc dự án Google Maps


Dự án Google Maps được tạo có chứa hai tập tin quan trọng mà chúng ta sẽ thao tác, chỉnh
sửa với chúng là google_maps_api.xml và MapsActivity.java.

2.2. Google Maps Android API Key


- Google Maps Android API Key: chuỗi mã hóa được Google cung cấp miễn phí để
quản lý và chứng thực việc truy xuất dữ liệu bản đồ trên ứng dụng.
- GMAA Key được liên kết thông qua Digital Cerfiticate (DC-Chứng thư số) và
Pakage name (Tên đóng gói) của ứng dụng.
- Tạo GMAA Key bao gồm 3 bước:
o Truy xuất thông tin DC bằng mã SHA-1.
o Đăng ký Project trong Google API Console.
o Tích hợp Google Map Service vào Project và gửi yêu cầu cấp GGMA Key.
- Cấu hình tập tin AndroidManifest: cần thực hiện khai báo một số quyền truy cập phần
cứng và sử dụng dữ liệu người dùng.
o Xác định quyền sử dụng dữ liệu bản đồ thông qua GMAA KEY:
<string name="google_maps_key" translatable="false"
templateMergeStrategy="preserve">YOUR_KEY_HERE</string>

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 31


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Chú ý: YOUR_KEY_HERE được thay thế bằng GMAA KEY.


- Một số quyền cần thiết để sử dụng Google Maps:
<!-- Xác định quyền truy cập, kiểm soát Internet. -- >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.vidu.minhhoamap.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- Xác định quyền truy cập, kiểm soát dữ liệu phần cứng GPS -- >
<uses-permission
android:name="com.google.android.providers.gsf.permission.READ_GSERVICES”/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE”/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION”/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION”/>
<!-- 2 quyền dưới đây không bắt buột phải khai báo để sử dụng
Google Maps Android API v2 nhưng được khuyến khích nên khai báo. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

- Sử dụng OpenGL 2.0 cho việc đồ họa bản đồ:


<uses-feature android:glEsVersion="0x00020000" android:required="true"/>

2.3. GoogleMap & Xây dựng Đối tượng


- Tạo các đối tượng để thực hiện tương tác giữa ứng dụng với người dùng bao gồm:
o GoogleMap:
 Kết nối đến Google Map Service
 Tải dữ liệu bản đồ theo từng mảng nhỏ (tiles).
 Thể hiện dữ liệu bản đồ trên màn hình thiết bị.
 Thể hiện các điều khiển giao tiếp như thu phóng, la bàn…
 Xử lý các tương tác thu phóng, xoay, góc nhìn…
o MapFragment: xây dựng giao diện bản đồ bằng cách xây dựng Fragment.
o MapView: xây dựng giao diện bản đồ như một điều khiển và tương tác với
Activity.
- Truy xuất và sử dụng đối tượng GoogleMap từ thẻ fragment trong XML:
GoogleMap mMap =
((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 32


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Hoặc tạo trực tiếp bằng câu lệnh Java:


MapFragment mapFragment = MapFragment.newInstance();
GoogleMap mMap = mapFragment.getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
getFragmentManager().beginTransaction().add(R.id.container,
mapFragment).commit();

- Cần thực hiện kiểm tra đối tượng GoogleMap trước khi tương tác. Mã lệnh kiểm tra
như sau:
private void setUpMapIfNeeded(){
//Khởi tạo đối tượng GoogleMap nếu chưa có giá trị
if( mMap == null){
mMap = mapFragment.getMap();
// Kiểm tra đối tượng GoogleMap đã được khởi tạo thành công
if( mMap != null) {
// Thực hiện các tùy chỉnh trên đối tượng GoogleMap
mMap.setMapType (GoogleMap.MAP_TYPE_TERRAIN);
}
}
}

- Các giao diện bản đồ:


o MAP_TYPE_NORMAL
o MAP_TYPE_HYBRID
o MAP_TYPE_NONE
o MAP_TYPE_SATELLITE
o MAP_TYPE_TERRAIN
- Để thực hiện thay đổi giao diện gọi phương thức setMapType(int) và truyền vào
tham số tương ứng.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 33


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.4. Minh họa một số loại giao diện bản đồ

- Thiết lập các giá trị ban đầu và điều khiển cho GoogleMap bao gồm:
o Góc nhìn (Camera).
 Thu phóng (zoom).
 Chuyển điểm (location).
 Xoay (bearing).
 Góc nghiêng (titl).
o La bàn và điều khiển thu phóng.
o Các điều khiển cử chỉ trên bản đồ.
- Thiết lập các giá trị ban đầu và điều khiển cho GoogleMap trong XML:
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment"/>

- Thực hiện tùy chỉnh GoogleMap thông qua đối tượng GoogleMapOptions:
GoogleMapOptions mapOptions = new GoogleMapOptions();

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 34


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

mapOptions.mapType(GoogleMap.MAP_TYPE_HYBRID)
.scrollGesturesEnabled(true)
.rorateGesturesEnabled(true)
.zoomControlsEnabled(true);

- Thiết lập đối tượng GoogleMapOptions:


o MapFragment.newInstance(GoogleMapOptions).
o MapView(Context, GoogleMapOptions).
2.4. Đồ họa trên Google Map
2.4.1. Marker:
- Marker là lớp được xây dựng sẵn cho việc sử dụng định vị tọa độ trên bản đồ, hiển thị
thông tin địa điểm và tương tác với người dùng. Ví dụ minh họa sử dụng lớp Marker:
MarkerOptions markerOptions = new MarkerOptions();
LatLng position = new LatLng(lat, lng);
markerOptions.position(position);
markerOptions.draggable(true);
Marker marker = map.addMarker(markerOptions);
marker.setTitle("Nhà của tui");

Hình 3.5. Minh họa sử dụng lớp Marker

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 35


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Tùy chỉnh Marker bằng các thông số:


o Position.
o Title.
o Snippet.
o Draggable.
o Visible.
o Anchor.
o Icon.
- Ví dụ tùy chỉnh Marker bằng các thông số position, title, snippet, draggable, anchor,
visible và icon:
mMap.addMarker(new MarkerOptions()
.position(new LatLng(10.385474, 104.488199))
.title(“Nhà của tôi”)
.snippet(“10 Mạc Thiên Tích”);
.draggable(true)
.anchor(0.7f, 0.6f)
.visible(BitmapDescriptorFactory
.fromResource(R.drawable.vision_ward)));

2.4.2. InfoWindow:
- InfoWindow được thể hiện phía trên đối tượng Marker thể hiện các thông tin cần thiết
về vị trí đang định vị.
- Chỉ một đối tượng InfoWindow hiển thị ở một thời điểm và có thể điều khiển thông
qua hai phương thức:
o showInfoWindow().
o hideInfoWindow().
- Để tùy chỉnh InfoWindow trong lớp GoogleMap hỗ trợ giao diện
InfoWindowAdapter bao gồm 2 phương thức:
o getInfoWindow(Marker).
o getInfoContents(Marker).
- Gọi phương thức setInfoWindowAdapter để thiết lập InfoWindow cho đối tượng
GoogleMap.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 36


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.6. Minh họa sử dụng Marker và InfoWindow

- Google Maps API cung cấp các giao diện cho phép bắt lại các sự kiện tương với
Marker và InfoWindow.
o OnMarkerClickListener.
o OnMarkerDragListener.
o OnInfoWindowClickListener.
2.4.3. Shape:
- Shape bao gồm các đối tượng hình học được vẽ trên bản đồ bao gồm các dạng sau:
o Polyline
o Polygons
o Circle
- Polyline: được tạo bằng các nối các điểm dựa trên toạ độ điểm. Ví dụ minh họa:
PolylineOptions options = new PolylineOptions()
.add(new LatLng(10.919618, 106.523438))
.add(new LatLng(13.410994, 123.046875))
.add(new LatLng(35.746512, 139.833984));
Polyline polyline = mMap.addPolyline(options);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 37


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 3.7. Minh họa sử dụng Polyline Hình 3.8. Minh họa sử dụng Polyline

- Polyline có các phương thức tùy chỉnh sau:


boolean equals(Object other)
int getColor()
String getId()
List<LatLng> getPoints()
float getWidth()
float getZIndex()
int hashCode()
boolean isGeodesic()
boolean isVisible()
void remove()
void setColor(int color)
void setGeodesic(boolean geodesic)
void setPoints(List<LatLng> points)
void setVisible(boolean visible)
void setWidth(float width)
void setZIndex(float zIndex)

- Polygon: giống với Polyline được tạo bằng các nối các điểm dựa trên toạ độ điểm, tuy
nhiên Polygon cho phép khép kín các tọa độ và thao tác vùng đã khép kín.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 38


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ minh họa sử dụng Polygon:


double height = 5, width = 5;
LatLng center = new LatLng(10.780231, 106.698579);
PolygonOptions options = new PolygonOptions();
options.add(new LatLng(center.latitude – height, center.longgitude – width))
.add(new LatLng(center.latitude – height, center.longgitude + width))
.add(new LatLng(center.latitude + height, center.longgitude + width))
.add(new LatLng(center.latitude – height, center.longgitude + width))
Polygon polygon = mMap.addPolygon(options);

Hình 3.9. Minh họa sử dụng Polygon


- Polygon có các phương thức tùy chỉnh sau:
PolygonOptions add(LatLng point)
PolygonOptions add(LatLng... points)
PolygonOptions addAll(Iterable<LatLng> points)
PolygonOptions addHole(Iterable<LatLng> points)
int describeContents()
PolygonOptions fillColor(int color)
PolygonOptions geodesic(boolean geodesic)
int getFillColor()
List<List<LatLng>> getHoles()

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 39


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

List<LatLng> getPoints()
int getStrokeColor()
float getStrokeWidth()
float getZIndex()
boolean isGeodesic()
boolean isVisible()
PolygonOptions strokeColor(int color)
PolygonOptions strokeWidth(float width)
PolygonOptions visible(boolean visible)
void writeToParcel(Parcel out, int flags)
PolygonOptions zIndex(float zIndex)

- Circle: đối tượng hình học (hình tròn) được xác định trên bản đồ thông qua bán kính
và tâm.
CircleOptions circleOptions = new CircleOptions();
circleOptions.center(HCM).radius(5);
Circle circle = mMap.addCircle(circleOptions);
circle.setFillColor(Color.CYAN);
circle.setStrokeColor(Color.WHITE);

Hình 3.10. Minh họa sử dụng Circle

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 40


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Circle có các phương thức tùy chỉnh sau:

LatLng getCenter()

int getFillColor()
String getId()

double getRadius()

int getStrokeColor()
float getStrokeWidth()
float getZIndex()

boolean isVisible()

void remove()
void setCenter(LatLng center)
void setFillColor(int color)
void setRadius(double radius)
void setStrokeColor(int color)
void setStrokeWidth(float width)
void setVisible(boolean visible)
void setZIndex(float zIndex)

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 41


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 4
GOOGLE CLOUD MESSAGING

1. GIỚI THIỆU
- Google Cloud Messaging (GCM) là một dịch vụ cho phép gửi dữ liệu từ máy chủ của
bạn đến các thiết bị Android của người dùng, và ngược lại.
- GCM được sử dụng cho hoạt động giao dịch giữa các ứng dụng và máy chủ hỗ trợ đầu
cuối. Cloud Messaging hiện đang được tích hợp vào Google Play Services và nhờ
những cải tiến mạnh mẽ, Cloud Messaging giờ đây tương trợ kết nối liên tục và truyền
tải thông điệp ngược dòng (upstream). Do đó, thiết bị có thể gởi phản hồi trở lại máy
chủ mà không còn chỉ một chiều từ máy chủ đến thiết bị như trước đây.
- Nhờ tính năng truyền tải ngược, các thông báo (Notification) mà bạn nhận được và bỏ
lỡ trên thiết bị này có thể được đồng bộ với thiết bị khác. Bạn sẽ không phải soát lại
hàng loạt các thông báo tương tự trên điện thoại khi chuyển sang sử dụng chiếc máy
tính bảng của mình.

Hình 4.1. Logo Google Cloud Messaging.

- GCM là hoàn toàn miễn phí và không giới hạn băng thông. Dịch vụ hoạt động trên các
gói dữ liệu có dung lượng nhỏ hơn 4kb và tin nhắn tới thiết bị Android là tức thời
(Push-notification).
- GCM là phù hợp cho việc xây dựng các ứng dụng nhắn tin tức thời hoặc tương tác
giữa người dùng và nhà phát triển ứng dụng.
- Ví dụ:
o Thông báo tới thiết bị Android của người khi có một email mới. GCM gửi
thông báo tới người quản lý khi có một đơn đặt hàng trên trang Web của họ.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 42


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Gửi tin nhắn tới cả một cộng đồng như: cồng đồng nhân viên thuộc cùng một công ty,
học sinh hoặc phụ huynh của một trường học với chi phí thấp nhất và hiệu quả nhất.
- Nguyên tắc hoạt động:
Hãy cùng xem hình dưới để hiểu rõ hơn.

Hình 4.2. Nguyên tắc hoạt động khi Web Server gửi thông báo
về thiết bị thông qua Google Cloud Messaging.

2. CẤU HÌNH CHO GOOGLE CLOUD MESSAGING


2.1. Đăng ký dịch vụ GCM
- Đầu tiên, bạn cần đăng ký Google Cloud Messaging bằng tài khoản Google của bạn.
o Truy cập Google Console tại: https://cloud.google.com/console/project
o Nếu bạn chưa tạo một dự án API nào, nhấp vào “Create Project”. Điền tên và
nhấn Create.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 43


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.3. Tạo một Project trên Google Developers Console.

o Một khi dự án đã được tạo ra, một trang xuất hiện hiển thị ID dự án của bạn. Ví
dụ: id dự án của bạn là engaged-root-93803

Hình 4.4. Minh hoạ màn hình tổng quan của dự án trên Google Developers Console.

o Sao chép số ID Project này lưu lại. Bạn sẽ sử dụng nó như GCM sender ID.
- Sau đó, bạn cần kích hoạt API cho GCM
o Trong thanh bên trên bên trái, chọn mục API & auth → Chọn tiếp APIs
o Tìm đến mục Google Cloud Messaging for Android và “Enable API”.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 44


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.5 Kích hoạt Google Cloud Messaging trong dự án của bạn 1

Hình 4.6. Kích hoạt Google Cloud Messaging trong dự án của bạn 2

- Bây giờ bạn đã có thể lấy API Key với các bước sau:
o Trong thanh bên trên bên trái, chọn API & auth → Sau đó chọn Credentials.
o Trong phần Public API access, nhấp vào Create new key.
o Trong hộp thoại Create a new key, nhấp vào Server key.
o Trong hộp thoại IP address bên dưới nhập vào địa chỉ IP Web Server của bạn.
Dùng địa chỉ 0.0.0.0/0 cho mục đích thử nghiệm.
o Nhấp vào Create.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 45


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Trong trang mới, sao chép API Key:

Hình 4.7. Sao chép lại API key.


- Mở tập tin appengine-web.xml và tìm đến dòng lệnh bên dưới và thay thế
“YOUR_KEY_HERE” là API key vừa lấy được:
<property name="gcm.api.key" value="YOUR_KEY_HERE" />

2.2. Cấu hình môi trường hoạt động cho GCM


- Download thư viện hỗ trợ GCM
- Mở SDK Manager lên và tiến hành tải thư viện hỗ trợ GCM.
- Vào mục Extras → Chọn mục Google Cloud Messaging for Android Library:

Hình 4.8. Tải GCM helper library.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 46


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2.3. Chuẩn bị máy ảo với Google API:


- Mở ADV Manager và tạo một máy ảo Google API emulator.

Hình 4.9. Tạo máy ảo Google API emulator


- Chạy máy ảo lên.
- Sau khi máy ảo chạy lên. Vào mục Setting, chọn Select Account & Sync. Và chọn
Add Account sau đó điền tài khoản Google của bạn vào.
- Lưu ý: Nếu bạn không đăng nhập tài khoản google vào và chạy ứng dụng sử dụng
dịch vụ GGM sẽ bị lỗi GCM: error (ACCOUNT_MISSING).

Hình 4.10. Lỗi Account Missing.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 47


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

2.4. Tạo Project để đăng ký GCM


- Tạo một Android Application Project.
- Trong tập tin AndroidManifest.xml cần đăng ký các quyền sau:
o INTERNET – để kết nối mạng.
o ACCESS_NETWORK_STATE – để kiểm tra trạng thái mạng.
o GET_ACCOUNTS – cần bởi vì GCM truy cập Google account của bạn.
o WAKE_LOCK – Cần để gọi thiết bị của bạn khi ở trạng thái sleep.
o VIBRATE – Xin quyền rung thiết bị.

2.5. Sử dụng “backend” trong Android Studio


- Backend được hiểu như một server. Backend minh họa dưới đây sử dụng Google
Cloud Endpoints để định nghĩa một RESTfull API.
- Sau đây là minh họa cụ thể từng bước thực hiện tạo một “backend” trong Android
Studio:
o Để tạo một “backend” từ một dự án (project) Android đã có sẵn, chúng ta khởi
động Android Studio và chọn File → New → Module hoặc nhấp chuột phải
vào dự án (project) và chọn New → Module.

Hình 4.11. Tạo “backend”


o Xuất hiện hộp thoại “Create New Module” → Chọn “Google Cloud Module”
→ Next

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 48


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.12. Tạo backend


o Xuất hiện hộp thoại “New Google Cloud Module” và điền các thông tin như
sau:

Hình 4.13. Tạo backend


Trong đó:
- Module type (1): chúng ta chọn “App Engine Backend with Google Cloud
Messaging”.
- Module name (2): là tên của backend mà chúng ta muốn tạo, ở đây tôi để mặc định là
backend.
- Package name (3): tên gói để chứa backend.
- Client module (4): backend được tạo cho ứng dụng này.
Cuối cùng, chúng ta chọn Finish để kết thúc quá trình tạo backend. Và backend sau khi tạo
có cấu trúc như sau:

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 49


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.14. Cấu trúc backend sau khi tạo

Hình 4.15. Cấu trúc backend sau khi tạo

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 50


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Chạy Debbugging backend (Debugging the backend locally).

Hình 4.16. Chạy Debbugging backend

Hình 4.17. Kết quả sau khi chạy Debbug


- Kết nối ứng dụng Android của bạn tới backend
Trước khi những tin nhắn có thể được gửi từ Google Cloud Messaging backend đến các thiết
bị thì những thiết bị này cần được đăng ký với GCM backend. Ví dụ sau đây sẽ minh họa cho
bạn cách tạo AsyncTask để đăng ký các thiết bị với một GCM backend:
class GcmRegistrationAsyncTask extends AsyncTask<Void, Void, String> {
private static Registration regService = null;
private GoogleCloudMessaging gcm;
private Context context;

// Gán vào SENDER_ID số dự án (Project number) đã có được khi ta đăng ký


// dịch vụ GCM
private static final String SENDER_ID = "325746572265";

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 51


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

public GcmRegistrationAsyncTask(Context context) {


this.context = context;
}
@Override
protected String doInBackground(Void... params) {
if (regService == null) {
Registration.Builder builder = new
Registration.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// setRootUrl và setGoogleClientRequestInitializer để kiểm
// tra cục bộ (local)
.setRootUrl("http://10.0.2.2:8080/_ah/api/")
.setGoogleClientRequestInitializer(new
GoogleClientRequestInitializer() {
@Override
public void initialize(AbstractGoogleClientRequest<?>
abstractGoogleClientRequest) throws IOException {

abstractGoogleClientRequest.setDisableGZipContent(true);
}
});

regService = builder.build();
}
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
String regId = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regId;

//Gửi ID đăng ký đến server của bạn qua HTTP. Như vậy, nó có
//thể sử dụng GCM/ HTTP hoặc CSS để gửi tin nhắn đến các
//ứng dụng của bạn
regService.register(regId).execute();

} catch (IOException ex) {


ex.printStackTrace();
msg = "Error: " + ex.getMessage();
}
return msg;
}
@Override
protected void onPostExecute(String msg) {
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
Logger.getLogger("REGISTRATION").log(Level.INFO, msg);
}
}
o Chú ý:

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 52


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Trong lớp MainActivity.java phải có phương thức new


GcmRegistrationAsyncTask(this).execute(); thì lớp
GcmRegistrationAsyncTask.java mới được thực thi.
- Chạy kiểm tra đăng ký thiết bị với máy ảo Google API emulator.
- Hiển thị các thông báo (notifications) được đẩy (push) từ GCM backend:
o Để sắp xếp thứ tự hiển thị các thông báo (notifications) được gửi đi từ backend,
chúng ta cần viết thêm 2 lớp GcmIntentService.java và
GcmBroadcastReceiver.java vào ứng dụng Android (phía Client):
 Mã nguồn cho lớp GcmIntentService.java
public class GcmIntentService extends IntentService {

public GcmIntentService() {
super("GcmIntentService");
}

@Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);

String messageType = gcm.getMessageType(intent);

if (extras != null && !extras.isEmpty()) {


if
(GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
Logger.getLogger("GCM_RECEIVED").log(Level.INFO,
extras.toString());
showToast(extras.getString("message"));
}
}

GcmBroadcastReceiver.completeWakefulIntent(intent);
}

protected void showToast(final String message) {


new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override
public void run() {

Toast.makeText(getApplicationContext(), message,
Toast.LENGTH_LONG).show();
}
});
}
}
 Mã nguồn cho lớp GcmBroadcastReceiver.java

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 53


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}

Sau khi thêm 2 lớp GcmIntentService.java và lớp GcmBroadcastReceiver.java vào ứng dụng
Android, chúng ta đăng ký cho chúng bằng cách thêm đoạn mã vào tập tin
AndroidManifest.xml (đặt trong thẻ <application>) như sau:
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="TEN_PACKAGE_CHUA_UNG_DUNG_CUA_BAN" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />

- Triển khai backend trực tiếp đến Google App Engine


o Nếu backend đang chạy thì dừng backend bằng cách chọn Run → Stop.
o Chọn Build → Deploy Module to App Engine. Xuất hiện hộp thoại Deploy to
App Engine → chọn dự án Google Developers Console (phải đăng nhập tài
khoản Google) → chọn Deploy. Nếu chưa có dự án Google Developers
Console nào thì nhấn chọn “create a new Google Developers Console project”
để tạo dự án Google Developers Console mới.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 54


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 4.18. Triển khai backend đến App Engine

o Mở tập tin appengine-web.xml theo đường dẫn src/main/webapp/WEB-


INF/appengine-web.xml và tìm đến thẻ <application> và thay thế
“myApplicationId” bằng ID của dự án bạn vừa tạo (dự án Google Developers
Console).

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 55


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 5
CÁC ĐIỀU KHIỂN ĐA TRUYỀN THÔNG

1. MEDIA PLAYER
1.1. Giới thiệu
- Android cung cấp lớp MediaPlayer để quản lý các tác vụ đa truyền thông bao gồm các
tập tin âm thanh, hình ảnh, video...
- Có thể truy xuất các tập tin media thông qua việc lưu trữ như tài nguyên ứng dụng, bộ
nhớ thiết bị, content provider hoặc thông qua URL.
- MediaPlayer quản lý các tập tin media và luồng xử lý thông qua một tập các trạng thái
sau:
o Khởi tạo đối tượng MediaPlayer.
o Chuẩn bị bộ thu phát MediaPlayer.
o Bắt đầu thực hiện thu phát.
o Thực hiện các thao tác Pause và Stop trên tập tin media trong khi đang thu
phát.
o Hoàn thành quá trình thu phát.
1.2. Xây dựng MediaPlayer Audio
- Android hỗ trợ truy xuất các tập tin Audio thông qua các lưu trữ như: tài nguyên ứng
dụng, bộ nhớ thiết bị, content provider và xử lý các luồng URL.
- Có thể đóng gói tập tin Audio vào thư mục res/raw như một dạng tài nguyên của ứng
dụng.
- Để thu phát một tập tin Audio cần tạo một đối tượng MediaPlayer và thiết lập nguồn
dữ liệu cho đối tượng này.
- Thực hiện thu phát bằng phương thức Create() truyền vào 2 tham số: context của ứng
dụng và một trong những dạng tài nguyên sau:
o Định danh của tài nguyên.
o URI trỏ đến nơi lưu trữ của tập tin trên thiết bị.
o URI trỏ đến tập tin trực tuyến thông qua URL.
o URI trỏ đến dòng dữ liệu trong bảng của content provider.
- Ví dụ tạo đối tượng MediaPlayer
Context appContext = getApplicatiionContext();
MediaPlayer filePlayer = MediaPlayer.create(appContext,

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 56


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Uri.parse(file:///sdcard/localfile.mp3));
MediaPlayer urlPlayer = MediaPlayer.create(appContext,
Uri.parse(“http://site.com/audio/audio.mp3”));
MediaPalyer contentPlayer = MediaPlayer.create(appContext,
Settings.System.DEFAULT_RINGTONE_URI);

- Để thực thi việc thu phát tập tin Video cần tạo một màn hình cho việc trình chiếu. Có
hai cách để thực hiện công việc này:
o Sử dụng thành phần Video View, đóng gói các thao tác trên đối tượng
MediaPlayer (tạo trình chiếu, chuẩn bị và cấp phát tập tin) vào trong thành
phần View này.
o Xây dựng màn hình hiển thị riêng và gắn kết dữ liệu thông qua đối tượng
MediaPlayer.
1.3. Xây dựng MediaPlayer Video
- Để thực thi việc thu phát tập tin Video cần tạo một màn hình cho việc trình chiếu. Có
hai cách để thực hiện công việc này:
o Sử dụng thành phần Video View, đóng gói các thao tác trên đối tượng
MediaPlayer (tạo trình chiếu, chuẩn bị và cấp phát tập tin) vào trong thành
phần View này.
o Xây dựng màn hình hiển thị riêng và gắn kết dữ liệu thông qua đối tượng
MediaPlayer.
- Ví dụ tạo bộ thu phát bằng Video View:
VideoView videoView = (VideoView) findViewById(R.id.surface);
videoView.setKeepScreenOn(true);
videoView.setVideoPath(“/sdcard/test2.2gp”);
if(videoView.canSeekForward())
videoView.seekTo(videoView.getDuration()/2);
videoView.start();
[ ... do something ... ]
videoView.stopPlayback();

- Ví dụ tạo màn hình hiển thị trong Video View:


<LinearLayout xmlns:android= “http://schemas.android.com/apk/res/android”
android:orientation= “vertical”
android:layout_width= “fill_parent”
android:layout_height= “fill_parent”>
<SurfaceView
android:id= “@+id/surface”
android:layout_width= “wrap_content”

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 57


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

android:layout_height = “wrap_content”
android:layout_gravity= “center”>
</SurfaceView>
</LinearLayout>

- Tạo đối tượng Surface Holder để hỗ trợ việc cập nhật các nguồn xử lý bên dưới:
public class MyActivity extends Activity implements SurfaceHolder.Callback
{
private MediaPlayer mediaPlayer;
@Override
public void onCreate(Bundle saveInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mediaPlayer = new MediaPlayer();
SurfaceView surface = (SurfaceView) findViewById(R.id.surface);
SurfaceHolder holder = surface.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.setFixedSize(400, 300);
}
}

- Khởi tạo nội dung của tập tin cần trình chiếu:
public void SurfaceCreated(SurfaceHolder holder)
{
try{
mediaPlayer.setDisplay(holder);
mediaPlayer.setDataSource(“/sdcard/test2.3gp”);
mediaPlayer.prepare();
mediaPlayer.start();
}
catch(IllegalArgumentException e)
{
Log.d(“MEDIA_PALYER”, e.getMessage());
}
catch(IllegalStateException e){
Log.d(“MEDIA_PALYER”, e.getMessage());
}
catch(IOException e)
{
Log.d(“MEDIA_PALYER”, e.getMessage());
}
}
1.4. Các điều khiển trên MediaPlayer

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 58


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Khởi chạy đối tượng bằng phương thức start().


- Ví dụ:
Mediaplayer mediaPlayer = new MediaPlayer();
mediaPlayer.start();

- MediaPlayer cung cấp một số phương thức cho việc điều khiển như getDuration,
getCurrentPositon, seekTo...

mediaPlayer.start();
int pos = mediaPlayer.getCurrentPosition();
int duration = mediaPlayer.getDuration();
mediaPlayer.seekTo(pos + (duration-pos)/10);
[ ... wait for a duration ... ]
mediaPlayer.stop();

- Một số phương thức khác như hỗ trợ âm thanh, chống khóa màn hình trong khi thu
phát, thiết lập các chế độ phát lại...
o Sử dụng phương thức isLooping() và setLooping() để thiết lập chế độ phát lại
cho tập tin media.
o Ví dụ:
if (!mediaPlayer.isLooping())
mediaPlayer.setLooping(true);

o Thiết lập Wake Clock giữ cho màn hình luôn mở khi đang phát bằng phương
thức setScreenOnWhilePlaying()
o Ví dụ:
mediaPlayer.setSreenOnWhilePlaying(true);

o Điều khiển âm thanh bằng phương thứ setVolume()


o Ví dụ:
mediaPlayer.setVolume(1f, 0.5f);

2. THU ÂM THANH VÀ HÌNH ẢNH (RECODING)

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 59


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Android cung cấp 2 lựa chọn trong việc thu âm thanh và hình ảnh:
o Sử dụng Intent để khởi chạy ứng dụng Video Camera. Lựa chọn này cho phép
chỉ định nơi lưu trữ, định dạng và chất lượng của hình ảnh thu được.
o Sử dụng lớp Media Recoder để xây dựng các thành phần UI, các thiết lập
record cho ứng dụng.
o Sử dụng Intent để thu hình ảnh: bằng cách truyền action
ACTION_VIDEO_CAPTURE vào một Intent và gửi Intent này đến một
Activity khác xử lý và trả về kết quả thu được.
- Ví dụ:
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
startActivityForResult(intent, RECORD_VIDEO);

- MediaStore hổ trợ hai URI cho phép lựa chọn trong quá trình thu hình ảnh:
o EXTRA_OUPUT: cho phép tùy chọn nơi lưu trữ.
o EXTRA_VIDEO_QUALITY: cho phép tùy chọn chất lượng hình ảnh thu
được.
- Ví dụ sử dụng Intent để thu hình ảnh:
private static int RECORD_VIDEO =1;
private static int HIGH_VIDEO_QUALITY = 1;
private static int MMS_VIDEO_QUALITY = 0;
private void recordVideo(Uri outputpath)
{
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if(outputpath != null)
Intent.putExtra(MediaStore.EXTRA_OUTPUT, output);
Intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, HIGH_CIDEO_QUALITY);
startActivityForResult(intent, RECORD_VIDEO);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent
data)
{
if(requestCode == RECORD_VIDEO){
Uri recordVideo = data.getData();
}
}

- Sử dụng Media Recorder để thu âm thanh và hình ảnh: cần tạo đối tượng thuộc lớp
MediaRecoder để sử dụng.
- Ví dụ:

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 60


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

MediaRecoder mediaRecorder = new MediaRecorder();

- Cần đăng ký quyền sử dụng cho ứng dụng trong file AndroidManifest.xml
<uses-permisson android:name= “android.permission.RECORD_AUDIO/>
<uses-permission android:name= “android.permission.RECORD_VIDEO/>

- MediaRecoder quản lý các tập tin media và luồng xử lý thông qua một tập các trạng
thái sau:
o Khởi tạo đối tượng MediaPlayer.
o Chỉ định nguồn vào của thiết bị thu.
o Thiết lập định dạng của tập tin đầu ra.
o Thiết lập các chỉ số như: bộ mã hóa, chất lượng hình ảnh, dung lượng xuất ra...
o Chọn tập tin để xuất.
o Chuẩn bị thu âm & hình ảnh.
o Tiến hành thu âm & hình ảnh.
o Hoàn thành quá trình thu.
- Ví dụ tạo MediaRecorder
MediaRecorder mediaRecorder = new MediaRecorder();

// Cấu hình các thông tin đầu vào


mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(mediaRecorder.VideoSource.CAMERA);

// Thiết lập định dạng các thông tin đầu ra


mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);

//Chỉ định mã hóa audio và video


mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

// Chỉ định tập tin đầu ra


mediaRecorder.setOutputFile(“ /sdcard/taptinxuatra.mp4”);

//chuẩn bị record
mediaRecorder.prepare();

o Tiến hành thu, dừng thu và giải phóng tài nguyên


mediaRecorder.start();
mediaRecorder.stop();

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 61


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

mediaRecorder.release();

o Tạo màn hình Preview trong lúc record


public class MyActivity extends Activity implements SurfaceHolder.Callback
{
private MediaRecorder mediaRecorder;
@Override
public void onCcreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SurfaceView surface = (SurfaceView) findViewById(R.id.surface);
SurfaceHolder holder = surface.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.setFixedSize(400, 300);
}
public void surfaceCreated(SurfaceHolder holder)
{
if(mediaRecoder == null)
{
try
{
mediaRecoder.setAudioSource(MediaRecoder.AudioSource.MIC);
mediaRecoder.setVideoSource(MediaRecoder.VideoSource.CAMERA);
mediaRecoder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mediaRecoder.setAudioEncoder(MediaRecoder.AudioEncoder.DEFAULT);
mediaRecoder.setVideoEncoder(MediaRecoder.VideoEncoder.DEFAULT);
mediaRecoder.setOutputFile(“ /sdcard/taptinxuatra.mp4”);
mediaRecorder.setPreviewDisplay(holder.getSurface());
mediaRecoder.prepare();
}
catch(IllegalArgumentException e){
Log.d(“MEDIA_PALYER”, e.getMessage());
}
catch(IllegalStateException e){
Log.d(“MEDIA_PALYER”, e.getMessage());
}
catch(IOException e)
{
Log.d(“MEDIA_PALYER”, e.getMessage());
}
}
}
}

3. CAMERA
3.1. Điều khiển chụp hình với Camera

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 62


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Sử dụng Intent để gửi hành động ACTION_IMAGE_CAPTURE đến activity xử lý và


nhận kết quả trả về.
- Ví dụ:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PICTURE);

- Hành động CAPTURE trả về 2 kiểu hình:


o Thumbnail: định dạng ảnh bitmap được trả về cho người dùng xử lý trong ứng
dụng.
o FullImage: sử dụng URI để lấy kết quả trả về một ảnh hoàn chỉnh và chỉ định
lưu trong MediaStore.
- Ví dụ sử dụng Intent để lấy về dữ liệu của ACTION_IMAGE_CAPTURE
private static int TAKE_PICTURE = 1;
private Uri outputFileUri;
private void getThumbailPicture()
{
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file=new File(Enviroment.getExternalStorageDicrectory(),“hinh.jpg”);
outputFileUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, TAKE_PICTURE);
}

- Nhận kết quả trả về và xử lý


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent
data)
{
if( requestCode == TAKE_PICTURE){
//Kiểm tra nếu kết quả bao gồm 1 thumbail Bitmap
if(data != null){
if(data.hasExtra(“data”)){
Bitmap thumbail = data.getParcelableExtra(“data”);
}
}
else{
//int outputFileUri
}
}
}
- Cần đăng ký trong file AndroidManifest để sử dụng Camera:
<uses-permission android:name= “android.permision.CAMERA”/>

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 63


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Khởi tạo đối tượng Camera để tùy chỉnh và sử dụng:


Camera camera = Camera.open();
[....Làm việc với camera...]
camera.release();

- Tùy chỉnh Camera thông qua đối tượng của Parameter trong lớp Camera:
Camera.Parameters parameters = camera.getParameters();
[... make changes ... ]
Camera.setParameter(parameters);

- Một số thiết lập đối tượng Parameter


o [get/set]ScreenMode
o [get/set]FlashMode
o [get/set]WhiteBalance
o [get/set]ColorEffect
o [get/set]FocusMode
- Tạo màn hình Preview
public class MyActivity extends Activity implements SurfaceHolder.Callback
{
private MediaRecoder mediaRecoder;
@Override
public void onCreate(Bundle savedInstanceState)
{
Super.onCreate(savedInstanceState);
setContentView(R.layout.main);

SurfaceView surface = (SurfaceView) findViewById(R.id.surface);


SurfaceHolder holder = surface.getHolder();
holder.addCallback(this);
holder.setFixedSize(400, 300);
}
public void surfaceCreate(SurfaceHolder holder)
{
if(mediaRecorder == null)
{
try
{
camera = camera.open();
camera.setPreviewDisplay(holder);
camera.starPreview();

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 64


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

[ ... draw on surface ... ]


}
catch (IOException e)
{
Log.d(“CAMERA”, e.getMessage());
}
}
}
public void surfaceDestroyed(SurfaceHolder holder)
{
camera.stopPreview();
camere.release();
}
}

- Ví dụ tiến hành chụp ảnh và lưu trên SDCard


private void takePicture()
{
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
shutterCallback shutterCallback = new ShutterCallback()
{
public void onShutter()
{

}
};

- Ví dụ tiến hành chụp ảnh và lưu trên SDCard


pictureCallback jpegCallback = new PictureCallback()
{
public void onPictureTaken(byte[] data, Camera camera)
{
//Lưu dữ liệu hình vào SD Card
FileOutputStream outStream = null;
try
{
outStream = new FileOutputStream(“ /sdcard/ hinh.jpg”);
outStream.write(data);
outStream.close();
}
catch(FileNotFoundException e)
{
Log.d(“CAMERA”, e.getMessage());

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 65


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

}
catch(IIOException e)
{
Log.d(“CAMERA”, e.getMessage());
}
}
};

3.2. Lưu tập tin Media vào MediaStore


- Có thể lưu tập tin media vào MediaStore bằng 2 cách:
o Sử dụng MediaScanner để thông dịch tập tin vào thêm vào một cách tự động.
o Thêm mới vào một record trong một Content Provider thích hợp.
- Ví dụ tạo MediaScanner để thêm tập tin media
MeidaScannerConnectionClient mediaScannerClient = new
MediaScannerConnectionClient()
{
private MediaScannerConnection msc = null;
{
msc = new MediaScannerConnection(getApplicationContext(), this);
msc.connect ();
}
public void onMediaScannerConnected(){
msc.scanFile(“ /sdcard/hinh1.jpg”, null);
}
public void onScanCompleted(String path, Uri uri){
msc.disconnect();
}
};

- Ví dụ thêm media bằng Content Provider


ContentValues content = new ContentValues(3);
Content.put(Audio.AudioColumns.TITLE, “TrheSoundandtheFury”);
Content.put(Audio.AudioColumnd.DATE_ADDED, System.currentTimeMillis()/1000);
Content.put(Audio.Media.MIME_TYPE, “audio/ amr”);
ContentResolver resolver = getContentResolver();
Uri uri = resolver.insert(mediaStore.Video.Media.EXTERNAL_CONTENT_URI, content);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCAN_FILE, uri));

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 66


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 6
TELEPHONY & SMS

1. TELEPHONE
- Tạo cuộc gọi bằng các sử dụng Intent để gọi Dialer có sẵn trong thiết bị. Ví dụ:
Intent intent = new Intent(Intetn.ACTION_DIAL, Uri.parse(“tel:123456”));
startActivity(intent);

- Thực hiện hành động gọi ACTION_CALL bằng cách nhấn nút Call trong thiết bị.
- Một số thông tin cần thiết cho việc quản lý chức năng Phone trên thiết bị:
o PhoneType (GSM - CDMA)
o UniqueID (IMEI – MIED)
o Sofware version
o Number
- Để truy xuất được các thông tin này cần thực hiện đăng ký trong
AndroidManifest.xml
<uses-permission android:name= “android.permission.READ_PHONE_STATE”/>

- Việc truy xuất quản lý bởi lớp TelephonyManager với phương thức
getSystemService(). Ví dụ:
String srvcName = Context.TELEPHONY_SERVICE;
TelephonyManager telephonyManager =
(TelephonyManager)getSystemService(srvcName);
int phoneType = telephonyManager.getPhoneType();
switch (phoneType) {
case (TelephonyManager.PHONE_TYPE_CDMA): break;
case (TelephonyManager.PHONE_TYPE_GSM) : break;
case (TelephonyManager.PHONE_TYPE_NONE): break;
default: break;
}
String deviceId = telephonyManager.getDeviceId();

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 67


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

String softwareVersion = telephonyManager.getDeviceSoftwareVersion();


String phoneNumber = telephonyManager.getLine1Number();

- Quản lí trạng thái:


o Ví dụ:
class MyPhoneStateListener extends PhoneStateListener
{
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch(state)
{
case TelephonyManager.CALL_STATE_IDLE: break;
case TelephonyManager.CALL_STATE_RINGING: break;
case TelephonyManager.CALL_STATE_OFFHOOK: break;
default: break;
}
}
}

o Đọc dữ liệu kết nối và các thay đổi trạng thái thông qua các phương thức
getDataSet() và getDataActivity()

int dataActivity = telephonyManager.getDataActivity();


int dataState = telephonyManager.getDataState();
switch (dataActivity)
{
case TelephonyManager.DATA_ACTIVITY_INT : break;
case TelephonyManager.DATA_ACTIVITY_OUT : break;
case TelephonyManager.DATA_ACTIVITY_INOUT : break;
case TelephonyManager.DATA_ACTIVITY_NONE : break;
}

o Đọc các dữ liệu Network cần thiết:

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 68


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

String networkCountry = telephonyManager.getNetworkCountryIso();


String networkOperatorId = telephonyManager.getNetworkOperator();
String networkName = telephonyManager.getNetworkOperatorName();
int networkType = telephonyManager.getNetworkType();
switch (networkType) {
case (TelephonyManager.NETWORK_TYPE_1xRTT) : break;
case (TelephonyManager.NETWORK_TYPE_CDMA) : break;
case (TelephonyManager.NETWORK_TYPE_EDGE) : break;
case (TelephonyManager.NETWORK_TYPE_EVDO_0) : break;
case (TelephonyManager.NETWORK_TYPE_EVDO_A) : break;
case (TelephonyManager.NETWORK_TYPE_GPRS) : break;
case (TelephonyManager.NETWORK_TYPE_HSDPA) : break;
case (TelephonyManager.NETWORK_TYPE_HSPA) : break;
case (TelephonyManager.NETWORK_TYPE_HSUPA) : break;
case (TelephonyManager.NETWORK_TYPE_UMTS) : break;
case (TelephonyManager.NETWORK_TYPE_UNKNOWN) : break;
default: break;
}

o Đọc các dữ liệu SIM:


int simState = telephonyManager.getSimState();
switch (simState) {
case (TelephonyManager.SIM_STATE_ABSENT): break;
case (TelephonyManager.SIM_STATE_NETWORK_LOCKED): break;
case (TelephonyManager.SIM_STATE_PIN_REQUIRED): break;
case (TelephonyManager.SIM_STATE_PUK_REQUIRED): break;
case (TelephonyManager.SIM_STATE_UNKNOWN): break;
case (TelephonyManager.SIM_STATE_READY): {
String simCountry = telephonyManager.getSimCountryIso();
String simOperatorCode = telephonyManager.getSimOperator();
String simOperatorName =telephonyManager.getSimOperatorName();
String simSerial = telephonyManager.getSimSerialNumber();
break;
}
default: break;
}

o Các thay đổi trạng thái Phone được quản lý bởi lớp PhoneStateListener

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 69


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

PhoneStateListener phoneStateListener = new PhoneStateListener() {


public void onCallForwardingIndicatorChanged(boolean cfi) {}
public void onCallStateChanged(int state, String incomingNumber) {}
public void onCellLocationChanged(CellLocation location) {}
public void onDataActivity(int direction) {}
public void onDataConnectionStateChanged(int state) {}
public void onMessageWaitingIndicatorChanged(boolean mwi) {}
public void onServiceStateChanged(ServiceState serviceState) {}
public void onSignalStrengthChanged(int asu) {}
}

o Cần đăng ký với Telephony Manager để khởi tạo các sự kiện muốn lắng nghe
để xử lý:
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR|
PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_CELL_LOCATION |
PhoneStateListener.LISTEN_DATA_ACTIVITY |
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
PhoneStateListener.LISTEN_SERVICE_STATE |
PhoneStateListener.LISTEN_SIGNAL_STRENGTH);

o Hủy đăng ký bằng LISTEN_NONE


telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_NONE);

- Xây dựng ứng dụng thay thế ứng dụng cuộc gọi có sẵn trong ứng dụng. Bao gồm 2
bước:
o Chặn những Intent đến của ứng dụng Dialer và xử lý.
o Tổ chức quản lí các cuộc gọi ra bên ngoài.
- Cần đăng ký các Intent cho Activity xử lý:
o Intent.ACTION_CALL_BUTTON
o Intent.ACTION_DIAL

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 70


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Intent.ACTION_VIEW
- Ví dụ đăng kí trong Intent trong AndroidManifest
<activity
android:name= “.MyDialerActivity”
android:label =”@string/app_name”>
<intent-filter>
<action android:name = “android.intent.action.CALL_BUTTON”/>
<category android:name = “android.intent.category.DEFAULT”/
</intent-filter>
<intent-filter>
<action android:name = “android.intent.action.VIEW”/>
<action android:name = “android.intent.action.DIAL” />
<category android:name = “android.intent.category.DEFAULT” />
<category android:name = “android.intent.category.BROWSANLE” />
<data android:scheme = “tel” />
</intent-filter>
</activity>

- Ví dụ xử lý cuộc gọi tới


phoneStateListner callStateListener = new PhoneStateListner()
{
public void onCallStateChanged( int state, String incomingNumber)
{
}
};
telephonyManager.listen(callStateListener,
phoneStateListener.LISTEN_CALL_STATE;

2. SMS
- Gửi tin nhắn bằng cách tạo một Intent để gọi ứng dụng Message trong thiết bị.
- Ví dụ:
o Tạo tin nhắn SMS
Intent smsIntent = new Intent(Intent.ACTION_SENDTO,Uri.parse(“sms:123456”));
smsIntent.putExtra(“sms_body”, “Press send to send me”);
startActivity(smsIntent);

- Gửi tin nhắn MMS có chứa tập tin Media.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 71


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ:
//Tạo tin nhắn MMS
Uri attached_Uri = Uri.parse("content://media/external/images/media/1");
Intent mmsIntent = new Intent(Intent.ACTION_SEND,attached_Uri);
mmsIntent.putExtra("sms_body", "Please see the attached image");
mmsIntent.putExtra("address", "07912355432");
mmsIntent.putExtra(Intent.EXTRA_STREAM, attached_Uri);
mmsIntent.setType("image/png");
startActivity(mmsIntent);

- SMS tin nhắn được điều khiển bởi SmsManager


o Tạo đối tượng SmsManager
SmsManager smsManager = SmsManager.getDefault();

o Yêu cầu quyền truy cập khi gửi tin nhắn


<uses-permission android:name= “android.permission.SEND_SMS”/>

- Việc gửi tin nhắn được thực hiện bởi phương thức sendTextMessage của lớp
SmsManager
o Cú pháp:
sendTextMessage(Stringdestination Address,
String scAddress,
String text,
PendingIntent sentIntent,
PendingIntent deliveryIntent)

o Ví dụ:
String sendTo = “5551234”;
String myMessage = “Android supports programmatic SMS messaging!”;
smsManager.sendTextMessage(sendTo, null, myMessage, null, null);

- Theo dõi, xác nhận SMS tin nhắn đã được gửi bằng cách đăng ký BroadcastReceiver
để lắng nghe các hoạt động từ Pending Itent được tạo khi gửi tin nhắn.
o sentItent được gọi lên khi tin nhắn được gửi thành công hay lỗi.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 72


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

 Activity.RESULT_OK.
 SmsManager.RESULT_ERROR_GENERIC_FAILURE.
 SmsManager.RESULT_ERROR_RADIO_OFF.
 SmsManager.RESULT_ERROR_NULL_PDU.
o deliveryIntent được gọi lên một khi thiết bị đích nhận được tin nhắn.
- Ví dụ về kiểm soát gửi tin nhắn
o Tạo Pending Intent
String SENT_SMS_ACTION = "SENT_SMS_ACTION " ;
String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION " ;
Intent sentIntent = new Intent(SENT_SMS_ACTION);
PendingIntent sentPI = PendingIntent.getBroadcast(getApplicationContext(),0,
sentIntent,0);
Intent deliveryIntent = new Intent(DELIVERED_SMS_ACTION);
PendingIntent deliverPI =
PendingIntent.getBroadcast(getApplicationContext(),0, deliveryIntent,0);

o Tạo Broadcast Receiver cho Send_Action


registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context _context, Intent _intent){
switch (getResultCode()) {
case Activity.RESULT_OK: break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE: break;
case SmsManager.RESULT_ERROR_RADIO_OFF: break;
case SmsManager.RESULT_ERROR_NULL_PDU:break;
}
}
},
new IntentFilter(SENT_SMS_ACTION));

o Tạo Broadcast Receiver cho Delivery_Action


registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context _context, Intent _intent){
[ ... SMS delivered actions ... ]
}
},
new IntentFilter(DELIVERED_SMS_ACTION));
smsManager.sendTextMessage(sendTo, null, myMessage, sentPI, deliverPI);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 73


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Xử lý các tin nhắn dài hơn 160 ký tự bằng phương thức divideMessage() và
sendMultipartTextMessage().
o Cú pháp:
sendMultipartTextMessage(Stringdestination Address,
String scAddress,
ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents,
ArrayList<PendingIntent> deliveryIntents)

o Ví dụ:
ArrayList<String> messageArray = smsManager.divideMessage(myMessage);
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
for (int i = 0; i < messageArray.size(); i++)
sentIntents.add(sentPI);
smsManager.sendMultipartTextMessage(sendTo,null,messageArray, sentIntents,null);

- Gửi tin nhắn chứa dữ liệu bằng mảng byte


o Cú pháp:
sendDataMessage(Stringdestination Address, String scAddress,
short destination Port, byte[] data,
PendingIntent sentIntent,
PendingIntent deliveryIntent)

o Ví dụ:
Intent sentIntent = new Intent(SENT_SMS_ACTION);
PendingIntent sentPI =
PendingIntent.getBroadcast(getApplicationContext(),0,sentIntent,0);
short destinationPort = 80;
byte[] data = [... your data ... ];
smsManager.sendDataMessage(sendTo,null,destinationPort,data, sentPI,null);

- Để ứng dụng nhận được SMS, cần đăng ký:


o BroadcastReceiver với action

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 74


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

<receiver android:name="MySMSMonitor">
<intent-filter>
<action
android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>

o Cung cấp quyền truy cập nhận SMS tin nhắn


<uses-permission android:name= “android.permission.RECEIVE_SMS”/>

- Ví dụ tạo Broadcast Receiver để nhận tin nhắn


public class MySMSMonitor extends BroadcastReceiver
{
private static final String ACTION =
“android.provider.Telephony.SMS_RECEIVED”;
@Override
public void onReceive(Context context, Intent intent)
{
if(intent != null && intent.getAction() != null &&
ACTION.compareToIgnoreCase(intent.getAction()) == 0)
{
Object[] pduArray = (Objectp[] intent. getExtras(). get(“pdus”);
SmsMessage[] messages = new SmsMessage[pduArray.length];
for( int i = 0; i < pduArray.length; i++)
{
Messages[i] = SmsMessage.createFromPdu((byte[])pduArray[i]);
Log.d(“MySMSMonitor”, “From: ” + messages[i].
getOriginatingAddress());
Log.d(“MySMSMonitor”, “Msg: ” + messages[i].getMessageBody());
Log.d(“MySMSMonitor”, “SMS Message Received”);
}
}
}
}

- Làm việc với các thư mục tin nhắn, cần đăng ký quyền trong AndroidManifest.xml
<uses-permission android:name=”android.permission.READ_SMS”/>

- Thực hiện truy vấn để lấy ra các thông tin về tin nhắn trong các thư mục với URI
tương ứng:
o All: content://sms/all

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 75


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

o Inbox : content://sms/inbox
o Sent: content://sms/sent
o Draft: content://sms/draft
o Outbox: content://sms/outbox
o Failed : content://sms/failed
o Queued: content://sms/queued
o Undelivered: content://sms/undelivered
o Conversations: content://sms/conversations

- Ví dụ truy vấn lấy nội dung các tin nhắn trong Inbox.
public class SMSInboxDemo extends ListActivity{
private ListAdapter adapter;
private static final Uri SMS_INBOX = Uri.parse(“content://sms/inbox”);
@Override
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
Cursor c = getContentResolver().Query(SMS_INBOX,null,null,null, null);
startManagingCursor(c);
String[] colums = new String[] {“body”};
int[] names = new int[] {R.id.row};
adapter=new SimpleCursorAdapter(this,R.layout.sms_inbox,c,colums,names);
setListAdapter(adapter);
}
}

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 76


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 7
BỘ CẢM BIẾN

1. GIỚI THIỆU SƠ LƯỢC VỀ CẢM BIẾN


- Cảm biến là phần cứng được tích hợp trên các thiết bị, có tác dụng phản hồi lại các
hành động ở thế giới thực vào trong môi trường ứng dụng chạy trên thiết bị đó.
- Các hành động trong cảm biến được thực hiện một chiều và chúng chỉ cho phép thực
hiện các hành động mặc định sẵn (trừ NFC).
- GPS cũng là một bộ cảm biến nhưng không được tích hợp vào nền tảng cảm biến
trong Android.
- Các loại cảm biến có thể có trong một thiết bị:
o Light Sensor.
o Proximity Sensor.
o Temparature Sensor.
o Pressure Sensor.
o Gyroscope Sensor.
o Accelerometer Sensor.
o Magnetic Field Sensor.
o Orientation Sensor.
o Gravity Sensor (Android 2.3).
o Linear Accelerometer Sensor (Android 2.3).
o Rotation Vector Sensor (Android 2.3).
o Near Field Communication Sensor (Android 2.3).
- Có 2 cách để nhận biết thiết bị hổ trợ những loại cảm biến nào:
o Sử dụng đối tượng thuộc lớp SensorManager để thực hiện thao tác lấy về danh
sách các loại cảm biến trên thiết bị.
o Thiết lập trong tập tin AndroidManifest để chỉ định các tính năng thiết bị cần
có cho ứng dụng.
uses-feature android:name= “android.hardware.sensor.proximity”/>

- Ví dụ lấy thông tin cảm biến trên thiết bị thông qua SensorManager:
SensorManager mgr = (SensorManager)this.getSystemService(SENSOR_SERVICE);

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 77


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

List<Sensor> sensors = mgr.getSensorList(Sensor.TYPE_ALL);


StringBuilder message = new StringBuilder(2048);
message.append("The sensors on this device are:\n");
for(Sensor sensor : sensors) {
message.append(sensor.getName() + "\n");
message.append(" Type: " + sensorTypes.get(sensor.getType()) + "\n");
message.append(" Vendor: " + sensor.getVendor() + "\n");
message.append(" Version: " + sensor.getVersion() + "\n");
message.append(" Resolution: " + sensor.getResolution() + "\n");
message.append(" Max Range: " +
sensor.getMaximumRange() + "\n");
message.append(" Power: " + sensor.getPower() + " mA\n");
}
text.setText(message);

Hình 7.1

2. LẤY THÔNG TIN VÀ ĐIỀU KHIỂN CẢM BIẾN


- Cần đăng ký một bộ lắng nghe (Listener) sự thay đổi của cảm biến để thực hiện lấy
các thông tin.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 78


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Ví dụ: tạo lớp thực thi giao diện SensorEventListioner


public class MainActivity extends Activity implements SensorEventListener{
private SensorManager mfr;
private Sensor light;
private TextView text;
private StringBuilder msg = new StringBuilder(2048);

@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

mgr = (SensorManager) this.getSystemService(SENSOR_SERVICE);


light = mgr.getDefaultSensor(Sensor.TYPE_LIGHT);
text = (TextView) findviewById(R.id.text);
}
}

- Override các onResume và onPause để thực hiện các thiết lập trên cảm biến.
- Ví dụ: đăng ký và hủy đăng ký bộ lắng nghe
@Override
protected void onResume(){
mgr.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL);
super.onresume();
}
@Override
protected void onPause()
{
mgr.unregisterListener(this, light);
super.onPause();
}

- Trong phương thức registrerListener() ta thiết lập thông số để nắm bắt các giá trị thay
đổi của cảm biến.
o SENSOR_DELAY_NORMAL
o SENSOR_DELAY_UI
o SENSOR_DELAY_GAME
o SENSOR_DELAY_FASTEST

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 79


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

- Theo dõi các hoạt động của cảm biến


- Ví dụ: thực hiện callback 2 phương thức onAccuracyChanged() và
onSensorChanged().
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
msg.insert(0, sensor.getName() + “accuracy changed: “ + accuracy +
(accuracy + (accuracy==1?” (LOW)” : (accuracy == 2?” (MED)”: “(HIGH)”))
+ “\n”);
text.setText(msg);
text.invalidate();
}
public void onSensorChangeed(SensorEvent event)
{
msg.insert(0, “Got a sensor event: “ + event.values[0] + “SI lux
units\n”);
text.setText(msg);
text.invalidate();
}

- Một số vấn đề phát sinh khi sử dụng Cảm biến


o Phương thức onAccuracyChanged() sẽ được gọi lại mỗi khi một loại cảm biến
được sử dụng và được thiết lập thông số cao nhất.
o Khó truy cập trực tiếp đến các giá trị của của cảm biến theo thời gian cho
trước trừ khi thực hiện các phương thức API của driver cảm biến và thiết lập lại
giao diện (Interface) để sử dụng.
o Tốc độ truy xuất dữ liệu của cảm biến không đủ nhanh để đáp ứng trong một
số các tác vụ. Có thể tùy chỉnh trong các phương thức có sẵn của thư viện
thông qua cơ chế JNI.
o Android 2.1 không hổ trợ duy trì các cảm biến khi màn hình hiển thị tắt.

3. XỬ LÝ THÔNG TIN MỘT SỐ CẢM BIẾN


3.1. Accelerometer
- Cảm biến Gia tốc được sử dụng đế thu nhận các thay đổi hướng vật lí của thiết bị
trong không gian có mối tương quan với trọng lực và các lực tác dụng lên thiết bị.
- Đơn vị tính: m/s2

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 80


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 7.2
- Các thông số trên các trục x,y,z sẽ được tổng hợp và trả về duy nhất một giá trị
Rotation khi thiết bị thay đổi các trạng thái về phương hướng.

Hình 7.3
- Ví dụ sử dụng cảm biến gia tốc
SensorManager sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
Int sensorType = Sensor.TYPE_ACCELEROMATER;
Sm.registerListener(mySennorEventListener, sm.getDefaultSensor(sensorType),
SensorManager.SENSOR_DELAY_NORMAL);
final SennorEventListener mySennerEventListener = new SensorEventListener()
{
public void onSensorChanged(SensorEvent sensorEvent)
{
if(sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
float xAxis_lateralA = sensorEvent.values[0];
float yAxis_longitudinalA = sensorEvent.values[1];
float zAxis_verticalA = sensorEvent.values[2];
}
}
};

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 81


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

3.2. Near Field Communacation Sensor (NFC)


- NFC (Near Field Communacation) là một chuẩn giao tiếp giữa thiết bị di động với các
thẻ thông tin được gọi là NFC Tags hoặc với các thiết bị khác.
- Có 3 kiểu tiếp nhận dữ liệu bằng NFC:
o Tương tác với các thẻ tag cho việc nhận và ghi thông tin trên thiết bị di động.
o Thiết bị di động được xem như nơi để các thiết bị khác truy xuất thông tin.
o Hai thiết bị cùng trao đổi và tiếp nhận các thông tin của nhau.
- NFC cơ bản làm việc dữ liệu dạng NDEF (NFC Data Exchange Format) và sử dụng
hệ thống Tag Dispatch để phân biệt từng loại dữ liệu và khởi động ứng dụng tương
ứng.
- Hệ thống Tag Dispatch thực hiện theo cơ chế:
o Phân tích dữ liệu NDEF và chuyển dữ liệu sang kiểu MIME hoặc URI.
o Đóng gói dữ liệu MIME và URI vào Intent.
o Khởi động ứng dụng tương ứng với gói Intent.
- Dữ liệu NDEF được gói trong NdefMessage và chứa dạng các NdefRecord với các
trường dữ liệu sau:
o 3-bit TNF (Type Name Format ): trường chỉ định định dạng dữ liệu.
o Variable Length Type: kiểu độ dài dữ liệu.
o Variable Length ID: Id chỉ định record
o Variable Length Playload: dữ liệu của record.
- Cảm biến NFC được điều khiển bởi NFCAdapter để nhận các gói Intent:
NfcManager manager =
(NfcManager)context.getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter = manager.getDefaultAdapter();

- Cần thực hiện phương thức isEnable() để kiểm tra trạng thái của cảm biến NFC.
- Không có phương thức cho phép tắt mở NFC.
startActivityForResult( new Intent(
android.provider.Settings.ACTION_WIRELESS_SETTINGS), 0);

- Thứ tự ưu tiên xử lý các gói Intent được gửi tới thiết bị:
o ACTION_NDEF_DISCOVERED: intent được sử dụng để khởi chạy một Activity
trong ứng dụng có đăng ký xử lý gói intent này.
o ACTION_TECH_DISCOVERED: nếu không có Activity nào đăng ký việc xử lý gói
intent đến, hệ thống sẽ khởi động ứng dụng thích hợp.
o ACTION_TAG_DISCOVERED: hệ thống chuyển sang xử lý kiểu dữ liệu Tag thông
thường.

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 82


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Hình 7.4

- Cần đăng kí trong AndroidManifest để sử dụng NFC


<uses-permission android:name= “android.permission.NTFC”/>

- Lưu ý phiên bản của ứng dụng:


<uses-sdk android:minSdkVersion= “10” />

- Cho phép ứng dụng chỉ cài đặt trên các thiết bị có hỗ trợ NFC:
<uses-feature android:name= “android.hardware.nfc” android:required=“true”/>

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 83


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Mục lục

Bài 1: Khai thác tài nguyên Internet.................................................................................. 1

1. Tổng quan tài nguyên Internet ........................................................................................... 1

2. Sử dụng dịch vụ Download Manager ................................................................................ 5

Bài 2: Kết nối các dịch vụ Web thao tác với dữ liệu XML và JSON .............................. 10

1. Giới thiệu về các dịch vụ Web........................................................................................... 10

2. Các loại Webservice .......................................................................................................... 11

3. Xây dựng ứng dụng kết nối dịch vụ Web Restful ............................................................. 16

4. Đọc ghi dữ liệu XML......................................................................................................... 19

5. Đọc ghi dữ liệu JSON ........................................................................................................ 25

Bài 3: Google Map ............................................................................................................... 29

1. Google Play Service SDK ................................................................................................. 29

2. Google Maps Android API ................................................................................................ 30

Bài 4: Google Cloud Messaging .......................................................................................... 42

1. Giới thiệu ........................................................................................................................... 42

2. Cấu hình cho Google Cloud Messaging ............................................................................ 43

Bài 5: Các điều khiển đa truyền thông .............................................................................. 56

1. Media Player ...................................................................................................................... 56

2. Thu âm thanh và hình ảnh ................................................................................................. 59

3. Camera ............................................................................................................................... 62

Bài 6: Telephony & SMS ..................................................................................................... 67

1. Telephone........................................................................................................................... 67

2. SMS ................................................................................................................................... 71

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 84


Trung Tâm Tin Học Đại Học Khoa Học Tự Nhiên TP.HCM

Bài 7: Bộ cảm biến ............................................................................................................... 77

1. Giới thiệu sơ lược về cảm biến .......................................................................................... 77

2. Lấy thông tin và điều khiển cảm biến ................................................................................ 78

3. Xử lý thông tin một số cảm biến........................................................................................ 80

Tài liệu Lập trình thiết bị di động trên Android – Module 4 | 85

You might also like