android tutorial

152
MỤC LỤC MỤC LỤC..........................................................4 MỞ ĐẦU...........................................................7 Tại sao cần quan tâm tới nền tảng Android......................7 Đối tượng và phạm vi nghiên cứu của đề tài.....................8 PHẦN 1: NGHIÊN CỨU NỀN TẢNG ANDROID..............................9 CHƯƠNG 1. GIỚI THIỆU TỔNG QUAN VỀ MẠNG 3G VÀ XU THẾ THỊ TRƯỜNG. 9 1.1. Giới thiệu................................................ 9 1.2. Xu thế của thị trường di động............................13 CHƯƠNG 2. TỔNG QUAN VỀ ANDROID................................15 2.1. Android là gì ?.......................................... 15 2.2. Các chức năng chính của Android..........................15 2.3. Kiến trúc của Android....................................16 2.4. Cấu trúc một dự án Android...............................19 CHƯƠNG 3. CÁC THÀNH PHẦN TRONG ANDROID VÀ VIỆC TRUYỀN DỮ LIỆU. 23 3.1. Các kiến thức cơ bản về ứng dụng Android.................23 3.2. Cách sử dụng các thành phần Android......................24 3.3. File AndroidManifest.xml.................................25 3.4. Truyền dữ liệu giữa các Activity.........................26 CHƯƠNG 4. CẤU TRÚC GIAO DIỆN VÀ CÁC SỰ KIỆN TRONG ANDROID.. . . .29 4.1. Giao diện người dùng trong Android.......................29 4.2. Cách bố trí giao diện....................................30 4.3. Cách xử lý các sự kiện trên giao diện....................30 4.4. Đối tượng Toast..........................................32 CHƯƠNG 5. LISTVIEW VÀ MENU....................................34 5.1. Giới thiệu ListView......................................34 5.2. ListAdapter.............................................. 35 5.3. Menu..................................................... 38 1

Upload: huykenawp

Post on 07-Feb-2016

593 views

Category:

Documents


0 download

DESCRIPTION

For someone who need

TRANSCRIPT

Page 1: Android Tutorial

MỤC LỤC

MỤC LỤC.................................................................................................................................4

MỞ ĐẦU...................................................................................................................................7

Tại sao cần quan tâm tới nền tảng Android..........................................................................7

Đối tượng và phạm vi nghiên cứu của đề tài.........................................................................8

PHẦN 1: NGHIÊN CỨU NỀN TẢNG ANDROID...................................................................9

CHƯƠNG 1. GIỚI THIỆU TỔNG QUAN VỀ MẠNG 3G VÀ XU THẾ THỊ TRƯỜNG....9

1.1. Giới thiệu...................................................................................................................9

1.2. Xu thế của thị trường di động..................................................................................13

CHƯƠNG 2. TỔNG QUAN VỀ ANDROID.......................................................................15

2.1. Android là gì ?..........................................................................................................15

2.2. Các chức năng chính của Android...........................................................................15

2.3. Kiến trúc của Android.............................................................................................16

2.4. Cấu trúc một dự án Android....................................................................................19

CHƯƠNG 3. CÁC THÀNH PHẦN TRONG ANDROID VÀ VIỆC TRUYỀN DỮ LIỆU. 23

3.1. Các kiến thức cơ bản về ứng dụng Android.............................................................23

3.2. Cách sử dụng các thành phần Android....................................................................24

3.3. File AndroidManifest.xml........................................................................................25

3.4. Truyền dữ liệu giữa các Activity..............................................................................26

CHƯƠNG 4. CẤU TRÚC GIAO DIỆN VÀ CÁC SỰ KIỆN TRONG ANDROID.............29

4.1. Giao diện người dùng trong Android.......................................................................29

4.2. Cách bố trí giao diện................................................................................................30

4.3. Cách xử lý các sự kiện trên giao diện.......................................................................30

4.4. Đối tượng Toast........................................................................................................32

CHƯƠNG 5. LISTVIEW VÀ MENU.................................................................................34

5.1. Giới thiệu ListView..................................................................................................34

5.2. ListAdapter..............................................................................................................35

5.3. Menu........................................................................................................................38

CHƯƠNG 6. GỌI DỊCH VỤ WEB.....................................................................................41

6.1. Dịch vụ web..............................................................................................................41

6.1.1. Dịch vụ web là gì...............................................................................................41

1

Page 2: Android Tutorial

6.1.2. Đặc điểm...........................................................................................................43

6.2. Gọi dịch vụ web trong lập trình Android.................................................................44

6.2.1. Không sử dụng thư viện bên thứ ba..................................................................44

6.2.2. Sử dụng thư viện bên thứ ba:...........................................................................46

CHƯƠNG 7. SQLITE.........................................................................................................49

7.1. Tổng quan về SQLite................................................................................................49

7.1.1. Giới thiệu..........................................................................................................49

7.1.2. Những điều cần chú ý khi làm việc với SQLite :...............................................49

7.1.3. Kiểu dữ liệu:.....................................................................................................50

7.1.4. Câu lệnh SQL (sql statement)...........................................................................51

7.2. SQLite trong Android:.............................................................................................52

7.2.1. Tạo cơ sở dữ liệu :.............................................................................................53

7.2.2. Truy vấn và thao tác trong cơ sở dữ liệu..........................................................55

7.2.3. Transaction.......................................................................................................61

7.2.4. Lấy dữ liệu từ Cursor.......................................................................................62

7.3. Tạo cơ sỡ dữ liệu riêng và đưa vào ứng dụng Android............................................64

7.3.1. Tạo file cơ sở dữ liệu.........................................................................................64

7.3.2. Sao chép, sử dụng cơ sở dữ liệu có sẵn trong ứng dụng Android.....................65

CHƯƠNG 8. THREAD TRONG ANDROID.....................................................................69

8.1. UI thread..................................................................................................................69

8.2. Handler....................................................................................................................71

8.2.1. Sử dụng Messages.............................................................................................71

8.2.2. Sử dụng Runable..............................................................................................75

8.3. AsyncTask................................................................................................................77

8.3.1. Bốn bước được thực hiện trong AsyncTask......................................................78

8.3.2. Cách sử dụng....................................................................................................79

8.4. Một số chú ý khi làm việc với background thread...................................................83

Chương 9 LƯU TRỬ DỮ LIỆU........................................................................................84

9.1. Dùng Shared Preferences.........................................................................................84

9.2. Sử dụng file hệ thống ...............................................................................................87

9.2.1. Sử dụng bộ nhớ trong.......................................................................................87

9.2.2. Lưu trử vào file cache.......................................................................................90

2

Page 3: Android Tutorial

9.2.3. Đọc file từ resources..........................................................................................91

9.2.4. Sử dụng bộ nhớ ngoài.......................................................................................92

Chương 10 LOCATION VÀ MAP......................................................................................96

10.1. Map API...............................................................................................................96

10.1.1. Cách lấy một map-api key từ Google................................................................96

10.1.2. MapView và MapActivity.................................................................................99

10.1.3. Sử dụng Overlays............................................................................................102

10.2. Location base service..........................................................................................107

10.2.1. Dịch vụ LocationManager..............................................................................107

10.2.2. Geocoding với Android...................................................................................112

DANH MỤC TÀI LIỆU THAM KHẢO...............................................................................142

3

Page 4: Android Tutorial

MỞ ĐẦU

Tại sao cần quan tâm tới nền tảng Android

Hiện nay trên thế giới có rất nhiều các nền tảng lập trình di động khác nhau, bao

gồm Symbian, iPhone, Windows Mobile, BlackBerry, Java Mobile Edition, … Vậy

tại sao chúng ta lại cần quan tâm tới Android ?

Tuy sinh sau đẻ muộn nhưng Android là nền tảng đầu tiên đem lại những điều sau:

Một nền tảng hoàn toàn mở, tự do phát triển, dựa trên nhân Linux và mã

nguồn mở. Các nhà chế tạo thiết bị cầm tay và các nhà phát triển phần mềm

rất thích điều này vì họ có thể tự do tùy chỉnh lại nó và sử dụng nó mà không

phải trả thêm chi phí bản quyền.

Kiến trúc hệ thống dựa trên các thành phần rời rạc. Các lập trình viên có thể

thay thế hoàn toàn một thành phần trong nền tảng bằng một phiên bản cải

tiến khác của họ, điều này đem lại một xu hướng sáng tạo mới trong thế giới

lập trình di động.

Các dịch vụ mạnh mẽ được thiết kế bên trong: có thể kể đến các dịch vụ dựa

trên vị trí hiện tại của người dùng sử dụng GPS cho phép ta cung cấp cho

người dùng những trải nghiệm mới tùy vào nơi mà họ đang đứng, hoặc một

hệ thống cơ sở dữ liệu sử dụng SQL cho phép ta lưu trữ dữ liệu và đồng bộ

hóa chúng khi kết nối vào Internet.

Vòng đời của ứng dụng được kiểm soát tự động. Các ứng dụng được cô lập

lẫn nhau hoàn toàn bởi cơ chế bảo mật của Android. Điều này mang lại tính

ổn định mà chưa một nền tảng nào hiện nay làm được. Người dùng không

cần phải lo lắng xem ứng dụng nào đang chạy và ứng dụng nào cần phải tắt

để các ứng dụng khác có thể hoạt động. Android được tối ưu cho các thiết bị

có bộ nhớ thấp và ít năng lượng ở mức tốt nhất hiện nay.

Hình ảnh và âm thanh chất lượng cao. Nhanh, mượt, hình ảnh được khử

răng cưa cộng với khả năng tăng tốc cho đồ họa 3D bằng thư viện OpenGL

4

Page 5: Android Tutorial

cho phép nhiều loại ứng dụng doanh nghiệp và Game chạy được trên nền

tảng này.

Khả năng tương thích với nhiều loại phần cứng hiện nay và trong tương lai.

Tất cả các chương trình được viết bằng Java và được thực thi bởi máy ảo

Dalvik của Android, do đó mã nguồn của lập trình viên sẽ tương thích hoàn

toàn với các kiến trúc chip như ARM, x86, … Hỗ trợ một loạt các phương

pháp nhập liệu như dùng bàn phím, cảm ứng, trackball. Giao diện người

dùng có thể được tùy chỉnh theo độ phân giải và phương hướng của thiết bị.

Đối tượng và phạm vi nghiên cứu của đề tài

Nội dung của bài báo cáo gồm 2 phần:

Phần một, chúng ta đi vào tìm hiểu nền tảng Android và các kỹ thuật lập trình ứng

dụng trên Android. Nội dung xoay quanh các thành phần cơ bản giúp chúng ta có

thể tạo ra một phần mềm ứng dụng trên nền tảng Android.

Phần hai, báo cáo sẽ giới thiệu về ứng dụng minh họa đã được xây dựng trong quá

trình nghiên cứu và tìm hiểu nền tảng Android. Đây là ứng dụng mang tính thực

tiễn cao thông qua việc sử dụng các dịch vụ dựa vào vị trí người dùng.

5

Page 6: Android Tutorial

PHẦN 1: NGHIÊN CỨU NỀN TẢNG ANDROID

CHƯƠNG 1. GIỚI THIỆU TỔNG QUAN VỀ MẠNG 3G VÀ

XU THẾ THỊ TRƯỜNG.

1.1. Giới thiệu

3G, hay 3-G, (viết tắt của third-generation technology) là công nghệ truyền thông

thế hệ thứ ba, cho phép truyền cả dữ liệu thoại và dữ liệu ngoài thoại (tải dữ liệu,

gửi email, tin nhắn nhanh, hình ảnh...).

3G cung cấp cả hai hệ thống là chuyển mạch gói và chuyển mạch kênh. Hệ thống

3G yêu cầu một mạng truy cập radio hoàn toàn khác so với hệ thống 2G hiện nay.

Điểm mạnh của công nghệ này so với công nghệ 2G và 2.5G là cho phép truyền,

nhận các dữ liệu, âm thanh, hình ảnh chất lượng cao cho cả thuê bao cố định và thuê

bao đang di chuyển ở các tốc độ khác nhau. Với công nghệ 3G, các nhà cung cấp có

thể mang đến cho khách hàng các dịch vụ đa phương tiện, như âm nhạc chất lượng

cao; hình ảnh video chất lượng và truyền hình số; Các dịch vụ định vị toàn cầu

(GPS); E-mail;video streaming; High-ends games;...

6

Page 7: Android Tutorial

CDMA

GSM

TDMA

PHS (IP-Based)

64 Kbps

GPRS

115 Kbps

CDMA 1xRTT

144 Kbps

EDGE

384 Kbps

cdma20001X-EV-DV

Over 2.4 Mbps

W-CDMA (UMTS)

Up to 2 Mbps

2G2.5G

2.75G 3G

1992 - 2000+2001+

2003+

1G

1984 - 1996+

2003 - 2004+

TACS

NMT

AMPS

GSM/GPRS

(Overlay) 115 Kbps

9.6 Kbps

9.6 Kbps

14.4 Kbps/ 64 Kbps

9.6 Kbps

PDC

Analog Voice

Digital Voice

Packet Data

IntermediateMultimedia

Multimedia

PHS

TD-SCDMA

2 Mbps?

9.6 Kbps

iDEN

(Overlay)

iDEN

Source: U.S. Bancorp Piper Jaffray

Hình 1-1 Lịch sử phát triển của công nghệ truyền thông

2G Network Layout

Mobile Switching Center

NetworkManagement

(HLR)

Out to another MSC or Fixed Network (PSTN/ISDN)

2.5G/2.75G Network Layout

Mobile Switching Center

NetworkManagement

(HLR)

Out to another MSC or Fixed Network (PSTN/ISDN)

IP GatewayInternet(TCP/IP)

3G Network Layout

Mobile Switching Center

IP Gateway

Internet(TCP/IP)

IP Gateway

Internet(TCP/IP)

NetworkManagement

(HLR)

- Base Station - Radio Network Controller

Mobile Switching Center

NetworkManagement

(HLR)

Out to another MSC or Fixed Network (PSTN/ISDN)

Hình 1-2 Sơ đồ mạng 3G

7

Page 8: Android Tutorial

Các dịch vụ mạng 3G có thể mang lại:

Mobile Internet: duyệt Web, truyền tải file, email, truyền âm thanh, video,

dịch vụ thanh toán trên mạng.

Mobile Intranet / Extranet: cung cấp chức năng truy cập LAN, VPN.

Multimedia Message Service: gửi tin nhắn dạng MMS

Location based Service: cung cấp các thông tin, dịch vụ dựa vào vị trí của

người dùng.

Voice services: tăng cường chất lượng cuộc gọi với khả năng trình chiếu

hình ảnh.

Tại Việt Nam, lượng người sử dụng các dịch vụ 3G ngày càng đông, dưới đây là

thông số về lưu lượng sử dụng dữ liệu theo tháng.

Hình 1-3 Lưu lượng sử dụng dịch vụ 3G / tháng

8

Page 9: Android Tutorial

Hình 1-4 Các website / dịch vụ trên Internet được sử dụng trên thiết bị di động

Hình 1-5 Thống kê mục đích sử dụng dịch vụ 3G

9

Page 10: Android Tutorial

Theo khảo sát, các điện thoại thông minh (smart phone) đã tăng trưởng 142% ở Việt

Nam vào năm 2009. Nhu cầu dịch vụ 3G và các thiết bị di động hỗ trợ Internet ở

Việt Nam tăng theo từng ngày. Việt Nam đang trở thành một thị trường tiềm năng

cho các nhà cung cấp dịch vụ mạng, các thiết bị cầm tay và các dịch vụ giá trị gia

tăng dựa trên công nghệ 3G.

Theo ước tính của phân tích viên tạp chí ICT News, thị trường di động tại Việt Nam

sẽ vượt trên 620 triệu $ vào năm 2010.

Hình 1-6 Một số thiết bị di động hỗ trợ 2G / 3G

1.2. Xu thế của thị trường di động

Dưới đây là các xu hướng tương lai của ngành công nghiệp di động và dịch vụ

mạng theo khảo sát của CNET.

Trong cuộc chạy đua trên thị trường di động thông minh, iPhone của hãng Apple và

Android của Google sẽ chiếm giữ vị trị thống lĩnh. Đứng thứ 3 sẽ là BlackBerry,

sau đó sẽ tới Symbian và Windows Mobile.

10

Page 11: Android Tutorial

Tốc độ băng thông trên di động sẽ nhanh hơn, cao hơn để đáp ứng được nhiều dịch

vụ hơn. Điện thoại Internet và dịch vụ ngân hàng qua di động là 2 lĩnh vực sẽ hưởng

lợi nhiều nhất.

Các dịch vụ dựa trên vị trí sẽ được cá nhân hóa hơn. Các dịch vụ dựa vào hệ thống

định vị toàn cầu sẽ được đưa vào trong các ứng dụng, giúp chúng trở nên thông

minh hơn khi đưa ra các kết quả dựa vào vị trí hiện tại của người dùng.

Các dịch vụ mạng xã hội sẽ ngày càng đa dạng và chuyên biệt hóa. Twitter,

Facebook, Friendster, MySpace, v.v… sẽ trở nên thân thuộc với nhiều người. Người

dùng có thể chia sẻ nội dung của họ và nắm quyền quản lý tốt hơn về tính riêng tư,

cá nhân. Các yếu tố giải trí sẽ là chìa khóa giữ chân người dùng trong lĩnh vực này.

11

Page 12: Android Tutorial

CHƯƠNG 2. TỔNG QUAN VỀ ANDROID.

2.1. Android là gì ?

Android là một hệ điều hành dành cho thiết bị di động như điện thoại, máy tính

bảng và netbooks. Android được phát triển bởi Google, dựa trên nền tảng Linux

kernel và các phần mềm nguồn mở. Ban đầu nó được phát triển bởi Android Inc

(sau đó được Google mua lại) và gần đây nó trở thành một trong những phần mềm

đứng đầu của liên minh OHA (Open Handset Alliance - với khoảng 78 thành viên

bao gồm cả nhà sản xuất, nhà phát triển ứng dụng... cho thiết bị di dộng mà dẫn đầu

là Google). Andorid được phát triển nhằm cạnh tranh với các hệ điều hành di động

khác như iOS (Apple), BlackBerry OS, Windows Mobile (Microsoft), Symbian

(Nokia), Samsung (Bada), WebOS (Palm)... Theo thống kê trong quý II năm 2010

tại Mỹ, hệ điều hành Android chiếm thị phần 33% (cao nhất) trong tổng số các hệ

điều hành di động được bán ra, thứ 2 là BlackBerry OS 28% và iOS (Apple) xếp

thứ 3 với 22%.

Android có một cộng đồng phát triển ứng dụng rất lớn, hiện có khoảng hơn 70.000

ứng dụng có sẵn cho Android và đang liên tục được cập nhật. Ứng dụng được phát

triển bằng ngôn ngữ Java kết hợp với thư viện Java có sẵn của Google. Các nhà phát

triển ứng dụng có thể sử dụng máy tính chạy hệ điều hành Windows hoặc MacOS

hoặc Linux kết hợp với Android SDK để phát triển ứng dụng cho Android. Hệ điều

hành Android bao gồm 12.000.000 dòng mã trong đó có 3.000.000 dòng XML,

2.800.000 dòng C, 2.100.000 dòng Java, và 1.750.000 dòng C++.

Để phát triển phần mềm trên Android, các lập trình viên có thể tải về bộ công cụ

phát triển (Android SDK). Bộ công cụ bao gồm các công cụ và các API cần thiết, sử

dụng ngôn ngữ Java để lập trình.

2.2. Các chức năng chính của Android.

12

Page 13: Android Tutorial

Các chức năng mà Android cung cấp:

Android cung cấp framework ứng dụng cho phép việc tái sử dụng và thay thế

mã nguồn ở dạng component một cách dễ dàng.

Cung cấp máy ảo Dalvik được tối ưu cho các thiết bị di động.

Trình duyệt Web dựa trên engine mã nguồn mở Webkit.

Các tính năng đồ họa được tối ưu bởi một thư viện đồ họa 2D bên dưới; đối

với đồ họa 3D, Android sử dụng thư viện OpenGL ES 1.0 nếu thiết bị có hỗ

trợ.

Sử dụng SQLite để lưu trữ dữ liệu có cấu trúc.

Hỗ trợ các định dạng hình ảnh, âm thanh, video phổ biến như MPEG4,

H.264, MP3, AAC, AMR, JPG, PNG, GIF.

Hỗ trợ băng tầng GSM (tùy vào phần cứng thiết bị).

Hỗ trợ Bluetooth, EDGE, 3G, WiFi (tùy vào phần cứng thiết bị).

Ngoài ra còn có khả năng của các thiết bị như máy chụp ảnh, thiết bị định vị

toàn cầu, la bàn, và bộ cảm biến gia tốc.

Cung cấp môi trường phát triển phần mềm đầy đủ, bao gồm phần mềm giả

lập thiết bị, các công cụ gỡ rối (debugging), theo dõi bộ nhớ và năng suất

hoạt động, plugin cho Eclipse IDE.

2.3. Kiến trúc của Android

13

Page 14: Android Tutorial

Hình 2-7 Kiến trúc tổng quát của Android

Tầng ứng dụng – Applications:

Tầng ứng dụng của Android bao gồm các ứng dụng cốt lõi như:

Email client

Chương trình SMS

Lịch

Bản đồ

Trình duyệt

Danh bạ

Các ứng dụng khác.

Tầng Application Framework:

14

Page 15: Android Tutorial

Ở tầng này, các nhà phát triển ứng dụng có thể truy cập vào phần cứng thiết bị,

thông tin định vị vị trí, chạy các dịch vụ nền, đặt các cảnh báo, thông báo vào thanh

trạng thái, v.v…. và quan trọng nhất, đó là các API của framework.

Phía dưới tất cả các ứng dụng là một tập các dịch vụ hệ thống bao gồm:

Một tập các đối tượng View có thể được mở rộng để xây dựng một ứng

dụng, gồm có List, Grid, TextBox, Button, và WebBrowser.

Các đối tượng ContentProvider cho phép các ứng dụng truy cập vào dữ liệu

của các ứng dụng khác (chẳng hạn như truy cập danh bạ), hoặc để chia sẽ dữ

liệu với nhau.

Một trình quản lý tài nguyên, cho phép truy xuất các tài nguyên không phải

mã nguồn như các chuỗi đã được bản địa hóa, các tập tin đồ họa và giao

diện.

Trình quản lý thông báo cho phép tất cả các ứng dụng hiển thị các cảnh báo

lên thanh trạng thái.

Trình quản lý các đối tượng Activity dùng để quản lý vòng đời của các ứng

dụng cung cấp các chức năng điều hướng.

Tầng Libraries - Runtime

Tầng này cung cấp các thư viện media dựa trên thư viện PacketVideo’s

OpenCORE; các thư viện này hỗ trợ khả năng playback và thu lại nhiều định dạng

âm thanh, hình ảnh thông dụng như MPEG4, H.264, MP3, AAC, AMR, JPG, PNG.

Kèm theo đó là thư viện SQLite, một hệ quản trị cơ sở dữ liệu nhỏ nhẹ và mạnh mẽ

được cung cấp cho tất cả các ứng dụng.

Ở Runtime, Android cung cấp máy ảo Dalvik dùng để thực thi các file định dạng

Dalvik Executable (.dex) đã được tối ưu hóa cho các thiết bị có bộ nhớ nhỏ. Máy ảo

Dalvik chỉ chạy các class đã được đăng ký và được biên dịch bởi một trình biên

dịch Java đi kèm theo bộ SDK (dx tool). Ngoài ra Dalvik còn sử dụng nhân Linux

để quản lý các tính năng ở mức thấp và các tác vụ chạy theo luồng. Mọi ứng dụng

Android chạy trên một tiến trình riêng cùng với một instance riêng của máy ảo

15

Page 16: Android Tutorial

Dalvik. Dalvik đã được tối ưu sao cho một thiết bị có thể chạy nhiều mày ảo cùng

lúc một cách hiệu quả.

Tầng Linux kernel

Android được phát triển dựa trên các dịch vụ hệ thống cốt lõi của Linux phiên bản

2.6, bao gồm các module:

Security

Memory management

Process management

Network stack

Driver model

Tầng kernel hoạt động như một lớp trừu tượng giữa lớp phần cứng và phần mềm.

2.4. Cấu trúc một dự án Android

Khi tạo mới một dự án Android, bạn cần lưu ý tới các mục sau:

AndroidManifest.xml, là một file XML miêu tả ứng dụng được xây dựng và

các thành phần kèm theo như các Activities, các Services được cung cấp bởi

ứng dụng đó.

Thư mục libs/ chứa các thư viện Java ở dạng JAR của các hãng thứ 3 mà ứng

dụng cần để chạy.

Thư mục src/ chứa mã nguồn Java cho ứng dụng.

Thư mục res/ chứa các tài nguyên chẳng hạn như các biểu tượng, giao diện,

… được đóng gói kèm theo khi biên dịch ứng dụng.

Thư mục assets/ chứa các file tĩnh mà bạn muốn cài đặt lên hệ thống.

Các bước để tạo mới một dự án Android:

File > New > Android project, điền các thông số cần thiết.

16

Page 17: Android Tutorial

Hình 2-8 Cửa sổ tạo mọt dự án Android mới

Sửa đổi File giao diện được tạo sẵn: main.xml

17

Page 18: Android Tutorial

Hình 2-9 file main.xml có sẵn

Sửa file mã nguồn tương ứng:

Hình 2-10 File HelloAndroid.java

Chạy ứng dụng ở dạng Android Application

18

Page 19: Android Tutorial

Hình 2-11 Kết quả chạy chương trình HelloAndroid

Và như vậy, bạn đã viết được ứng dụng Android đầu tiên.

19

Page 20: Android Tutorial

CHƯƠNG 3. CÁC THÀNH PHẦN TRONG ANDROID VÀ

VIỆC TRUYỀN DỮ LIỆU.

3.1. Các kiến thức cơ bản về ứng dụng Android.

Các ứng dụng Android được viết bằng ngôn ngữ Java. Tất cả các đoạn code được

đóng gói lại thành một file .apk và được xem là một ứng dụng Android. Một file

apk được tạo ra bởi công cụ aapt đi kèm theo bộ SDK bao gồm:

Mã nguồn Java đã được biên dịch.

Dữ liệu của ứng dụng.

Các file tài nguyên.

Mỗi ứng dụng Android có một không gian hoạt động riêng. Mặc định, mọi ứng

dụng chạy trên một tiến trình Linux riêng. Android quản lý việc bắt đầu và kết thúc

một tiến trình khi nó không còn được dùng đến. Mỗi tiến trình có một máy ảo riêng,

do đó mã của ứng dụng chạy hoàn toàn cách biệt với tất cả các ứng dụng khác. Mặc

định, mỗi ứng dụng được gán cho một ID của người dùng duy nhất.

Điểm đặc biệt của một ứng dụng Android: không có một đầu vào duy nhất cho mọi

thứ trong ứng dụng ( không có hàm main() ) nhưng các thành phần cơ bản có thể

được hệ thống tạo ra và chạy khi cần thiết. Bốn thành phần chính của ứng dụng

Android là:

Activity.

Service.

Broadcast Receiver.

Content provider.

Activity là một cá thể, tập trung vào những việc mà người dùng có thể làm, chẳng

hạn như: liệt kê tất cả các mục cho người dùng chọn, hiển thị một nội dung cụ thể

20

Page 21: Android Tutorial

cho người dùng xem, Activity1 hiển thị danh sách các email, Activity2 hiện chi tiết

nội dung của email.

Mỗi activity được cài đặt thông qua việc kế thừa từ lớp cơ sở Activity. Activity đảm

nhiệm việc tạo ra cửa sổ để thiết lập giao diện người dùng thông qua phương thức

setContentView(View).

Service là thành phần không chứa giao diện người dùng, chạy ngầm trong hệ thống

trong một khoảng thời gian không xác định. Ví dụ: một Service chơi file nhạc ở

background, hoặc một service lấy dữ liệu qua mạng Internet hoặc thực hiện các tính

toán và cung cấp kết quả về cho các Activity cần nó. Mỗi service kế thừa từ lớp cơ

sở Service.

Content Provider là thành phần giúp chia sẻ một tập dữ liệu của ứng dụng tới các

ứng dụng khác. Dữ liệu có thể được lưu trên file hệ thống, trong cơ sở dữ liệu

SQLite, hoặc các các lưu trữ hợp lý khác. Để sử dụng, ta cần gọi các phương thức

từ đối tượng ContentResolver.

3.2. Cách sử dụng các thành phần Android.

ContentProvider được kích hoạt khi chúng nhận được yêu cầu từ ContentResolver.

Ba thành phần còn lại, bao gồm Activity, Service, BroadcastReceiver được kích

hoạt thông qua đối tượng Intent. Intent là đối tượng chứa nội dung của thông điệp

cần gửi tới các thành phần trong Android.

Một Activity được kích hoạt bằng cách truyền một đối tượng Intent vào các phương

thức sau:

Context.startActivity()

Activity.startActivityForResult()

21

Page 22: Android Tutorial

Activity được gọi có thể lấy được các dữ liệu kèm theo lời gọi bằng cách lấy đối

tượng Intent truyền vào thông qua method getIntent().

Một Activity thường bắt đầu một Activity khác. Nếu nó mong đợi kết quả trả về từ

Activity mà nó gọi, nó sẽ sử dụng phương thức startActivityForResult() thay vì

startActivity().

Lấy ví dụ: nếu một Activity gọi một Activity khác cho phép người dùng chọn một

tấm hình và chờ kết quả trả về là tấm hình được chọn. Kết quả trả về là một đối

tượng Intent kèm theo các dữ liệu cần thiết để lấy được tấm ảnh đó. Đối tượng

Intent này được lấy thông qua phương thức onActivityResult().

Một đối tượng Service được bắt đầu bằng cách truyền một đối tượng Intent vào

phương thức Context.startService(). Android gọi phương thức onStart() của Service

và truyền đối tượng Intent vào.

Các thành phần nên được tắt khi chúng không còn cần dùng đến nữa hoặc phải giải

phóng bộ nhớ cho các thành phần khác đang hoạt động. Một Activity có thể kết

thúc một Activity mà nó gọi thông qua phương thức startActivityForResult() bằng

phương thức finishActivity(). Một Service có thể được tắt bằng cách gọi chính

phương thức stopSelf() của nó hoặc bằng phương thức Context.stopService().

3.3. File AndroidManifest.xml.

Trước khi Android kích hoạt một thành phần ứng dụng nào đó, nó phải biết được sự

tồn tại của thành phần đó. Do đó các ứng dụng phải khai báo các thành phần mà

chúng có trong file manifest.

File Manifest là một file XML có cấu trúc và được đặt tên chung là

AndroidManifest.xml cho tất cả các ứng dụng.

Ví dụ:

22

Page 23: Android Tutorial

Hình 3-12 File Manifest của ứng dụng mShopping

3.4. Truyền dữ liệu giữa các Activity.

Để truyền dữ liệu giữa các Activity với nhau rất đơn giản, ta chỉ cần sử dụng đối

tượng Bundle và gán vào Intent để truyền vào hoặc trả về Intent đó.

Ví dụ:

23

Page 24: Android Tutorial

Hình 3-13 Ứng dụng minh họa việc truyền dữ liệu.

Truyền dữ liệu:

private View.OnClickListener mClickViewContactListener = new View.OnClickListener() {

@Override

public void onClick(View v) {

Intent iGetContactInfo = new Intent(getApplicationContext(), ViewContactInfoActivity.class);

Bundle bundle = new Bundle();

bundle.putString("nameKey", txtName.getText().toString());

bundle.putString("emailKey", txtEmail.getText().toString());

bundle.putString("projectKey", txtProject.getText().toString());

iGetContactInfo.putExtras(bundle);

startActivity(iGetContactInfo);

}

};

Nhận dữ liệu:

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.contactinfo);

txtNameValue = (TextView)findViewById(R.id.txtNameInfoValue);

txtEmailValue = (TextView)findViewById(R.id.txtEmailInfoValue);

txtProjectValue = (TextView)findViewById(R.id.txtProjectInfoValue);

24

Page 25: Android Tutorial

finishBtn = (Button)findViewById(R.id.btnFinish);

finishBtn.setOnClickListener(mClickFinishListener);

Bundle bundle = getIntent().getExtras();

String name = bundle.getString("nameKey");

String email = bundle.getString("emailKey");

String project = bundle.getString("projectKey");

txtNameValue.setText(name);

txtEmailValue.setText(email);

txtProjectValue.setText(project);

}

25

Page 26: Android Tutorial

CHƯƠNG 4. CẤU TRÚC GIAO DIỆN VÀ CÁC SỰ KIỆN

TRONG ANDROID.

4.1. Giao diện người dùng trong Android.

Trong ứng dụng Android, giao diện người dùng được xây dựng bằng các đối tượng

View và ViewGroup. View là đối tượng cơ sở của giao diện người dùng trên nền

tảng Android, lấy ví dụ như TextView hoặc Button. Đối tượng ViewGroup là lớp cơ

sở cho các cách bố cục giao diện khác nhau như LinearLayout, GridLayout,

TableLayout, …

Giao diện người dùng trong Android sử dụng hệ thống phân cấp gồm các View và

ViewGroup.

Hình 4-14 Hệ thống phân cấp View

Để gắn cây phân cấp View lên màn hình hiển thị, đối tượng Activity trước tiên phải

gọi phương thức setContentView() và truyền vào tham chiếu tới đối tượng đại diện

cho nút gốc của cây phân cấp.

26

Page 27: Android Tutorial

4.2. Cách bố trí giao diện.

Để bố trí giao diện trong Android, ta có thể sử dụng file XML để định nghĩa và thể

hiện các View.

Tất cả các tập tin định nghĩa giao diện nằm trong thư mục <Tên dự án>/res/layout

Ta có thể tạo giao diện và bố cục chúng bằng tập các tham số như android:id,

android:layout_width, android:layout_height, android:text, …

Ví dụ mã XML tạo 1 View bao gồm một TextView và 1 Button

Hình 4-15 Tạo giao diện bằng XML

4.3. Cách xử lý các sự kiện trên giao diện.

Một khi đã thêm các đối tượng View vào giao diện người dùng, người dùng sẽ

tương tác được với chúng. Để xử lý các sự kiện trên giao diện người dùng, chúng ta

cần phải làm một trong hai việc sau:

27

Page 28: Android Tutorial

Định nghĩa một đối tượng lắng nghe sự kiện và đăng ký nó với lớp View tương ứng.

Lớp View chứa một danh sách các lớp giao tiếp được đặt tên theo cấu trúc On<Sự

kiện>Listener, ví dụ: OnClickListener(). Các lớp giao tiếp này được gọi là event

listeners.

Viết mã ghi đè lên các phương thức có sẵn của đối tượng View, chẳng hạn như

onTouchEvent(). Phương pháp này được sử dụng khi chúng ta cần tự tạo ra lớp

View. Các đối tượng như vậy được gọi là event handlers.

Một số event listener thường sử dụng:

View.OnClickListerner, cài đặt phương thức onClick() để xử lý khi người

dùng nhấn vào các View.

View.OnKeyListener, cài đặt phương thức onKey() để xử lý các sự kiện khi

người dùng nhấn, thả một phím trên thiết bị.

View.OnTouchListener, cài đặt phương thức onTouch() để xử lý khi người

dùng thực hiện một hành động gây ra sự kiệm chạm.

Ví dụ minh họa:

28

Page 29: Android Tutorial

Hình 4-16 Ví dụ xử lý sự kiện onClick()

4.4. Đối tượng Toast.

Toast là một đối tượng được sử dụng để thể hiện những thông điệp thoáng qua trong

chốc lát. điều này có nghĩa là thông điệp này sẽ tự hiển thị và biến mất bất chấp tới

thao tác của người dùng.

Toast là cách tốt để tương tác với người dùng và sử dụng trong quá trình gỡ rối.

Để sử dụng, ta sử dụng các phương thức tĩnh của lớp Toast, ví dụ:

Toast.makeText(this, “successfully”, Toast.LENGTH_SHORT).show();

29

Page 30: Android Tutorial

Hình 4-17 Toast xuất hiện trên màn hình và biến mất sau 1 khoảng thời gian cho trước

30

Page 31: Android Tutorial

CHƯƠNG 5. LISTVIEW VÀ MENU.

5.1. Giới thiệu ListView.

ListView là một trong những widget quan trọng nhất trong Android vì nó được sử

dụng rất thường xuyên.

Hình 5-18 Một dạng ListView

ListView là một lớp kế thừa từ View, dùng để hiển thị các item trong một danh sách

cuộn dọc màn hình. Các item này được lấy ra từ một ListAdapter kết nối với

ListView.

31

Page 32: Android Tutorial

ListView thường đi kèm trong ListActivity vì nó có thể gắn kết các nguồn dữ liệu

vào ListView. Để sử dụng ListView, file layout phải chứa một đối tượng ListView

với thuộc tính id là “@android:id/list”

Một tập các hàng ngang sẽ tạo thành ListView. Mỗi hàng có thể được tạo ra bằng

cách chỉ định cụ thể file layout dành cho nó thông qua ListAdapter.

Hình 5-19 Tạo giao diện với ListView bằng XML

5.2. ListAdapter.

ListAdapter là cầu nối giữa ListView và các nguuồn dữ liệu. ListAdapter là một lớp

giao tiếp cài đặt từ Adapter. Để gắn kết dữ liệu với ListView, ta cần có đối tượng

cài đặt lớp giao tiếp ListAdapter này. Android cung cấp 2 ListAdapter chuẩn sau:

SimpleAdapter, sử dụng cho các loại dữ liệu tĩnh (chẳng hạn như Map).

SimpleCursorAdapter, sử dụng cho các đối tượng Cursor, kết quả của các

truy vấn.

32

Page 33: Android Tutorial

Class SimpleCursorAdapter là cách đơn giản để ánh xạ các cột dữ liệu từ đối tượng

Cursor sang các TextView hoặc ImageView được định nghĩa trong một file XML

qua các bước:

Đặc tả các cột dữ liệu.

Đặc tả các View dùng để hiển thị các cột dữ liệu.

Đặc tả file XML dùng để định nghĩa sự hiện diện của các đối tượng View.

Sử dụng hàm tạo: SimpleCursorAdapter(Context context, int layout, Cursor

c, String[] from, int[] to)

Để gắn kết dữ liệu danh bạ điện thoại từ ListAdapter vào ListView như hình dưới,

ta thực hiện các bước sau:

Hình 5-20 Ví dụ minh họa ListView

Tạo layout chính cho màn hình:

33

Page 34: Android Tutorial

Hình 5-21 main.xml

Tạo layout cho các hàng (các item trong ListView):

Hình 5-22 row.xml

Thực hiện gắn kết dữ liệu:

34

Page 35: Android Tutorial

Hình 5-23 Gắn kết dữ liệu vào ListView

5.3. Menu.

Menu là một thành phần quan trọng của một ứng dụng dùng để cung cấp một

phương pháp giao tiếp thân thiện cho người dùng truy cập vào các chức năng của

chương trình và các thiết lập.

Android cung cấp 3 loại menu cho ứng dụng:

Options Menu: loại menu chính của class Activity, xuất hiện khi người dùng bấm

vào nút menu trên điện thoại.

Context Menu: một danh sách các menu items hiện ra khi người dùng thực hiện

hành động nhấn giữ (long press) lên View.

Submenu: một danh sách các menu items hiện ra khi người dùng nhấn vào một

menu item trong Options Menu hoặc Context Menu.

Để cài đặt menu ta cần thực hiện 2 bước:

35

Page 36: Android Tutorial

Tạo ra menu thông qua Menu Resource bằng cách override phương thức

onCreateOptionsMenu(Menu menu). Phương thức này được gọi lần đầu tiên

khi Options Menu được mở.

Xử lý việc menu được chọn bằng cách override phương thức

onOptionsItemSelected(MenuItem item)

Hình 5-24 Options Menu

36

Page 37: Android Tutorial

Hình 5-25 menu.xml

Hình 5-26 Minh họa cài đặt menu

37

Page 38: Android Tutorial

CHƯƠNG 1.GỌI DỊCH VỤ WEB

Trong chương này chúng em không hướng dẫn chi tiết cách cài đặt một dịch vụ web

như thế nào sẻ giới thiệu về dịch vụ web, như là dịch vụ web là gì, đặc điểm của nó

như thế nào , …Và tiếp đó là cách gọi dịch vụ web trong lập trình với hệ điều hành

Android như thế nào như là : cách tạo yêu cầu (request) đến dịch vụ web, cách xữ lý

những đáp trả (response) của dịch vụ web có định dạng là XML hoặc là JSON.

6.1. Dịch vụ web

6.1.1. Dịch vụ web là gì

Hãy bắt đầu bằng cách xem xét toàn cảnh về các dịch vụ web thực sự là gì và tại sao

chúng lại quan trọng cho sự phát triển phần mềm.

Các ứng dụng truyền thống

Lúc bắt đầu, đã có các máy tính. Và nó đã hoạt động rất tốt. Các máy tính có vẻ đã

thực hiện các nhiệm vụ phi thường, tự động hoá rất nhiều thứ mà mọi người đã phải

làm bằng tay, bắt đầu với các tính toán phức tạp và chuyển sang tài chính và nhiều

nhiệm vụ khác.

Nhưng các ứng dụng truyền thống là "các tháp cao". Ứng dụng nguồn nhân lực có

thể không thực sự nói về ứng dụng tài chính, mà ứng dụng tài chính có thể không

thực sự nói về ứng dụng phân phối. Tất cả các ứng dụng này đã có nhà riêng của

mình, trên máy tính của riêng mình và trong khi chúng đã rất có ích, nhưng vẫn

chưa có một cách hay để chia sẻ dữ liệu giữa chúng. Bạn đã có tùy chọn để viết các

quy trình bó (batch) để chuyển dữ liệu từ một hệ thống này đến một hệ thống khác,

nhưng điều đó không thay thế cho việc tích hợp thời gian thực.

38

Page 39: Android Tutorial

Tính toán phân tán

Bước tiếp theo trong chuỗi tiến hóa của chúng ta là tính toán phân tán. Tính toán

phân tán đã cho phép các ứng dụng khác nhau nói chuyện với nhau, ngay cả khi

chúng không ở trên cùng một máy tính. Các công nghệ như CORBA, MTS và EJB

(Enterprise Java Beans), đã cung cấp một hệ thống bao gồm một đăng ký về các loại

để cho các ứng dụng có thể tìm thấy các thành phần mà chúng muốn tương tác và

sau đó gọi các thành phần này như thể chúng đang nằm trên máy cục bộ.

Các hệ thống này đã được phần mềm trung gian hỗ trợ, hoặc cụ thể hơn, phần mềm

trung gian hướng-thông báo, cung cấp cả hai yêu cầu này. Các ứng dụng bây giờ có

thể được xây dựng theo cách mà chúng có thể truy cập tài nguyên trên các hệ thống

khác, ngay cả khi chúng đang ở các vị trí địa lý khác nhau.

Nhưng vẫn còn có một vấn đề. Trong khi các ứng dụng tự do truyền thông bất cứ

nơi nào trong hệ thống, thì hệ thống vẫn còn là hệ thống khép kín. Ít nhất, ứng dụng

khách của bạn đã phải sử dụng cùng một công nghệ như là ứng dụng máy chủ.

Ngoài ra, các hệ thống không được thiết kế, theo một quy tắc, để truy cập từ bên

ngoài tổ chức riêng lẻ đã tạo ra chúng

Các dịch vụ web

Tiếp theo, liên kết hầu như không tránh khỏi trong chuỗi tiến hóa này là các dịch vụ

web. dịch vụ web có thể dựa trên các thông báo SOAP hoặc dựa trên REST .Sử

dụng XML hoặc JSON, trong nhiều trường hợp, trên HTTP, "các dịch vụ web" vẫn

còn có nghĩa là nhiều thứ cho nhiều người. XML và JSON, là những tiêu chuẩn mã

nguồn mở dựa trên văn bản, bất cứ ai có thể truy cập được từ bất kỳ ứng dụng nào

(ứng dụng bất kỳ là ứng dụng được thiết kế để chấp nhận nó). Điều này mở rộng thế

giới cho ứng dụng của bạn để bao gồm bất cứ ai có thể tiếp cận nó trên mạng của

bạn.

Một loại dịch vụ web khác liên quan đến việc sử dụng một chuẩn như XML-RPC.

Trong trường hợp này, các lệnh được gửi đến một hệ thống thông qua XML.

39

Page 40: Android Tutorial

Hình 6-27 Ví dụ về ứng dụng gọi dịch vụ web dựa trên SOAP

6.1.2. Đặc điểm

Dịch vụ web cho phép client và server tương tác được với nhau ngay cả

trong những môi trường khác nhau.

Phần lớn kĩ thuật của dịch vụ web được xây dựng dựa trên mã nguồn mở

và được phát triển từ các chuẩn đã được công nhận, ví dụ như XML,

JSON…

Một dịch vụ web bao gồm có nhiều mô-đun và có thể công bố lên mạng

Internet.

Các client và dịch vụ web đều không cần biết cài đặt của nhau. Một ứng

dụng khi được triển khai sẻ hoạt động theo mô hình client-server. Nó có

thể được triển khai bởi một phần mềm ứng dụng phía server ví dụ như

Microsoft.Net, java , PHP…

40

Page 41: Android Tutorial

Ưu điểm :

- Dịch vụ web cung cấp khả năng hoạt động rộng lớn với các ứng dụng

phần mềm khác nhau chạy trên những nền tảng khác nhau.

- Sử dụng các giao thức và chuẩn mở. Giao thức và định dạng dữ liệu

dựa trên văn bản (text), giúp các lập trình viên dễ dàng hiểu được.

- Nâng cao khả năng tái sử dụng.

Thúc đẩy đầu tư các hệ thống phần mềm đã tồn tại bằng cách cho

phép các tiến trình/chức năng nghiệp vụ đóng gói trong giao diện

dịch vụ web .

- dễ dàng cho việc phát triển các ứng dụng phân tán.

- Thúc đẩy hệ thống tích hợp, giảm sự phức tạp của hệ thống, hạ giá

thành hoạt động, phát triển hệ thống nhanh và tương tác hiệu quả với

hệ thống của các doanh nghiệp khác.

Nhược điểm :

- Những thiệt hại lớn sẻ xảy ra vào khoảng thời gian chết của dịch vụ

web , giao diện không thay đổi, có thể lỗi nếu một máy khách không

được nâng cấp, thiếu các giao thức cho việc vận hành.

- Có quá nhiều chuẩn cho dịch vụ web khiến người dùng khó nắm bắt.

- Phải quan tâm nhiều hơn đến vấn đề an toàn và bảo mật.

Dịch vụ web sẻ đáp ứng (response ) cho chúng ta cái gì ?

Khi nhận được một lời gọi, dịch vụ web sẻ thực hiện yêu cầu mà nó nhận được, tùy

cài đặt, có thể là update, delete, … Nhưng khi được yêu cầu phải đáp trả lại thông

tin thì nó sẻ trả về một tài liệu XML hoặc là một tài liệu JSON (có thể là một SOAP

message, RSS, Atom , …)

6.2. Gọi dịch vụ web trong lập trình Android

6.2.1. Không sử dụng thư viện bên thứ ba

41

Page 42: Android Tutorial

Trong Android không có thư viện về SOAP để hổ trợ cho dịch vụ web. Tuy nhiên,

nó có sẵn các thư viện cho việc kết nối qua giao thức HTTP, củng như hổ trợ việc

phân tích (parse) tài liệu XML , và tài liệu JSON. Để phân tích tài liệu XML chúng

ta có thể sử dụng SAX, DOM, với JSON thì ta có thể dùng JSONObject.

Vì các thiết bị di động có tài nguyên hạn chế , nên việc chúng ta tự phân tích tài liệu

XML hoặc JSON bằng giải thuật riêng, thì có thể hổ trợ việc tối ưu bộ nhớ củng

như các yêu cầu khác. Tuy nhiên hiện nay các thư viện third party củng đã được xây

dựng rất nhiều hổ trợ cho việc phân tích , gọi dịch vụ web , ví dụ như : KSoap2,

Axis2, GSON, … Để gọi một dịch vụ web ta cần làm theo từng bước sau :

Với dịch vụ web sử dụng SOAP :

Tạo một kết nối HTTP tới dịch vụ web, thường sử dụng lớp

java.net.HttpURLConnection.

Tạo một yêu cầu SOAP (SOAP request).

Mở một ouput stream từ kết nối HTTP ban đầu. Ghi SOAP request vào stream đó.

Bước tiếp theo là mở một input stream từ kết nối HTTP ban đầu và nhận chuổi đáp

trả của dịch vụ web. Chuổi đó chính là một SOAP response.

Bước tiếp theo là chúng ta sử dụng SAX hoặc DOM để phân tích dữ liệu XML nhận

được từ SOAP response.

Với dịch vụ web sử dụng REST :

Tạo một HTTP request có thể sử dụng một trong các phương thức GET, POST,

PUT, DELETE của HTTP. Thường dùng lớp con của interface :

HttpUriRequest(HttpGet, HttpPost, ..) trong gói

org.apache.http.client.methods.HttpUriRequest.

Tạo kết nối tới nhà cung cấp dịch vụ web. Mở một input stream từ kết nối để lấy

đáp trả từ dịch vụ web.

42

Page 43: Android Tutorial

Phân tích tài liệu XML hoặc tài liệu JSON từ đáp trả của dịch vụ web.

Để thao tác với XML chúng ta có thể sử dụng các package sau :

org.w3c.dom : phân tích bằng DOM

org.xml.sax : phân tích bằng SAX

org.xmlpull : dùng XMLPULL V1 API

Để thao tác với JSON ta dùng lớp căn bản như org.json.JSONArray,

org.json.JSONObject.

6.2.2. Sử dụng thư viện bên thứ ba:

Ksoap2 :

Với những dịch vụ web sử dụng SOAP chúng ta có thể sử dụng thư viện KSoap2.

Đây là một thư viện được xem là khá nhẹ và hiệu quả, đang được sử dụng rất nhiều

hiện nay.

Để sử dụng KSoap2 trước hết phải download thư viện Ksoap2 từ liên kết :

http://code.google.com/p/ksoap2-android/

Sau khi add thư viện vào project. Để sử dụng ta phải sử dụng các thư viện :

org.ksoap2.SoapEnvelope;

org.ksoap2.serialization.SoapObject;

org.ksoap2.serialization.SoapSerializationEnvelope;

org.ksoap2.transport.HttpTransportSE;

Tạo một yêu cầu SoapObject (SoapObject requet).

43

Page 44: Android Tutorial

Tạo một đôi tượng SoapSerializationEnvelope từ SoapRequest đó.

Tạo một đối tượng của lớp HttpTransportSE từ đối tượng

SoapSerializationEnvelope ở trên.

Từ đối tượng của lớp HttpTransportSE, gọi method “call() “ để gọi dịch vụ web.

Sau khi thực hiện lời gọi dịch vụ web. Chúng ta sẻ nhận về một đối tượng

SoapObject là đáp trả từ dịch vụ web. Từ đối tượng này ta sẻ lấy được những dữ

liệu cần thiết mà dịch vụ web đáp trả.

Ví dụ sử dụng Ksoap2

Dưới đây là một ví dụ sử dụng thư viện KSoap2 để thực hiện lời gọi dịch vụ web

được triển khai bằng .Net.

private static final String SOAP_ACTION =

"http://tempuri.org/IXDTService/GetTop100ThiSinhDetailsByMaTruong";

private static final String METHOD_NAME =

"GetTop100ThiSinhDetailsByMaTruong";

private static final String NAMESPACE = "http://tempuri.org/";

private static final String URL = "http://10.0.2.2:3744/XemDiemThiService.svc";

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

request.addProperty("maTruong",mt);

SoapSerializationEnvelope envelope = new

SoapSerializationEnvelope(SoapEnvelope.VER11);

envelope.dotNet = true;

envelope.setOutputSoapObject(request);

HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

androidHttpTransport.call(SOAP_ACTION, envelope);

44

Page 45: Android Tutorial

SoapObject result=(SoapObject)envelope.getResponse();

SoapObject thisinh = (SoapObject) result.getProperty(i);

String name = thisinh.getProperty("HoTen").toString();

String sbd = thisinh.getProperty("SoBaoDanh").toString();

45

Page 46: Android Tutorial

CHƯƠNG 2.SQLITE

6.1. Tổng quan về SQLite

6.1.1. Giới thiệu

SQLite là phần mềm quản lý cơ sở dữ liệu (DBMS) với đặc điểm gọn, nhẹ. Được

nhúng sẵn trong hệ điều hành Android, không cần cài đặt, không cần cấu hình hay

khởi động mà có thể sử dụng ngay. SQLite hổ trợ những chức năng của cơ sỡ dữ

liệu quan hệ giống như cú pháp của SQL. Dữ liệu database cũng được lưu ở một file

duy nhất. Không có khái niệm user, password hay quyền hạn trong SQLite

database. SQLite được phát triển bởi Richard Hipp và được tài trợ bởi Adobe,

Oracle, Bloomberg, Mozilla với website chính thức http://www.sqlite.org. Chính vì

sự ra đời sau các đàn anh lớn như Microsoft SQL server, Oracle, MySQL . . . .

SQlite có cấu trúc câu lệnh tương tự như các hệ quản trị trước nó và website của

SQlite có một cách hướng dẫn sữ dụng khá sơ sài. Cũng chính vì thế sẻ có một khó

khăn cho người sữ dụng nếu như họ chưa hề sữ dụng các hệ quản trị đó(hệ quản trị

lớn).

SQLite rất gọn nhẹ, toàn bộ hệ quản trị chưa đến 400KB, và sữ dụng rất ít bộ nhớ

trong. Nên nó là một lựa chọn hoàn hỏa cho việc quản lý cơ sỡ dữ liệu trên điện

thoại di động. Như là Android, IphoneOS.

6.1.2. Những điều cần chú ý khi làm việc với SQLite :

Trong SQLite không có ràng buộc kiểu dữ liệu. Bạn có thể đặt một giá trị

của kiểu dữ liệu này vào một cột (column) có kiểu dữ liệu khác. Ví dụ như

bỏ một chuổi vào một cột số nguyên.

46

Page 47: Android Tutorial

Nếu ban xây dựng ứng dụng với Android 2.2 trở lên thì có thể sử dụng khóa

ngoại trong SQLite. Vì lúc này Android sử dụng SQLite 3.6.22. Các phiên

bản SQLite trước 3.6.19 không hổ trợ khóa ngoại trong SQLite.

SQLite không hổ trợ Unicode mặc định.

6.1.3. Kiểu dữ liệu:

Các nhóm kiểu dữ liệu trong SQlite:

TEXT: dữ liệu dạng chuỗi, bao gồm:

- CHARACTER(20)

- VARCHAR(255)

- VARYING CHARACTER(255)

- NCHAR(55)

- NATIVE CHARACTER(70)

- NVARCHAR(100)

- TEXT

- CLOB

INTEGER: dữ liệu số nguyên, bao gồm:

- INT

- INTEGER

- TINYINT

- SMALLINT

- MEDIUMINT

- BIGINT

- UNSIGNED BIG INT

- INT2

- INT8

47

Page 48: Android Tutorial

NUMERIC: dữ liệu số nói chung, bao gồm:

- NUMERIC

- DECIMAL(10,5)

- BOOLEAN

- DATE

- DATETIME

REAL: kiếu số thực, bao gồm:

- REAL

- DOUBLE

- DOUBLE PRECISION

- FLOAT

NONE: không xác đinh kiểu, bao gồm: BLOB

6.1.4. Câu lệnh SQL (sql statement).

Câu lệnh của SQLite hoàn toàn tương tự với ngôn ngữ sql.

Tạo bảng :

create table <tên bảng>(

cột 1 <kiểu dữ liệu>,

cột 2 <kiểu dữ liệu>,

cột 3 <kiểu dữ liệu>,

. . . . . . .

);

Thêm một dòng mới

48

Page 49: Android Tutorial

insert into <tên bảng> [(các cột)] values(<các gia trị>);

Xóa dữ liệu

Delete from <tên bảng> [where điều liện];

Cập nhật

Update <tên bảng> set <tên cột>=<giá trị>[,<tên cột>=<giá trị>, . . ]

[where diều kiện];

6.2. SQLite trong Android:

Android cung cấp một thư viện được xây dựng bằng ngôn ngữ C để truy cập đến cơ

sở dữ liệu SQLite nhằm đảm bảo tốc độ và giảm tối đa việc sử dụng tài nguyên.

Nhưng thư viện này đã được bao bằng những lớp java (API) ở mức cao hơn. Để

hiểu rõ hơn ta có thể xem hình 7- 1 sau :

Hình 7-28 Android SDK software stack

49

Page 50: Android Tutorial

Ta có thể thấy SQLite nằm trong Native libraries. Cần nói thêm, Native libraries là

những thư viện được xây dựng bằng những ngôn ngữ khác (phần lớn là C/ C++),

không phải là java. Và những thư viện này thường được bao bởi các lớp java(API).

Trong phần lớn trường hợp chúng ta chỉ cần thao tác với các lớp java và không cần

quan tâm đến các mức sâu hơn.

Trong hệ điều hành Android, SQLite chạy như là một dịch vụ của hệ điều hành, chứ

không giống với một hệ quản trị cơ sở dữ liệu như SQL server hoặc MySQL. Một

cơ sở dữ liệu của ứng dụng nào thì chỉ có ứng dụng đó truy cập. Nếu muốn chia sẻ

dữ liệu với những ứng dụng khác, thì chúng ta có thể sử dụng Content Provider.

Nếu ứng dụng của bạn tạo cơ sở dữ liệu, thì nó sẻ được lưu theo đường dẫn :

"DATA/data/APP_NAME/databases/FILENAME". "DATA".

APP_NAME : là tên ứng dụng.

FILENAME : là tên cơ sở dữ liệu của ứng dụng.

Khi bạn muốn copy cơ sở dữ liệu từ máy này sang máy khác, bạn chỉ cần copy file

trên, và đặt vào đúng đường dẫn.

6.1.1. Tạo cơ sở dữ liệu :

Để tạo hoặc upgrade một cơ sở dữ liệu trong ứng dụng Android, chúng ta thường

thừa kế lớp SQLiteOpenHelper, lớp này nằm trong gói android.database. Sau đó

chúng ta override các phương thức onCreate() và onUpgrade() :

onCreate() : Được gọi khi database được tao ra .Trong phương thức này

chúng ta tạo table, trigger, view.

onUpgrade() để upgrade cơ sở dữ liệu trong trường hợp chúng ta cần thay

đổi mô hình cơ sở dữ liệu. Như là alter table, drop table, tạo mới table.

50

Page 51: Android Tutorial

Cả hai phương thức này đều có đối số là một đối tượng của lớp “SQLiteDatabase”.

SQLiteOpenHelper cung cấp phương thức “getReadableDatabase()” và

“getWriteableDatabase()” để truy cập đến một đối tượng của lớp “SQLiteDatabase”

, đây là đối trượng cho phép truy cập vào cơ sở dữ liệu với chế độ đọc hoặc ghi.

Trong cơ sở dữ liệu, bạn cần đặt tên khóa chính luôn là “_id”.

Dưới đây là một ví dụ với lớp DBHelper thừa kế từ lớp SQLiteOpenHelper.

package com.example.sqlite;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

import android.util.Log;

public class DBHelper extends SQLiteOpenHelper{

private static final String DATABASE_NAME = "applicationdata";

private static final int DATABASE_VERSION = 1;

private static final String DATABASE_CREATE = "create table todo (_id

integer primary key autoincrement, "

+ "category text not null, summary text not null, description text not

null);";

public DBHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION);

51

Page 52: Android Tutorial

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(DATABASE_CREATE);

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

{

Log.w(DBHelper.class.getName(),

"Upgrading database from version " + oldVersion + " to

"

+ newVersion + ", which will destroy all

old data");

db.execSQL("DROP TABLE IF EXISTS todo");

onCreate(db);

}

}

Cần lưu ý, phương thức onCreate() chỉ được một lần, khi database chưa được tạo ra.

Những lần sau chạy ứng dụng thì phương thức này không được gọi lại nữa.

6.1.2. Truy vấn và thao tác trong cơ sở dữ liệu.

52

Page 53: Android Tutorial

Để truy vấn và thao tác trong cơ sở dữ liệu, chúng ta sử dụng lớp SQLiteDatabase

và giao diện Cursor. Cả hai đều nằm trong gói android.database.

“SQLiteDatabase” là class cung cấp các phương thức quan trọng trong việc quản lý

cơ sở dữ liệu như create, delete, thực thi các câu lệnh SQL, .. . Một vài phương thức

cụ thể như :

insert() : để thêm một hàng vào table.

update() : thay đổi giá trị của một hàng.

delete() : xóa một hoặc nhiều hàng trong table

execSQL() : thực thi câu lệnh sql không trả về dữ liệu (không phải là

SELECT).

query() , rawQuery() : để thực thi truy vấn cơ sở dữ liệu.

Phương thức “rawQuery()” sử dụng những câu truy vấn SQL còn “query()” cung

cấp một giao diện trong việc truy vấn động, ví dụ như là chúng ta chưa biết cần phải

truy vấn những cột nào. Cả hai phương thức này đều trả về một đối tượng Cursor.

Đây là một ví dụ về sử dụng rawQuery():

Cursor getAllDepts()

{

SQLiteDatabase db=this.getReadableDatabase();

Cursor cur=db.rawQuery("SELECT _id, colDeptName from

deptTable” ,new String [] {});

return cur;

}

Phương thức “query()” có những các đối số quan trọng sau :

String table : Tên của table được dùng để truy vấn.

53

Page 54: Android Tutorial

int[] columnNames : Mảng tên của những cột mà chúng ta muốn truy vấn từ

bảng.

String whereClause : có thể đặt null nếu không sử dụng where trong câu truy

vấn. Có thể đặt các đối số trong where là “?”. Ví dụ như “_id = ?, HoTen

= ?”. Và các đối số cần đặt trong mảng valuesForWhereClause.

String[] valuesForWhereClause : Mảng chứa các giá trị thay thế cho “?”

trong whereClause. Có thể đặt null.

String groupBy : chuổi string , GROUP BY những cột nào. Có thể đặt null.

String having : tương tự với whereClause, having theo điều kiện nào. Có thể

đặt null.

String orderBy : sắp xếp theo kiểu nào. Có thể đặt null.

Cursor là một giao diện. Đại diện cho kết quả của một truy vấn vào cơ sở dữ liệu.

Nó cung cấp các phương thức cho chúng ta đọc hoặc viết ngẩu nhiên từ kết quả của

truy vấn dữ liệu. Khi sử dụng Cursor cần chú ý là nó không có đồng bộ hóa, nên khi

xữ lý với nhiều thread chúng ta cần chú ý thực thi đồng bộ hóa khi sử dụng đối

tượng của Cursor. Ngoài ra trong khi truy vấn , nếu tên của khóa chính của bạn

không phải là _id thì chúng ta phải đặt alias cho nó là _id, vì Cursor luôn yêu cầu

khóa chính là _id. Ví dụ như :

SELECT [Column Name] as _id.

Ngoài ra, để thêm vào hoặc thay đổi một hàng trong table, chúng ta sử dụng lớp

android.content.ContentValues. Ví dụ sử dụng ContentValues:

ContentValues values = new ContentValues();

values.put(KEY_CATEGORY, category);

values.put(KEY_SUMMARY, summary);

54

Page 55: Android Tutorial

values.put(KEY_DESCRIPTION, description);

Lớp này cho phép chúng ta chứa một tập những khóa / giá trị. Chúng ta sử dụng tên

của cột trong table để làm khóa. Sau khi tao ra , thêm vào những giá trị cần thiết cho

một hàng, sử dụng phương thức insert(), hoặc update của một đối tượng

SQLiteDatabase để thêm vào hoặc update trong cơ sở dữ liệu.

Dưới đây là một ví dụ truy vấn cơ sở dữ liệu. Đây là một adapter của lớp DBHelper

trong ví dụ trên :

package com.example.sqlite;

import android.content.ContentValues;

import android.content.Context;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.util.Log;

public class SQLAdapter {

// Database fields

public static final String KEY_ROWID = "_id";

public static final String KEY_CATEGORY = "category";

public static final String KEY_SUMMARY = "summary";

public static final String KEY_DESCRIPTION = "description";

private static final String DATABASE_TABLE = "todo";

private Context context;

private DBHelper dbHelper;

private SQLiteDatabase db;

55

Page 56: Android Tutorial

public SQLAdapter(Context context) {

this.context = context;

}

public synchronized SQLAdapter open() {

if (dbHelper == null) {

dbHelper = new DBHelper(context);

Log.v("Minh", "call DBHelper constructer");

}

db = dbHelper.getWritableDatabase();

return this;

}

public void close() {

dbHelper.close();

}

public long insertTodo(String category, String summary, String description)

{

ContentValues value = createContentValues(category, summary,

description);

return db.insert(DATABASE_TABLE, null, value);

}

public boolean updateTodo(long rowId, String category, String summary,

String description) {

ContentValues updateValues = createContentValues(category,

summary,

56

Page 57: Android Tutorial

description);

return db.update(DATABASE_TABLE, updateValues,

KEY_ROWID + "=" + rowId,

null) > 0;

}

public Cursor fetchAllTodos() {

return db.query(DATABASE_TABLE, new String[]

{ KEY_CATEGORY,

KEY_SUMMARY, KEY_DESCRIPTION }, null, null,

null, null, null);

}

public Cursor fetchTodo(long rowID) {

Cursor cursor = db.query(true, DATABASE_TABLE, new String[]

{ KEY_CATEGORY, KEY_SUMMARY, KEY_DESCRIPTION }, KEY_ROWID

+ " = " + rowID, null, null, null, null, null);

if(cursor != null){

cursor.moveToFirst();

}

return cursor;

}

public boolean deleteTodo(long rowId) {

return db.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId,

null) > 0;

}

57

Page 58: Android Tutorial

private ContentValues createContentValues(String category, String

summary,

String description) {

ContentValues values = new ContentValues();

values.put(KEY_CATEGORY, category);

values.put(KEY_SUMMARY, summary);

values.put(KEY_DESCRIPTION, description);

return values;

}

}

6.1.3. Transaction

Thêm một điều đặc biệt nữa là lớp “SQLiteDatabase” hổ trợ cho chúng ta thực hiện

transaction , nghĩa là khi chúng ta cần thực hiện một tập những truy vấn lên cơ sở

dữ liệu và chỉ khi tất cả những truy vấn này cùng thành công thì chúng mới có hiệu

lực, ngược lại chỉ một truy vấn thất bại thì tất cả sẻ không được thực thi. Bằng các

phương thức :

db.beginTransaction(): đánh dấu bắt đầu một transaction.

db.setTransactionSuccessful() : đánh dấu rằng transaction đã thành công. Và

không thực hiện thêm bất kì một hành động nào lên cơ sỡ dữ liệu cho đến khi

gặp phương thức endTransaction. Nếu trong khoảng

setTransactionSuccessful() đến endTransaction() có exeption nào sinh ra thì

transaction vẩn được commit.

db.endTransaction();

Đây là một ví dụ về transaction :

58

Page 59: Android Tutorial

db.beginTransaction();

Cursor cur = null;

try {

cur = db.query("tbl_countries",

null, null, null, null, null, null);

cur.moveToPosition(0);

ContentValues values = new ContentValues();

values.put("state_name", "Georgia");

values.put("country_id", cur.getString(0));

long stateId = db.insert("tbl_states", null, values);

db.setTransactionSuccessful();

view.append("n" + Long.toString(stateId));

} catch (Exception e) {

Log.e("Error in transaction", e.toString());

} finally {

db.endTransaction();

cur.close();

}

6.1.4. Lấy dữ liệu từ Cursor

Điều chúng ta cần quan tâm bây giờ là khi đã có được dữ liệu từ cơ sở dữ liệu trong

một đối tượng của Cursor thì chúng ta sẻ thao tác với chúng như thế nào.

Như đã nói , kết quả của truy vấn cơ sỡ dữ liệu được đặt trong một đối tượng của

giao diện Cursor. Với giao diện này , chúng ta thường sử dụng các phương thức như

là :

59

Page 60: Android Tutorial

boolean moveToNext() : di chuyển đến dòng tiếp theo trong tập kết quả trả về. Nếu

không còn dòng nào nữa sẻ trả về false.

boolean moveToFist() : di chuyển đến dòng đầu tiên của tập kết quả trả về. Nếu tập

kết quả là rổng thì phương thức này sẻ trả về false.

boolean moveToPosition(int position) : di chuyển đến dòng có chỉ số position. Trả

lại false nếu không có dòng ở vị trí position.

boolean moveToPrevious() : di chuyển đến dòng phía trước của dòng hiện tại. Nếu

đang ở dòng đầu tiên thì phương thức này sẻ trả về false.

Boolean moveToLast() : di chuyển đến dòng cuối cùng trong tập kết quả. Nếu tập

kết quả là rổng thì phương thức này sẻ trả về false.

Ngoài ra, còn có các phương thức kiểm tra vị trí hiện thời mà đối tượng của Cursor

đang trỏ đến: isAfterLast(), isBeforeFirst(), isFirst(), isLast() và

isNull(columnIndex).

Dưới đây là một ví dụ về truy xuất dữ liệu từ Cursor :

if (cursor.moveToFirst()){

do{

String data = cursor.getString(cursor.getColumnIndex("data");

// do what ever you want here

}while(moveToNext());

}

cursor.close();

Hoặc một ví dụ khác :

mCursor.moveToFirst();

int index = mCursor.getColumnIndex(Browser.BookmarkColumns.TITLE);

60

Page 61: Android Tutorial

while (mCursor.isAfterLast() == false) {

view.append("n" + mCursor.getString(index));

mCursor.moveToNext();

}

Như ta thấy trong cả hai ví dụ trên đều sử dụng phuong thức

Cursor.getColumnIndex(String ColumnName) để lấy chỉ số của cột trong đối tượng

của Cursor. Từ chỉ số này mà chúng ta sẻ lấy được giá trị của các cột này bằng các

phương thức getShort(), getString(), getDouble(), getInt(), getBlob() sẻ trả về các

kiểu tương ứng là short, String, double, int và getBlob sẻ trả về một byte stream để

truy xuất đến kiểu dữ liệu không xác định.

6.3. Tạo cơ sỡ dữ liệu riêng và đưa vào ứng dụng Android

Giả sử bạn không muốn tạo cơ sở dữ liệu bằng ứng dụng Android. Mà muốn tự tạo

một cơ sở dữ liệu, hoặc trong trường hợp cơ sỡ dữ liệu đã có sẵn và bạn muốn đưa

vào ứng dụng Android sử dụng. Dưới đây là một hướng để giải quyết những yêu

cầu này.

6.1.1. Tạo file cơ sở dữ liệu

Trước hết là tạo một cơ sở dữ liệu. Hoặc nếu đã có sẵn một cơ sỡ dữ liệu thì bạn

củng phải thay đổi một vài điều.

Bạn nên có một giao diện đồ họa để thao tác với SQLite. Có thể sử dụng SQLite

Database Browser , là một phần mềm mả nguồn mở. Có thể download tại :

http://sourceforge.net/projects/sqlitebrowser/

61

Page 62: Android Tutorial

Bạn có thể tạo một cơ sở dữ liệu mới hoặc mở cơ sỡ dữ liệu đã có sẵn lên. Và tạo

thêm table “android_metadata” , bằng cách chạy câu lệnh SQL sau :

CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US')

Sau đó thêm vào một dòng có giá trị là “en_US”, bằng câu lệnh SQL sau :

INSERT INTO "android_metadata" VALUES ('en_US')

Bước tiếp theo , khá cần thiết đó là nếu là cơ sỡ dữ liệu có sẵn bạn nên chuyển tên

tất cả các khóa chính của các table mà bạn có thành “_id”. Hoặc, nếu bạn tạo mới

các table khác, thì các khóa chính nên đặt là “_id”. Hình 7-2 là một ví dụ :

Hình 7-29. Cơ sỡ dữ liệu ví dụ

6.1.2. Sao chép, sử dụng cơ sở dữ liệu có sẵn trong ứng dụng

Android

Sau khi đã có được file cơ sở dữ liệu. Bạn copy file đó vào thư mục “assets” trong

project của ứng dụng. Sau đó, trong project bạn thêm một class DatabaseHelper

thừa kế từ lớp SQLiteOpenHelper trong gói “android.database.sqlite”. Lớp này

củng có các phương thức tương tự như phần trên. Nhưng thay vì tạo cơ sở dữ liệu

trong hàm onCreate(), thì chúng ta thêm phương thức createDataBase() để copy file

cơ sở dữ liệu từ “assert” vào thư mục chứa cơ sở dữ liệu của ứng dụng

public class DataBaseHelper extends SQLiteOpenHelper{

62

Page 63: Android Tutorial

//đường dẫn đến cơ sở dữ liệu trong android

private static String DB_PATH = "/data/data/YOUR_PACKAGE/databases/";

//tên file cơ sở dữ liệu

private static String DB_NAME = "myDBName";

private SQLiteDatabase myDataBase;

private final Context myContext;

public DataBaseHelper(Context context) {

super(context, DB_NAME, null, 1);

this.myContext = context;

}

public void createDataBase() throws IOException{

boolean dbExist = checkDataBase();

if(dbExist){

return;

}else{

this.getReadableDatabase();

try {

copyDataBase();

} catch (IOException e) {

throw new Error("Error copying database");

}

}

}

63

Page 64: Android Tutorial

private boolean checkDataBase(){

SQLiteDatabase checkDB = null;

try{

String myPath = DB_PATH + DB_NAME;

checkDB = SQLiteDatabase.openDatabase(myPath, null,

SQLiteDatabase.OPEN_READONLY);

}catch(SQLiteException e){

//database does't exist yet.

}

if(checkDB != null){

checkDB.close();

}

return checkDB != null ? true : false;

}

private void copyDataBase() throws IOException{

InputStream myInput = myContext.getAssets().open(DB_NAME);

String outFileName = DB_PATH + DB_NAME;

OutputStream myOutput = new FileOutputStream(outFileName);

byte[] buffer = new byte[1024];

int length;

while ((length = myInput.read(buffer))>0){

myOutput.write(buffer, 0, length);

}

myOutput.flush();

myOutput.close();

myInput.close();

64

Page 65: Android Tutorial

}

public void openDataBase() throws SQLException{

String myPath = DB_PATH + DB_NAME;

myDataBase = SQLiteDatabase.openDatabase(myPath, null,

SQLiteDatabase.OPEN_READONLY);

}

@Override

public synchronized void close() {

if(myDataBase != null)

myDataBase.close();

super.close();

}

@Override

public void onCreate(SQLiteDatabase db) {

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

{

}

}

65

Page 66: Android Tutorial

CHƯƠNG 3.THREAD TRONG ANDROID

Khi sử dụng ứng dụng, người dùng luôn mong muốn không phải chờ, không cảm

thấy ứng dụng của mình đang dừng lại. Theo một số ý kiến thì tối đa nên

delay(dừng lại) 200 mili giây.

Nhưng ứng dụng thường có những tác vụ tốn nhiều chi phí và thời gian. Và giải

pháp được đưa ra là thực hiện những tác vụ này trong một thread khác (background

thread) với thread chính của ứng dụng.

6.2. UI thread

Khi ứng dụng được khởi chạy, hệ thống khởi tạo một thread, đây được gọi là “main

thread” của ứng dụng. Main thread còn được gọi là UI thread. Đây là thread có vai

trò rất quan trọng, nó có trách nhiệm gửi những sự kiện đến những widgets thích

hợp.

Ví dụ như , nếu bạn chạm vào một button trên màn hình, UI thread sẻ gửi sự kiện

này (touch event) đến button (widget) đó, do đó, button đó được đặt vào trạng thái

là pressed và một yêu cầu được gửi đến hàng đợi sự kiện. Tiếp đó, UI thread sẻ lấy

yêu cầu từ hàng đợi và thông báo tới button để vẽ nó tự vẽ lại.

Với mô hình một thread này nếu không triển khai đúng cách thì nó có thể mang lại

hiệu suất kém. Đặc biệt, nếu mọi thứ đểu được thực thi trong một thread, khi chúng

ta thực thi một công việc tốn thời gian ví dụ như truy cập dữ liệu từ internet, hoặc

truy vấn từ cơ sở dữ liệu trong UI thread thì giao diện của ứng dụng sẻ bị đứng.

Không có sự kiện nào được gửi đi, bao gồm cả việc vẽ giao diện. Khi đó, người

dùng sẻ nghĩ là ứng dụng bị treo. Và nếu UI thread bị khóa trong một khoảng thời

gian nào đó ( thường là 5 giây) thì một dialog sẻ hiện ra và thông báo là ứng dụng

không hồi đáp, bạn có muốn đóng nó lại không.

66

Page 67: Android Tutorial

Tóm lại, điều quan trọng là luôn để UI thread không bị khóa. Nếu có những tác vụ

cần nhiều tài nguyên, tốn thời gian để thực hiện, bạn nên đưa nó vào một thread

khác.

Dưới đây là một ví dụ về ứng dụng download hình ảnh từ internet và hiển thị vào

một ImageView.

public void onClick(View v) {

new Thread(new Runnable() {

public void run() {

Bitmap b = loadImageFromNetwork();

mImageView.setImageBitmap(b);

}

}).start();

}

Trước hết, đoạn code này có vẽ là một giải pháp tốt, và nó không làm cho UI thread

bị đứng vì nhiệm vụ download hình ảnh đã được thực hiện trong một thread khác.

Nhưng việc thực hiện như đoạn code vừa rồi đã vi phạm tới mô hình đơn thread của

giao diện người dùng. UI thread không phải là thread-safe, và việc cập nhật, hay

thao tác với giao diện phải luôn được thực hiện trong UI thread. Trong đoạn code

trên , mImageView đã được thao tác từ một thread khác, điều này có thể làm cho

chương trình crash.

Android đã đưa ra một số cách để truy cập đến UI thread từ những thread khác. Bao

gồm một số cách phổ biến sau :

Activity.runOnUiThread(Runnable)

View.post(Runnable)

View.postDelayed(Runnable, long)

Handler

Từ Android 1.5 trở lên, hổ trợ lớp AsynTask.

67

Page 68: Android Tutorial

Trong bài báo cáo này sẻ giới thiệu về hai cách được sử dụng nhiều nhất là Handler

và AsynTask.

6.3. Handler

Handler nằm trong gói “android.os” .Handler có thể xem như là một người liên lạc

giữa UI thread và những thread khác(background thread). Những thread khác có thể

gưởi message đến một đối tượng Handler. Và đối tượng Handle này sẻ xử lý từng

message đó, và update giao diện người dùng. Mổi Activity chỉ cần một đối tượng

Handler để xử lý những message được gửi đến, có thể là từ nhiều thread khác.

Chúng ta không cần phải đăng ký đối tượng Handler với UI thread, chỉ cần tạo ra

một đối tượng Handler , nó sẻ tự động ràng buộc với hàng đợi message của Activity

đã tạo ra nó.

Chúng ta có hai cách để giao tiếp với Handler :

Qua messages

Qua một đối tượng Runnable

6.3.1. Sử dụng Messages

Message là lớp nằm trong gói “android.os”.

Để dùng Messages và Handler chúng ta phải thực hiện hai bước chính sau :

Tạo một đối tượng Handler đã overide phương thức callback

“handleMessage(Message msg)”. Để điều khiển việc nhận messages từ những

thread khác. Ngĩa là khi nhận được messages thì làm gì. Mỗi khi có message gửi

đến thì phương thức này sẻ được gọi. Đây sẻ là phương thức thực hiện thay đổi trên

giao diện người dùng (giao tiếp với UI thread). Vì vậy , công việc thực hiện trong

phương thức này không nên tốn quá nhiều thời gian, dẫn đến việc UI thread bị khóa.

68

Page 69: Android Tutorial

Bước tiếp theo là từ những thread khác, chúng ta phải thực hiện gửi message cho

Handler khi cần thiết. Để send message cho Handler, trước hết phải gọi phương

thức obtainMessage() để nhận một đối tượng Message. Bạn có thể gửi một message

trống tới Handler, hoặc message đó chứa định danh và các đối số. Handler xử lý

càng phức tạp, càng nhiều loại message thì bạn càng phải đưa nhiều thông tin cho

Handler biết là đây là message xử lý sự kiện gì.

Bạn gửi message tới Handler bằng một trong các phương thức sau :

sendMessage() : đưa message vào hàng đợi message.

sendMessageAtFrontOfQueue() : đưa message vào hàng đợi, và đặt nó ngay đầu

hàng đợi. Nghĩa là nếu có nhiều message trong hàng đợi , thì message vừa gửi đến

sẻ có độ ưu tiên cao nhất, và xử lý đầu tiên.

sendMessageAtTime() : đặt message vào hàng đợi khi đến một thời điểm nào đó.

Được tính bằng mili giây.

sendMessageDelayed() : đặt message vào hàng đợi sau một khoảng thời gian delay

nào đó, tính bằng mili giây.

Dưới đây là một ví dụ sử dụng Handler :

Tạo mới một project. Sửa lại layout của activity như sau.

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<ProgressBar android:id="@+id/ progressBar1"

style="?android:attr/progressBarStyleHorizontal"

69

Page 70: Android Tutorial

android:layout_width="fill_parent"

android:layout_height="wrap_content" />

</LinearLayout>

ở đây chúng ta sử dụng một ProgressBar để minh họa trên UI cho biết background

thread chạy được tới đâu.

Tiếp theo là xử lý trong Activity :

package com.gtvt.example

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.widget.ProgressBar;

public class HandlerDemo extends Activity {

private ProgressBar m_ProgressBar;

private boolean isRunning=false;

private Handler handler=new Handler() {

@Override

public void handleMessage(Message msg) {

m_ProgressBar.incrementProgressBy(5);

}

};

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

70

Page 71: Android Tutorial

m_ProgressBar=(ProgressBar)findViewById(R.id.progressBar1);

}

public void onStart() {

super.onStart();

m_ProgressBar.setProgress(0);

Thread background=new Thread(new Runnable() {

public void run() {

try {

for (int i=0;i<20 && isRunning;i++) {

Thread.sleep(1000);

handler.sendMessage(handler.obtainMessage());

}

}

catch (Throwable t) {

}

}});

isRunning=true;

background.start();

}

@Override

protected void onDestroy() {

super.onDestroy();

isRunning=false;

}

}

71

Page 72: Android Tutorial

Trong phần khởi tạo của Activity, chúng ta tạo một đối tượng của lớp Handler. Ở

đây chúng ta đã overide lại phương thức handleMessage(). Trong hàm này , cứ mổi

lần nhận được một message từ thread khác, nó sẻ tăng giá trị của progressbar thêm

5.

Trong hàm onStart(), chúng ta tạo một background thread. Thread này đại diện cho

những thread thực hiện những tác vụ tốn nhiều thời gian. Vì vậy trong hàm run()

chúng ta cho thread này sleep một giây, cứ sau mổi giây, thread này sẽ gửi cho

Handler một message. Mặc định của progress bar thì giá trị max là 100. Nhưng

chúng ta có thể đặt lại giá trị này bằng phương thức “setMax()”, như đặt là số dòng

trong một truy vấn cơ sở dữ liệu, …

6.3.2. Sử dụng Runable

Runnable là giao diện nằm trong gói “java.lang”.

Để gưởi một message đến Handler qua Runable cần thực hiện hai bước sau :

Tạo một đối tượng Runnable.

Gửi message đến Handler qua phương thức “post(Runnable r)”.

Để thực hiện việc thay đổi trên giao diện, triển khai những thay đổi đó trong

phương thức run() của giao diện Runable.

Dưới đây là một ví dụ về sử dụng Runnable :

package de.vogella.android.handler;

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.view.View;

72

Page 73: Android Tutorial

import android.widget.ProgressBar;

public class ProgressTestActivity extends Activity {

private Handler handler;

private ProgressBar m_ProgressBar;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

progress = (ProgressBar) findViewById(R.id.progressBar1);

handler = new Handler();

startProgress();

}

public void startProgress() {

Runnable runnable = new Runnable() {

@Override

public void run() {

for (int i = 0; i <= 10; i++) {

final int value = i;

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

handler.post(new Runnable() {

73

Page 74: Android Tutorial

@Override

public void run() {

m_ProgressBar.setProgress(value);

}

});

}

}

};

new Thread(runnable).start();

}

}

Khi gọi phương thức handler.post(Runable r). Thì nó sẽ add đối tượng Runnable

vào hàng dợi message, và sẽ được thực thi bởi đối tượng handler.

6.4. AsyncTask

AsyncTask là một lớp ảo trong gói “android.os” của hệ điều hành Android. Lớp này

cung cấp cho chúng ta những phương thức để quản lý việc tương tác giữa UI thread

và background thread. Nó được triển khai bằng cách thừa kế lớp AsyncTask và triển

khai những phương thức đã được định nghĩa trước của nó. Lớp AsyncTask sử dụng

ba kiểu generic : Params, Progress, Result. Và bốn phương thức để chúng ta tương

tác giữa UI thread, và background thread : onPreExecute, doInBackground,

onProgessUpdate và onPostExecute.

Những kiểu generic mà AsyncTask sử dụng :

Params : kiểu của đối số được truyền cho background thread. Ví dụ như khi chúng

ta có một lớp con của AsyncTask có nhiệm vụ download dữ liệu. Thì chúng ta cần

74

Page 75: Android Tutorial

truyền cho đối tượng này một chuổi String là đường dẫn đến nguồn download. Khi

đó Params là kiểu String.

Progress : là kiểu được trả về trong quá trình đang thực hiện tính toán của

background thread. Ví dụ như trong quá trình download , bạn muốn thông báo cho

người dùng biết đã download được bao nhiêu % chẳng hạn. Thì khi đó Progress có

thể là kiểu int.

Result : kiểu của kết quả trả về từ background thread. Ví dụ bạn cần background

thread download dữ liệu thì kế quả có thể là một mảng byte. Thì khi đó Result là

kiểu byte[].

Mổi khi chúng ta muốn sử dụng AsyncTask , phải chỉ ra cả ba kiểu trên. Nếu chúng

ta không sử dụng một kiểu nào thì có thể dùng kiểu Void.

Ví dụ như :

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

6.4.1. Bốn bước được thực hiện trong AsyncTask

Khi một đối tượng AsyncTask được thực thi, nó sẽ lần lượt thực hiện các phương

thức :

onPreExecute() : được gọi trong UI thread, ngay sau khi đối tượng

AsyncTask được gọi thực thi. Vì phương thức này được thực hiện trong UI

thread, nên nó thường được dùng để thông báo cho người dùng biết là đang

bắt đầu thực thi background thread , ví dụ như hiển thị một Progess bar trong

giao diện người dùng.

doInBackground(Params…) : Được gọi trong background thread ngay sau

khi phương thức onPreExecute() được thực thi xong. Phương thức này được

dùng để thực thi những công việc tốn nhiều thời gian. Đây là phương thức

thực hiện những công việc chính của background thread. Đối số của hàm này

75

Page 76: Android Tutorial

chính là đối số được truyền lúc gọi thực thi AsyncTask. Trong hàm này , bạn

có thể gọi phương thức publishProgress(Progress…) để truyền những kết

quả đã làm được hoặc là những thông báo cho người dùng, … Giá trị truyền

cho hàm publishProgress(Progress …) sẽ được xử lý trong UI thread trong

hàm onProgressUpdate(Progress…).

onProgressUpdate(Progress…): hàm này được gọi trong UI thread sau khi

phương thức publishProgress(Progress…) được gọi. Phương thức này

thường được dùng để hiển thị lên giao diện ứng dụng những thông tin mà

background thread muốn thông báo khi đang thực hiện tính toán. Ví dụ như

hiển thị % đã được hoàn thành trên Progressbar, hoặc hiển thị log trong một

text field.

onPostExecute(Result) : được gọi trong UI thread sau khi hàm

doInBackground() thực hiện xong. Kết quả của việc tính toán trong

background thread được truyền vào phương thức này. Vì nó được thực hiện

trong UI thread nên phương thức này thường được sử dụng để hiển thị kết

quả mà background thread đã thực hiện lên giao diện.

6.4.2. Cách sử dụng

Dưới đây là một ví dụ sử dụng AsyncTask :

package com.gtvt.example

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.widget.ProgressBar;

public class ProgressTestActivity extends Activity {

private ProgressBar m_ProgressBar;

76

Page 77: Android Tutorial

private ProgressTask m_ ProgressTask;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

progress = (ProgressBar) findViewById(R.id.progressBar1);

m_ ProgressTask =new ProgressTask();

m_ ProgressTask.execute(10);

}

@Override

protected void onDestroy() {

super.onDestroy();

if(task.getStatus() == AsyncTask.Status.RUNNING)

m_ ProgressTask.cancel(true);

}

class ProgressTask extends AsyncTask<Integer, Integer, Void>{

@Override

protected void onPreExecute() {

m_ProgressBar.setMax(100);

}

@Override

protected void onCancelled() {

m_ProgressBar.setMax(0);

}

77

Page 78: Android Tutorial

@Override

protected Void doInBackground(Integer... params) {

// lay gia tri dau tien cua progress bar

int start=params[0];

// tang gia tri cua progress bar

for(int i=start;i<=100;i+=5){

try {

boolean cancelled=isCancelled();

if(!cancelled){

publishProgress(i);

SystemClock.sleep(1000);

}else{

break;

}

} catch (Exception e) {

Log.e("Error", e.toString());

}

}

return null;

}

@Override

protected void onProgressUpdate(Integer... values) {

m_ProgressBar.setProgress(values[0]);

}

78

Page 79: Android Tutorial

@Override

protected void onPostExecute(Void result) {

Log.v("Progress", "Finished");

}

}

}

Trong ví dụ này thực hiện việc tăng dần giá trị cho progress bar. Và để giả sử là

AsyncTask đang thực hiện một tác vụ tốn thời gian nào đó, chúng ta dùng hàm

SystemClock.sleep() để cho thread tạm dừng trong vòng 1 giây.

Để sử dụng AsyncTask trong ví dụ này đã gọi như sau :

ProgressTask task=new ProgressTask();

task.execute(10);

Để dừng một AsyncTask đang chạy chúng ta có thể gọi phương thức

cancel(boolean). Và thường thì trước khi dừng một AsyncTask chúng ta phải kiểm

tra xem nó đã được dừng chưa bằng phương thức : isCancelled() và kiểm tra xem

nó có đang chạy không bằng cách so sánh : task.getStatus() ==

AsyncTask.Status.RUNNING.

6.5. Một số chú ý khi làm việc với background thread

Có nhiều trường hợp ứng dụng của bạn muốn thay đổi công việc của

background thread, hay muốn tạm dừng background thread khi người dùng

thao tác với giao diện. Vì vậy trong trường hợp này bạn phải giao tiếp được

với background thread. Android đã hổ trợ nhiều lớp trong gói

java.util.concurrent để bạn có thể giao tiếp an toàn với background thread.

79

Page 80: Android Tutorial

Có trường hợp khi ứng dụng của bạn bị tắt đi trong khi background thread

vẩn tiếp tục thực thi. Ví dụ như sau khi bạn chạy ứng dụng, thì có một cuộc

gọi gọi tới, tiếp sau đó là thêm một tin nhắn tơi, rồi bạn tìm kiếm trong danh

bạ, … Những ứng dụng khác được mở ra liên tiếp như vậy có thể làm cho hệ

điều hành tắt đi ứng dụng ban đầu của bạn vì thiếu bộ nhớ, trong khi

background thread của bạn vẩn chạy. Để xử lý những trường hợp như thế

này bạn cần overive những phương thức khi mà ứng dụng của bạn tắt đi sẽ

được gọi để có thể tắt đi background thread của bạn. Những phương thức ví

dụ như : onStop() của activity…

Một chú ý nữa đó là bạn nên hiển thị cho người dùng biết là background

thread của bạn đang chạy. Ví dụ như dùng một ProgressBar chẳng hạn. Và

bạn nên chú ý khả năng gặp phải lổi trong background thread. Ví dụ như khi

bạn đang lấy thông tin từ Internet bằng một background thread. Và vì một lý

do gì đó, Internet bị ngắt chẳng hạn.

80

Page 81: Android Tutorial

Chương 7 LƯU TRỬ DỮ LIỆU

Hệ điều hành Android cung cấp cho chúng ta một vài cách để có thể lưu trử được

dữ liệu của ứng dụng. Tùy từng trường hợp mà bạn chọn cho mình cách nào, ví dụ

như dữ liệu đó là private hay là có thể cho ứng dụng khác truy cập ,hay bạn muốn

lưu trử nhiều hay ít, …

Gồm có các lựa chọn sau :

Cơ sở dữ liệu SQLite : như đã giới thiệu ở chương 7.

Dùng Shared Preferences :chứa dữ liệu đơn giản, và là private với các ứng

dụng khác. Dữ liệu được chứa theo từng cặp : key –values.

Bộ nhớ trong của máy : chứa dữ liệu trong bộ nhớ trong của điện thoại.

Bộ nhớ ngoài : chứa dữ liệu ở bộ nhớ ngoài, như là thẻ nhớ.

Chứa dữ liệu trên mạng : chứa dữ liệu trên mạng , ở một server nào đó.

6.6. Dùng Shared Preferences

Lớp SharedPreferences trong gói “android.content” cung cấp cho chúng ta cách

thức để lưu và lấy lại dữ liệu bằng những cặp khóa – giá trị. Có thể sử dụng lớp

SharedPreferences để lưu những kiểu cơ bản bao gồm : boolean, float, int, long và

String.

Để lấy đối tượng SharedPreferences của ứng dụng, chúng ta có thể sử dụng hai

phương thức:

getSharedPreferences() : sử dụng khi cần tạo nhiều file chứa dữ liệu bằng

SharedPreferences có thể gọi phương thức này từ context của ứng dụng.

Phương thức này gồm hai đối số :

o name : Tên file preference. Nếu file preference chưa tồn tại nó sẽ

được tạo ra khi bạn tạo một editor (sẽ được nói ở dưới) bằng phương

81

Page 82: Android Tutorial

thức SharedPreferences.edit() và commit bằng phương thức

Editor.commit().

o Mode : là đối số thứ hai. Chỉ ra quyền thao tác: MODE_PRIVATE, là

giá trị default. Nghĩa là chỉ có ứng dụng tạo ra có thể thao tác được.

MODE_WORLD_READABLE: cho phép tất cả các ứng dụng có thể

đọc được. MODE_WORLD_WRITEABLE : cho phép tất cả ứng

dụng có thể đọc ghi.

getPreferences(): dùng phương thức này khi bạn chỉ cần một file preference

để chứa dữ liệu. Trong trường hợp này bạn không cần truyền tên file.

Phương thức này có một đối số là mode , tương tự với đối số thứ 2 của hàm

getSharedPreferences() đã nói ở trên.

Cả hai phương thức này đều trả về một đối tượng SharedPreferences để chúng ta

đọc và ghi giá trị lên file preference.

Các giá trị preference khi được lưu lại sẽ được ghi vào một file xml có đường dẫn là

:

/data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PREFS_NAME.xml

Hoặc tên mặc định là(khi sử dụng phương thức : getPreferences()) :

/data/data/YOUR_PACKAGE_NAME/shared_prefs/

YOUR_PACKAGE_NAME_preferences.xml

Ở đây :

YOUR_PACKAGE_NAME : là tên gói của ứng dụng.

YOUR_PREFS_NAME : tên của file preference được truyền vào qua hàm

getSharedPreferences().

Để ghi dữ liệu chúng ta cần tạo một đối tượng của giao diện

SharedPreferences.Editor. Đây là một giao diện được sử dụng để ghi giá trị vào đối

tượng SharedPreferences. Tất cả những giá trị bạn ghi vào editor đều được giữ lại

82

Page 83: Android Tutorial

cho đến khi bạn gọi phương thức commit(), hoặc apply(). Thì lúc đó dữ liệu mới

được ghi xuống vào SharedPreferences. Nếu commit() thất bại thì tất cả dữ liệu

trong Editor sẽ không được lưu lại.

Để thêm giá trị vào một đối tượng Editor dùng các phương thức như là :

putBoolean(), putString(), …

Để đọc dữ liệu , chúng ta sử dụng các phương thức getBoolean() , getString() , … từ

một đối tượng SharedPreferences. Dựa vào khóa, để chúng ta có thể lấy được giá trị

của mình.

Dưới đây là một ví dụ khá dễ hiểu từ website : http://developer.android.com của

google.

public class Calc extends Activity {

public static final String PREFS_NAME = "MyPrefsFile";

@Override

protected void onCreate(Bundle state){

super.onCreate(state);

. . .

// doc gia tri

SharedPreferences settings = getSharedPreferences(PREFS_NAME,

Context.MODE_PRIVATE);

boolean silent = settings.getBoolean("silentMode", false);

setSilent(silent);

}

@Override

protected void onStop(){

83

Page 84: Android Tutorial

super.onStop();

SharedPreferences settings = getSharedPreferences(PREFS_NAME,

Context.MODE_PRIVATE);

SharedPreferences.Editor editor = settings.edit();

editor.putBoolean("silentMode", mSilentMode);

// Commit the edits!

editor.commit();

}

}

6.7. Sử dụng file hệ thống .

Hệ điều hành Android sử dụng file hệ thống dựa trên hệ điều hành Linux và hổ trợ

chia quyền. Có một vài cách để bạn có thể truy cập vào file hệ thống. Bạn có thể tạo

và đọc file của ứng dụng, củng có thể đọc file có sẵn trong resource, …

6.7.1. Sử dụng bộ nhớ trong.

Chúng ta có thể ghi dữ liệu vào file ở bộ nhớ trong của điện thoại. Mặc định thì file

lưu trong bộ nhớ trong là private với ứng dụng của bạn, và các ứng dụng khác

không thể truy cập được. Khi người dùng gở bỏ ứng dụng , những file đó sẽ bị xóa

cùng ứng dụng.

Khi bạn lưu file vào bộ nhớ trong, nó sẽ được lưu theo đường dẫn :

data/data/[PACKAGE_NAME]/files/[FILE_NAME]

84

Page 85: Android Tutorial

Để có thể ghi file chúng ta cần mở một Outputstream tới file cần ghi. Để làm được

điều đó chúng ta gọi phương thức openFileOutput() từ context của ứng dụng.

Phương thức này trả về cho chúng ta một FileOutputStream . Cần truyền hai đối số :

Name: tên file

Mode: chỉ ra quyền truy cập vào file . Bao gồm các quyền :

o MODE_PRIVATE : chỉ ứng dụng tạo ra file mới được truy cập.

o MODE_WORLD_READABLE : cho phép tất cả các ứng dụng có thể

đọc file.

o MODE_WORLD_WRITEABLE : cho phép những ứng dụng khác có

thể truy cập vào file.

o MODE_APPEND : nếu file đã có sẵn thì ghi tiếp dữ liệu vào cuối file

thay vì xóa file củ, ghi lại file mới.

Dưới đây là một ví dụ đơn giản để ghi file:

String FILENAME = "hello_file";

String string = "hello world!";

Context context = getApplicationContext();

FileOutputStream fos = null;

try {

fos = context.openFileOutput(FILENAME,

Context.MODE_PRIVATE);

fos.write(string.getBytes());

fos.close();

} catch (IOException e) {

Log.v(TAG, e.toString());

} final{

if(fos != null){

try{

85

Page 86: Android Tutorial

fos.close();

}catch(IOException e) {

Log.v(TAG, e.toString());

}

}

Khi đã có được Outputstream, chúng ta thao tác hoàn toàn giống như lập trình trong

java.

Để đọc dữ liệu chúng ta phải mở một InputStream bằng phương thức :

openFileInput(). Phương thức này sẽ trả về một đối tượng FileInputStream.

Ví dụ về đọc file hệ thống.

String FILENAME = "hello_file";

String string = null;

Context context = getApplicationContext();

FileInputStream fis = null;

try {

fis = context.openFileInput(FILENAME);

byte[] reader = new byte[fis.available()];

while (fis.read(reader) != -1) {}

string = new String(reader);

} catch (IOException e) {

Log.v(TAG, e.toString());

} final{

if(fis != null){

try{

fis.close();

}catch(IOException e) {

Log.v(TAG, e.toString());

}

86

Page 87: Android Tutorial

}

}

6.7.2. Lưu trử vào file cache

Nếu bạn muốn cache dữ liệu, thay vì tạo một file rồi ghi dữ liệu vào đó, bạn có thể

sử dụng phương thức getCacheDir() của Context của ứng dụng để lấy đường dẫn

của thư mục chứa file tạm của Android. Sau đó bạn tạo file tạm, và lưu dữ liệu vào

đó.

Khi thiết bị thiếu bộ nhớ trong, hệ điều hành có thể xóa những file tạm này. Tuy

nhiên chúng ta không nên để hệ điều hành làm việc này , mà nên đặt một giới hạn

nào đó cho cache file ví dụ như là 1MB. Khi cache file quá giới hạn này thì nên

thực hiện xóa , hay lược bớt.

Khi bạn gở bỏ chương trình thì những file tạm này củng bị xóa.

Dưới đây là một ví dụ :

File file = new File(context.getCacheDir(), "temp.txt");

try {

file.createNewFile();

FileWriter fw = new FileWriter(file);

BufferedWriter bw = new BufferedWriter(fw);

bw.write("Hello World");

bw.newLine();

bw.close();

} catch (IOException e) {

Log.v(TAG, e.toString());

} final{

87

Page 88: Android Tutorial

try{

if(fw != null)

fw.close();

if(bw!=null)

bw.close();

}catch(IOException e) {

Log.v(TAG, e.toString());

}

}

6.7.3. Đọc file từ resources

Trong trường hợp chúng ta đã có những file có sẵn , và muốn đưa vào ứng dụng sử

dụng. Chúng ta có thể đưa những file đó vào thư mục “res/raw”. Khi compile thành

file apk, file này cũng sẻ được nén cùng. Và để đọc những file này chúng ta có thể

thực hiện như ví dụ sau :

Resources resources = context.getResources();

InputStream is = null;

String string = null;

try {

is = resources.openRawResource(R.raw.filename);

byte[] reader = new byte[is.available()];

while (is.read(reader) != -1) {}

string = new String(reader);

} catch (IOException e) {

Log.e("ReadRawResourceFile", e.getMessage(), e);

} finally {

if (is != null) {

try {

88

Page 89: Android Tutorial

is.close();

} catch (IOException e) {

}

}

}

Có một chú ý là chúng ta không thể ghi lên file trong resources . Chúng ta chỉ có thể

đọc.

6.7.4. Sử dụng bộ nhớ ngoài

Các thiết bị Android đều hổ trợ bộ nhớ ngoài được dùng để lưu trử dữ liệu. Đó có

thể là một thiết bị nhớ có thể di chuyển được ví dụ như là sd card hay có bộ nhớ

không thể tháo ra được. Dử liệu lưu trử trong bộ nhớ ngoài có thể được truy cập từ

bất cứ ứng dụng nào. Và củng có thể truy cập được bằng cách kết nối chế độ USB

với máy tính.

Trước khi sử dụng bộ nhớ ngoài, chúng ta phải luôn kiểm tra xem nó có tồn tại hay

có thể sử dụng được không bằng phương thức :

Environment.getExternalStorageState(), Environment là lớp nằm trong gói :

android.os . Bộ nhớ ngoài có thể đang được kết nối với máy tính, không tồn tại, chỉ

được quyền đọc, …Dưới đây là một ví dụ để kiểm tra bộ nhớ ngoài :

boolean mExternalStorageAvailable = false;

boolean mExternalStorageWriteable = false;

String state = Environment.getExternalStorageState();

if (Environment.MEDIA_MOUNTED.equals(state)) {

// co the doc va ghi

mExternalStorageAvailable = mExternalStorageWriteable = true;

} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {

89

Page 90: Android Tutorial

// chi co the doc

mExternalStorageAvailable = true;

mExternalStorageWriteable = false;

} else {

// khong the doc hoac ghi

mExternalStorageAvailable = mExternalStorageWriteable = false;

}

Ví dụ vừa rồi kiểm tra xem bộ nhớ ngoài có thể đọc và viết hay không. Phương thức

getExternalStorageState() trả về trạng thái của bộ nhớ ngoài. Dựa vào đó bạn có thể

thông báo với người dùng những thông tin cần thiết khi truy cập bộ nhớ ngoài.

Sau khi kiểm tra và bạn có thể truy cập đến bộ nhớ ngoài. Bước tiếp theo là chúng

ta sẽ truy cập nó như thế nào. Nếu bạn sử dụng api level 8 trở lên, thì sử dụng

phương thức getExternalFilesDir() từ context của ứng dụng . Phương thức này có

một đối số “type” để chỉ ra thư mục con của bộ nhớ ngoài mà bạn muốn , ví dụ như

DIRECTORY_MUSIC ,DIRECTORY_RINGTONES, … Để lấy về thư mục gốc

của bộ nhớ ngoài bạn có thể truyền null. Ngoài ra, nếu bạn chỉ ra đối số type mà

trong bộ nhớ ngoài chưa có, thì sau khi gọi phương thức này nó sẽ tự tạo thu mục

đó cho bạn. Nếu người dùng gở bỏ ứng dụng của bạn thì thư mục đó và toàn bộ dữ

liệu sẽ bị xóa.

Nếu bạn sử dụng API level 7 trở xuống, có thể sử dụng phương thức

Environment.getExternalStorageDirectory() để lấy thư mục gốc của bộ nhớ ngoài.

Dưới đây là một ví dụ về tạo file trong bộ nhớ ngoài :

void createExternalStorageFile(Context context) {

//tao file moi

File file = new File(context.getExternalFilesDir(null), "DemoFile.txt ");

try {

90

Page 91: Android Tutorial

file.createNewFile();

FileWriter fw = new FileWriter(file);

BufferedWriter bw = new BufferedWriter(fw);

bw.write("Hello World");

bw.newLine();

bw.close();

} catch (IOException e) {

Log.w("ExternalStorage", "Error writing " + file, e);

}

}

91

Page 92: Android Tutorial

Chương 8LOCATION VÀ MAP

Một chức năng phổ biến mà hiện tại các thiết bị di động đang sử dụng đó là GPS.

Hiện nay , GPS không phải là cách duy nhất để một thiết bị di động có thể biết được

vị trí của bạn. Ngoài GPS còn có một số cách sau :

Dựa vào cột thu- phát sóng điện thoại gần nhất nơi bạn đang đứng.

Dựa vào sóng Wifi gần nhất mà bạn đang đứng.

Nhờ chức năng này mà thiết bị có thể nói cho bạn biết bạn đang ở đâu, và được sử

dụng nhiều nhất với các ứng dụng bản đồ và chỉ đường. Và android cung cấp cho

chúng ta hai API rất tốt để có thể phục vụ mục tiêu này. Đó là : Map API và

Location API.

6.2. Map API

Map API trong Android cung cấp cho chúng ta những công cụ cần thiết để hiển thị

bản đồ và có thể thao tác với nó. Ví dụ như có thể Zoom , pan, ..

Để làm quen với Map API trước hết cần tìm hiểu cách sử dụng lớp MapView. Để

làm việc với lớp MapView chúng ta cần phải có một map-api key từ Google vì

MapView lấy dữ liệu từ dịch vụ của Google.

6.2.1. Cách lấy một map-api key từ Google

Chúng ta cần phải hiểu như sau :

Để hiển thị bản đồ trên MapView, chúng ta phải có một map api key.

Mổi MapView phải có một map api key, và map api key phải được đăng ký

với chứng nhận được sử dụng cho ứng dụng. Ở đây cần giải thích thêm là ,

92

Page 93: Android Tutorial

một ứng dụng Android cần có một chứng nhận, được gọi là digital signature

vertificate. Và map api key phải được đăng ký với chứng nhận này.

Tất cả các MapView trong một ứng dụng có thể sử dụng chung một map api

key.

Chúng ta cần sử dụng hai map-api key. Một cho việc sử dụng trên emulator,

và một cho sản phẩm lúc đưa ra sử dụng trên thiết bị. Lý do của việc này là

vì , khi chúng ta phát triên ứng dụng, sử dụng ADT plug-in để build file apk

và cài đặt file apk đó lên emulator. Lúc này file apk phải được đăng ký một

chứng nhận như đã nói ở trên. ADT plug-in đã sử dụng chứng nhận debug

trong quá trình phát triển ứng dụng. Để có thể đưa ứng dụng ra thị trường

bạn cần phải có một chứng nhận khác cho apk file. Nên lúc này bạn cần một

map api key khác.

Để lấy được một map api key, chúng ta cần phải có được chứng nhận (digital

signature vertificate) mà bạn sẻ dùng cho ứng dụng. Chúng ta sẻ sử dụng chứng

nhận debug của ADT plug-in. Google yêu cầu chúng ta nhập vào mả hóa MD5

fingerprint của chứng nhận này sau đó Google sẻ sinh ra map api key cho chúng ta.

Chứng nhận của ADT plug in thường nằm ở : C:\Documents and Settings\

<username>\Local Settings\Application Data\Android\debug.keystore

Để chắc chắn , bạn có thể tìm chứng nhận của ADT plug in như sau : mở Eclipse

lên, vào menu :

Window->preferences->Android->Build. Vị trí của chứng nhận sẻ nằm ở : “Default

debug key-store”.

Như hình 10-1 :

93

Page 94: Android Tutorial

Hình 10-30 Cách lấy chứng nhận debug.

Để có được mả hóa MD5 fingerprint của chứng nhận bạn phải chạy keytool trong

jre. Thường nằm mặc định ở : C:\Program Files\Java\jdk\jre\bin. Mở commandline

lên, chuyển đến thư mục hiện hành là thư mục bin của jre. Gỏ lệnh như sau :

keytool -list –keystore “your debug.keystore file patch”

Sau đó bạn sẽ được yêu cầu nhập mật khẩu. Mặc định mật khẩu của chứng chỉ ADT

plug-in là : android.

Dưới đây là ví dụ :

94

Page 95: Android Tutorial

Hình 10-31 Ví dụ lấy MD5 fingerprint

Sau khi có được mả của MD5 fingerprint. Chúng ta nhập vào trang web của google

theo link sau :

http://code.google.com/android/maps-api-signup.html

Click vào nút : Generate API key.

Như vậy là bạn đã có được map api key. Bây giờ chúng ta sẻ bắt đầu sử dụng

MapView.

6.2.2. MapView và MapActivity

Có nhiều thành phần hổ trợ MapView trong Android. Và một class mở rộng của

Activity hổ trợ MapView là MapActivity. MapView và MapActivity là hai lớp hổ

trợ nhau khá tốt trong việc hiển thị và thao tác với bản đồ. Để hiển thị một

MapView chúng ta phải đặt nó trong một MapActivity. Thêm nữa, như đã nói ở

trên, khi sử dụng MapView cần phải có map api key. Nếu khởi tạo MapView trong

file xml, thì phải đặt map api key bằng thuộc tính : android:apiKey. Nếu khởi tạo

bằng Constructor thì bạn phải truyền map api key vào cho constructor của

MapView. Vì mapview phải lấy dữ liệu từ google nên bạn phải cấp quyền truy cập

internet cho ứng dụng của mình trong file AndroidManifest.xml.

<uses-permission android:name="android.permission.INTERNET" />

95

Page 96: Android Tutorial

Dưới đây là hình của một ví dụ sử dụng MapView và MapActivity :

Hình 10-32 Ví dụ sử dụng MapView

Trước hết chúng ta cần tạo file layout : mapview.xml nội dung như sau :

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent">

<com.google.android.maps.MapView android:id="@+id/mapview"

android:layout_width="fill_parent"

96

Page 97: Android Tutorial

android:layout_height="wrap_content"

android:apiKey="040-Yr0ZWi2scm-fazCcXKq2zZaglz-Ncv1IgQg"/>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/zoomCtrls"

android:orientation="horizontal"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true">

</LinearLayout>

</RelativeLayout>

Ở đây chúng ta sử dụng Relative layout, chứa một mapview và một LinearLayout.

Và bạn phải gán map api key như ví dụ vào thuộc tính : android:apiKey. Chúng ta

sử dụng linearlayout “zoomCtrls” để chứa những control của mapview.

Đây là phần code java sử dụng MapActivity:

package com.gtvt.hellomapview.activity;

import android.os.Bundle;

import android.widget.LinearLayout;

import com.google.android.maps.MapActivity;

import com.google.android.maps.MapView;

public class HelloMapView extends MapActivity {

private MapView m_MapView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

97

Page 98: Android Tutorial

setContentView(R.layout.mapview);

m_MapView = (MapView)findViewById(R.id.mapview);

LinearLayout layout = (LinearLayout)findViewById(R.id.zoomCtrls);

layout.addView(m_MapView.getZoomControls());

m_MapView.setClickable(true);

}

@Override

protected boolean isRouteDisplayed() {

// TODO Auto-generated method stub

return false;

}

}

Điều đáng chú ý trong lớp này là chúng ta sử dụng linearlayout zoomCtls để chứa

ZoomControl của mapview. Điều này có nghĩa là mapview đã có săn các control

cho phép bạn phóng to và thu nhỏ bản đồ. Điều mà chúng ta cần làm đó là tham

chiếu đến những control này và hiển thị chúng trên layout. Dòng cuối cùng trong

hàm onCreate() : mapView.setClickable(true), cho phép chúng ta có thể pan trên

bản đồ.

Phần tiếp theo chúng ta sẽ tìm hiểu làm sao để có thể thêm những dữ liệu khác lên

mapview.

6.2.3. Sử dụng Overlays

Google cung cấp cho chúng ta khả năng có thể hiển thị những dữ liệu của chúng ta

lên một mapview. Để làm được điều này , chúng ta phải thêm những layer khác lên

98

Page 99: Android Tutorial

trên cùng của bản đồ. Android cung cấp cho chúng ta một số lớp để chúng ta có thể

thêm những layer khác vào map. Các lớp này thường chứa từ “Overlay” trong tên

của mình. Dưới đây là một ví dụ mở rộng của ví dụ trên, có sử dụng lớp

ItemizedOverlay.

package com.gtvt.hellomapview.activity;

import java.util.ArrayList;

import java.util.List;

import android.graphics.Canvas;

import android.graphics.drawable.Drawable;

import android.os.Bundle;

import android.widget.LinearLayout;

import com.google.android.maps.GeoPoint;

import com.google.android.maps.ItemizedOverlay;

import com.google.android.maps.MapActivity;

import com.google.android.maps.MapView;

import com.google.android.maps.OverlayItem;

public class HelloMapView extends MapActivity {

private MapView m_MapView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

99

Page 100: Android Tutorial

setContentView(R.layout.mapview);

m_MapView = (MapView)findViewById(R.id.mapview);

LinearLayout layout = (LinearLayout)findViewById(R.id.zoomCtrls);

layout.addView(m_MapView.getZoomControls());

m_MapView.setClickable(true);

Drawable

marker=getResources().getDrawable(R.drawable.mapmarker);

marker.setBounds(0, 0, marker.getIntrinsicWidth(),

marker.getIntrinsicHeight());

m_MapView.getOverlays().add(new InterestingLocations(marker));

}

@Override

protected boolean isRouteDisplayed() {

return false;

}

class InterestingLocations extends ItemizedOverlay {

private List<OverlayItem> locations = new

ArrayList<OverlayItem>();

private Drawable marker;

public InterestingLocations(Drawable marker) {

super(marker);

this.marker=marker;

GeoPoint hanoi = new

GeoPoint((int)(21.0333333*1000000),(int)(105.85*1000000));

100

Page 101: Android Tutorial

GeoPoint hochiminh = new

GeoPoint((int)(10.8230989*1000000),(int)(106.6296638*1000000));

locations.add(new OverlayItem(hanoi ,

"Ha Noi, Vietnam's capital", "Ha Noi, Vietnam's

capital"));

locations.add(new OverlayItem(hochiminh ,

"Ho Chi Minh city", "Ho Chi Minh city"));

populate();

}

@Override

public void draw(Canvas canvas, MapView mapView, boolean

shadow) {

super.draw(canvas, mapView, shadow);

boundCenterBottom(marker);

}

@Override

protected OverlayItem createItem(int i) {

return locations.get(i);

}

@Override

public int size() {

return locations.size();

}

}

}

101

Page 102: Android Tutorial

Hình 10-33 Ví dụ sử dụng Overlay

Như đã nói ở trên, để thêm những điểm đánh dấu trên bản đồ, chúng ta phải sử dụng

lớp com.google.android.maps.Overlay. Đây là một lớp ảo, vì vậy để sử dụng nó

chúng ta phải thừa kế, hoặc là sử dụng những lớp con của nó. Trong ví dụ trên,

chúng ta đã viết lớp InterestingLocations thừa kế từ lớp ItemizedOverlay, đây là lớp

con của lớp Overlay. ItemizedOverlay là lớp hổ trợ cho chúng ta trong việc tạo một

danh sách những điểm cần đánh dấu trong bản đồ. Mổi điểm đánh dấu trên bản đồ

là một đối tượng của lớp OverlayItem. Hàm size() trả về số lượng cần đánh dấu trên

bản đồ, hàm createItem(int i) trả về điểm đánh dấu thứ i.

Cách thường gặp nhất trong việc sử dụng lớp ItemizedOverlay là thừa kế lớp này,

và thêm những điểm cần đánh dấu lên bản đồ trong hàm tạo của lớp đó. Sau đó gọi

102

Page 103: Android Tutorial

phương thức populate() của lớp ItemizedOverlay. Phương thức này sẽ gọi ngay đến

phương thứ size() để lấy được số lượng điểm đánh dấu. Sau đó mở một vòng lặp ,

gọi phương thức createItem(int i) mà bạn đã overide và lấy được điểm cần đánh dấu

trên bản đồ mà chúng ta đã tạo ra trong hàm tạo của lớp.

Một điều cần phải quan tâm ở đây nữa là trong hàm tạo của lớp OverlayItem, bạn

cần phải có một đối tượng GeoPoint. Lớp GeoPoint đại diện cho một địa điểm trên

trái đất, bao gồm kinh độ và vĩ độ. Chúng ta nhân với 1.000.000 là vì hàm tạo của

GeoPoint sử dụng vi độ, và là kiểu int.

6.3. Location base service

Gói android.location cung cấp cho chúng ta dịch vụ location(Location based

services). Chúng ta sẽ tìm hiểu hai thành phần quan trọng nhất của gói này đó là :

dịch vụ LocationManager và Geocoder.

6.1.1. Dịch vụ LocationManager

Location base service cung cấp cho chúng ta khả năng biết được vị trí địa lý hiện tại

của thiết bị. Và có thể đăng ký để biết được khi nào thiết bị đến một vị trí địa lý đặc

biệt nào đó. Thành phần chính của dịch vụ này là dịch vụ của hệ điều hành

LocationManager. Bây giờ chúng ta sẽ tìm hiểu cách sử dụng dịch vụ này.

Trước hết, muốn sử dụng dịch vụ, chúng ta phải có một tham chiếu đến dịch vụ đó.

Đây là một ví dụ :

package com.gtvt. hellomapview.activity;

import java.util.List;

import android.app.Activity;

import android.content.Context;

import android.location.Location;

103

Page 104: Android Tutorial

import android.location.LocationManager;

import android.os.Bundle;

public class LocationManagerDemoActivity extends Activity{

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

LocationManager m_locMgr =

(LocationManager)this.getSystemService(Context.LOCATION_SERVICE);

Location loc =

m_locMgr.getLastKnownLocation(LocationManager.GPS_PROVIDER);

List<String> providerList = locMgr.getAllProviders();

}

}

Dịch vụ LocationManager là một dịch vụ hệ thống nên chúng ta không thể khởi tạo

nó. Bạn có thể truy cập đến dịch vụ này từ context và sử dụng tên của dịch vụ để

gọi nó. Bạn có thể sử dụng phương thức getSystemService() của Context của ứng

dụng để gọi dịch vụ này, bạn phải truyền đối số là tên của dịch vụ , trong ví dụ trên

là : Context.LOCATION_SERVICE.

Dịch vụ LocationManager cung cấp vị trí địa lý bằng cách sử dụng GPS hoặc là

Network (mạng internet). GPS sử dụng hệ thống định vị toàn cầu để lấy được thông

tin về vị trí của thiết bị. Còn Network sử dụng trạm thu phát sóng điện thoại hoặc vị

trí phát wifi gần nhất để lấy thông tin vị trí của thiết bị. Lớp LocationManager cung

cấp vị trí gần nhất mà thiết bị nhận biết được qua phương thức

getLastKnowLocation(). Đối số truyền cho hàm này thông báo cho dịch vụ biết sẽ

lấy thông tin vị trí từ GPS “LocationManager.GPS_PROVIDER” hay là Network

“LocationManager.Network”. Kết quả trả về là một đối tượng của lớp

104

Page 105: Android Tutorial

android.location.Location. Đối tượng của lớp này cung cấp cho chúng ta những

thông tin về vị trí hiện tại của thiết bị như : kinh độ, vĩ độ, độ cao của thiết bị, tốc

độ, thời gian mà vị trí được tính toán..

Vì LocationManager tính toán vị trí dựa trên nhà cung cấp (GPS hay là Network),

lớp này cho phép chúng ta lấy được danh sách những nhà cung cấp bằng phương

thức : getAllProviders().

Như đã nói ở phần đầu, một lợi ích quan trọng của dịch vụ LocationManager là

nhận thông báo về những thay đổi của vị trí của thiết bị. Dưới đây là một ví dụ sử

dụng chức năng này của LocationManager, để làm được việc này chúng ta phải

đăng ký một listener để nhận những sự kiện về thay đổi vị trí từ LocationManager.

package com.gtvt.hellomapview.activity;

import android.app.Activity;

import android.content.Context;

import android.location.Location;

import android.location.LocationListener;

import android.location.LocationManager;

import android.os.Bundle;

import android.widget.Toast;

public class LocationUpdateDemoActivity extends Activity{

@Override

public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

LocationManager m_locMgr = (LocationManager)

getSystemService(Context.LOCATION_SERVICE);

LocationListener locListener = new LocationListener(){

public void onLocationChanged(Location location){

if (location != null){

105

Page 106: Android Tutorial

Toast.makeText(getBaseContext(),"New location

latitude [" +

location.getLatitude() + "] longitude [" +

location.getLongitude()+"]",

Toast.LENGTH_SHORT).show();

}

}

public void onProviderDisabled(String provider){}

public void onProviderEnabled(String provider){}

public void onStatusChanged(String provider, int status,

Bundle extras){}

};

m_locMgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,

0, locListener);

}

}

Từ ví dụ trên, bạn có thể thấy cách đăng ký với dịch vụ LocationManager một

LocationListener, đó là gọi phương thức requestLocationUpdates() để đăng ký đối

tượng LocationListener. Khi vị trí của thiết bị thay đổi, dịch vụ LocationManager sẽ

gọi phương thức onLocationChanged() của đối tượng listener, và truyền vào là

Location mới của thiết bị. Trong ví dụ trên , khi vị trí của thiết bị thay đổi, chương

trình chỉ hiển thị lên một Toast thông báo về vị trí mới của thiết bị.

Chú ý, chúng ta sử dụng emulator , mà emulator thì lại không có GPS hoặc là các

trạm thu phát sóng điện thoại. Vì vậy, để có thể sử dụng dịch vụ LocationManager

với emulator , chúng ta có thể gưởi vị trí bất kì cho emulator bằng cách như sau.

106

Page 107: Android Tutorial

Chạy emulator, sau đó mở cửa sổ Emulater Control trong eclipse lên ( cửa sổ này

nằm trong chế độ xem DDMS trong eclipse). Trong cửa sổ này , bạn có thể đặt kinh

độ và vĩ độ bất kỳ cho emulator ở phần Location Control. Như hình 10-5.

10-34. Đặt kinh độ và vĩ độ cho emulator.

Đây là kết quả sau khi chạy chương trình trên, và gưởi vị trí location mới cho

emulator.

107

Page 108: Android Tutorial

6.1.2. Geocoding với Android

Làm việc với bản đồ, bạn có thể muốn đổi từ tên một địa điểm thành vị trí kinh độ,

vĩ độ. Việc đổi như trên gọi là geocoding. Và Android cung cấp lớp

android.location.Geocoder hổ trợ cho chúng ta khả năng đổi như trên và ngược lại,

từ kinh độ, vĩ độ sẽ đổi thành một danh sách địa chỉ. Lớp này cung cấp các phương

thức như :

List<Address> getFromLocation(double latitude, double logtitude, int

maxResults);

List<Address> getFromLocationName(String locationName, int maxResults,

double lowerLeftLatitude, double lowerLeftLongitude, double

upperRightLatitude, double upperRightLongitude);

List<Address> getFromLocationName(String locationName, int

maxResults);

Đây là các phương thức trả về một danh sách các Address, lớp

android.location.Address đại diện cho một địa chỉ thực tế, chứa các thông tin về địa

chỉ đó. Vì trả về cả một danh sách nên chúng ta có thể hiểu rằng việc tính toán địa

chỉ không phải là một phép tình hoàn toàn chính xác. Một địa chỉ có thể có nhiều

cách tìm. Ví dụ như : dựa vào tên của địa điểm, dựa vào vị trí địa lý kinh độ, vĩ độ,

…Vì kết quả của phương thức trả về một danh sách nên chúng luôn có một đối số

giới hạn danh sách các địa chỉ tìm được là maxResult( giá trị từ 1 –> 5). Dưới đây là

một ví dụ sử dụng Geocoder.

File goecode.xml chứa layout của ví dụ:

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

<RelativeLayout 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"

108

Page 109: Android Tutorial

android:layout_alignParentBottom="true"

android:layout_height="wrap_content"

android:orientation="vertical" >

<EditText android:layout_width="fill_parent"

android:id="@+id/location"

android:layout_height="wrap_content"

/>

<Button android:id="@+id/geocodeBtn"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Find Location"/>

</LinearLayout>

<com.google.android.maps.MapView

android:id="@+id/geoMap" android:clickable="true"

android:layout_width="fill_parent"

android:layout_height="320px"

android:apiKey="@string/mapskey"

/>

</RelativeLayout>

Activity của ví dụ:

package com.gtvt.hellomapview.activity

import java.io.IOException;

import java.util.List;

import android.app.ProgressDialog;

import android.location.Address;

import android.location.Geocoder;

import android.os.AsyncTask;

109

Page 110: Android Tutorial

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ProgressBar;

import android.widget.Toast;

import com.google.android.maps.GeoPoint;

import com.google.android.maps.MapActivity;

import com.google.android.maps.MapView;

public class GeocodingDemoActivity extends MapActivity{

public static final String TAG = "GeocodingDemoActivity";

private ProgressDialog m_ProgressBar = null;

private Geocoder m_Geocoder = null;

private MapView m_MapView = null;

@Override

protected boolean isRouteDisplayed() {

return false;

}

@Override

protected void onCreate(Bundle icicle){

super.onCreate(icicle);

setContentView(R.layout.geocode);

110

Page 111: Android Tutorial

m_MapView = (MapView)findViewById(R.id.geoMap);

Button geoBtn =(Button)findViewById(R.id.geocodeBtn);

m_Geocoder = new Geocoder(this);

geoBtn.setOnClickListener(new OnClickListener(){

@Override

public void onClick(View arg0) {

EditText loc = (EditText)findViewById(R.id.location);

String locationName = loc.getText().toString();

new GettingAdresses().execute(locationName);

}

});

}

private class GettingAdresses extends AsyncTask<String, Void,

List<Address>>{

@Override

protected void onPostExecute(List<Address> addressList) {

m_ProgressBar.dismiss();

if(addressList!=null && addressList.size()>0){

int lat = (int)addressList.get(0).getLatitude()*1000000;

int lng =

(int)addressList.get(0).getLongitude()*1000000;

GeoPoint pt = new GeoPoint(lat,lng);

m_MapView.getController().setZoom(10);

m_MapView.getController().setCenter(pt);

m_MapView.getController().animateTo(pt);

}else{

111

Page 112: Android Tutorial

Toast.makeText(GeocodingDemoActivity.this, "Can't

get the address", Toast.LENGTH_LONG).show();

}

}

@Override

protected void onPreExecute() {

m_ProgressBar =

ProgressDialog.show(GeocodingDemoActivity.this,

"Searching..", "Wait for a moment !");

}

@Override

protected List<Address> doInBackground(String... locationNames) {

if(locationNames.length < 1)

return null;

try {

List<Address> addressList =

m_Geocoder.getFromLocationName(locationNames[0], 5);

return addressList;

} catch (IOException e) {

Log.v(TAG, e.toString());

return null;

}

}

}

}

112

Page 113: Android Tutorial

Cần thêm những quyền sau vào file AndroidManifest.xml.

<uses-permission

android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-permission

android:name="android.permission.ACCESS_COARSE_LOCATION" />

<uses-permission android:name="android.permission.INTERNET" />

Có một chú ý quan trọng đó là hiện tại thì Emulator không hổ trợ geocoder. Vì vậy

nếu bạn chạy ví dụ trên với emulator thì luôn có một thông báo hiện lên là "Can't

get the address". Lúc này một exception sẻ được quăng ra :

GeocodingDemoActivity(905): java.io.IOException: Service not Available.

Nhưng nếu bạn sử dụng geocoder trên thiết bị thật và có kết nối Internet thì chương

trình sẽ chạy bình thường.

113

Page 114: Android Tutorial

DANH MỤC TÀI LIỆU THAM KHẢO

Tiếng Anh

[1] Mark L.Murphy (2009), Beginning Android, APress, United States of America.

[2] Marko Gargenta (2011), Learning Android, O’Reilly Media, Inc.

114