You are on page 1of 234

TRƯỜNG ĐẠI HỌC KHOA HỌC TỰ NHIÊN

KHOA CÔNG NGHỆ THÔNG TIN


BỘ MÔN MẠNG MÁY TÍNH – VIỄN THÔNG

ĐẶNG NGUYỄN KIM ANH – ĐÀO ANH TUẤN

NGHIÊN CỨU JAVA MOBILE


VÀ XÂY DỰNG ỨNG DỤNG
MINH HỌA

KHÓA LUẬN CỬ NHÂN TIN HỌC

TP.HCM, 2005
TRƯỜNG ĐẠI HỌC KHOA HỌC TỰ NHIÊN
KHOA CÔNG NGHỆ THÔNG TIN
BỘ MÔN MẠNG MÁY TÍNH – VIỄN THÔNG

ĐẶNG NGUYỄN KIM ANH – 0112424


ĐÀO ANH TUẤN – 0112451

NGHIÊN CỨU JAVA MOBILE


VÀ XÂY DỰNG ỨNG DỤNG
MINH HỌA

KHÓA LUẬN CỬ NHÂN TIN HỌC

GIÁO VIÊN HƯỚNG DẪN

Thầy NGUYỄN MINH TUẤN

NIÊN KHÓA 2001-2005


Lời Cảm Ơn!

Sau hơn năm tháng tìm hiểu và thực hiện, luận văn “Nghiên cứu công nghệ
Java Mobile và xây dựng ứng dụng minh hoạ” đã cơ bản hoàn thành. Để đạt được
kết quả này, chúng tôi đã nỗ lực hết sức đồng thời cũng nhận được rất nhiều sự
quan tâm, giúp đỡ, ủng hộ của các thầy cô, bạn bè và gia đình.
Trước hết, chúng em xin gởi lời cảm ơn chân thành đến Bộ môn Mạng máy
tính và Viễn thông, Khoa Công nghệ Thông tin, trường Đại học Khoa học Tự nhiên
và các thầy cô đặc biệt là Thầy Nguyễn Minh Tuấn đã tận tình giúp đỡ, hướng dẫn
chúng em hoàn thành luận văn này.
Chúng tôi rất cảm ơn các bạn bè trong khoa, các anh chị, các bạn trong cộng
đồng Java Việt Nam đã bên cạnh ủng hộ, đóng góp ý kiến cho chúng tôi trong quá
trình thực hiện luận văn.
Và chúng con cũng xin chân thành cảm ơn gia đình đã luôn động viên, tạo
điều kiện tốt nhất cho chúng con học tập và hoàn tất luận văn.
Luận văn đã hoàn thành với một số kết quả nhất định, tuy nhiên vẫn không
tránh khỏi sai sót. Kính mong sự cảm thông và đóng góp ý kiến từ các thầy cô và
các bạn.

Thành phố Hồ Chí Minh, tháng 7 năm 2005

Đặng Nguyễn Kim Anh - Đào Anh Tuấn


MỤC LỤC
Lời Nói Đầu...................................................................................................... 1
Phần 1: Kiến thức nền tảng J2ME ................................................................ 5
Chương 1: Tổng quan về J2ME.................................................................... 5
1.1 Giới thiệu J2ME (Java 2 Micro Edition).......................................................5
1.2 Lý do chúng ta cần J2ME..............................................................................6
1.3 Các thành phần của J2ME:............................................................................7
1.3.1 Configuration:.............................................................................................7
1.3.2 Profile: ........................................................................................................9
1.3.3 Máy ảo Java ..............................................................................................10
Chương 2: Giới thiệu CLDC và MIDP ...................................................... 13
2.1. CLDC ..........................................................................................................13
2.1.1. Yêu cầu phần cứng: ..................................................................................13
2.1.2. Yêu cầu phần mềm: ..................................................................................13
2.1.3. Máy ảo Java:.............................................................................................13
2.2. MIDP:..........................................................................................................16
2.2.1. Yêu cầu phần cứng: ..................................................................................16
2.2.2. Yêu cầu phần mềm: ..................................................................................16
2.2.3. Cấu trúc MID Profile:...............................................................................16
2.2.4. MIDlet Suite: ............................................................................................18
2.2.5. Môi trường phát triển ứng dụng J2ME.....................................................22
Chương 3: Các vấn đề cơ bản của chương trình MIDlet ......................... 25
3.1. Cấu trúc cơ bản: ..........................................................................................25
3.2. Xây dựng một ứng dụng MIDlet:................................................................25
3.3. Lớp MIDlet: ................................................................................................26
3.4. Lớp MIDletStateChangeException:............................................................28
3.5. Display.........................................................................................................28
3.6. Lớp Displayable: .........................................................................................30
3.7. Quản lý các sự kiện (event).........................................................................32
3.7.1. Command & CommandListener...............................................................33
3.7.2. Item và ItemStateListener.........................................................................38
Chương 4: Giao diện đồ họa cấp cao.......................................................... 40
4.1. Screen: .........................................................................................................42
4.2. Form: ...........................................................................................................43
4.3. Item:.............................................................................................................45
4.3.1. DateField: .................................................................................................46
4.3.2. Gauge:.......................................................................................................48
4.3.3. String Item: ...............................................................................................51
4.3.4. TextField: .................................................................................................53
4.3.5. ChoiceGroup: ...........................................................................................57
4.3.6. Image và ImageItem: ................................................................................61
4.4. List:..............................................................................................................64
4.5. TextBox:......................................................................................................69
4.6. Alert và AlertType: .....................................................................................72
4.6.1. Alert:.........................................................................................................72
4.6.2. AlertType:.................................................................................................74
4.7. Ticker: .........................................................................................................77
Chương 5: Giao diện đồ họa cấp thấp........................................................ 78
5.1. Canvas: ........................................................................................................78
5.1.1. Hệ toạ độ:..................................................................................................79
5.1.2. Vẽ trên đối tượng Canvas:........................................................................79
5.1.3. Bắt sự kiện trong các đối tượng Canvas:..................................................82
5.1.4. Game action:.............................................................................................85
5.1.5. Sự kiện con trỏ:.........................................................................................87
5.2. Graphics: .....................................................................................................89
5.2.1. Màu sắc:....................................................................................................90
5.2.2. Nét vẽ:.......................................................................................................93
5.2.3. Font chữ:...................................................................................................98
5.2.4. Vẽ các đối tượng hình ảnh (image): .......................................................101
5.2.5. Các phương thức tịnh tiến đối tượng:.....................................................103
5.2.6. Vùng xén (Clipping regions):.................................................................105
Chương 6: Lưu trữ thông tin với RMS.................................................... 106
6.1. Giới thiệu RMS .........................................................................................106
6.2. Duyệt danh sách Record với RecordEnumeration ....................................115
6.3. Sắp xếp bằng RecordComparator..............................................................117
6.4. Lọc record với RecordFilter ......................................................................119
6.5. Nhận thông điệp khi Record Store thay đổi ..............................................121
6.6. Xử lý lỗi khi thao tác với Record Store.....................................................122
Chương 7: Kết nối mạng với Generic Connection Framework (GCF) 124
7.1. Giới thiệu GFC..........................................................................................124
7.2. Lược đồ lớp ...............................................................................................124
7.3. Kết nối HTTP:...........................................................................................127
7.3.1. Khởi tạo kết nối: .....................................................................................127
7.3.2. Các đặc điểm của kết nối HTTP bằng J2ME: ........................................130
7.3.3. Thông số kết nối: ....................................................................................137
7.4. Kết nối socket Datagram (UDP) ...............................................................138
7.5. Kết nối TCP socket ...................................................................................141
7.6. Gửi và nhận SMS ......................................................................................144
Phần 2 : Web Service và Ứng dụng "Đăng Ký Học Phần" .................... 149
Chương 8: Giới thiệu Web Service........................................................... 149
8.1. Ứng dụng phân tán (Distributed Application) ..........................................149
8.1.1. Giới thiệu ................................................................................................149
8.1.2. Các vấn đề nảy sinh trong hệ thống ứng dụng phân tán.........................150
8.1.3. Hạn chế của những mô hình ứng dụng phân tán trước đây....................151
8.2. Web Service ..............................................................................................152
8.2.1. Định nghĩa ..............................................................................................152
8.2.2. Thành phần cơ bản của Web service:.....................................................152
8.2.3. Hoạt động của Web service....................................................................152
8.2.4. Ưu điểm của web service .......................................................................155
8.3. Các thành phần chính của Web Service ....................................................157
8.3.1. SOAP (Simple Object Access Protocol) ................................................157
8.3.2. WSDL (Web Service Definition Language) ..........................................162
Chương 9: Ứng dụng đăng ký học phần .................................................. 172
9.1 Đặc tả chương trình:..................................................................................172
9.1.1 Tổng quan:..............................................................................................172
9.1.2 Các chức năng chính: .............................................................................172
9.2 Kiến trúc chương trình: .............................................................................174
9.2.1 Mô hình kết nối: .....................................................................................174
9.2.2 Mô hình bảo mật (mã hoá password): ....................................................176
9.3 Phân tích - thiết kế:....................................................................................177
9.3.1 Mô hình use case: ...................................................................................177
9.3.2 Đặc tả một số use case chính:.................................................................178
9.4 Thiết kế mô hình dữ liệu: ..........................................................................183
9.4.1 Mô hình thực thể kết hợp: ......................................................................183
9.4.2 Các bảng dữ liệu:....................................................................................183
9.4.3 Chi tiết các bảng dữ liệu:........................................................................184
9.4.4 Ràng buộc dữ liệu:..................................................................................188
9.4.5 Mô hình dữ liệu: .....................................................................................190
9.4.6 Các chức năng store procedures:............................................................190
9.4.7 Thiết kế lớp:............................................................................................191
9.5 Cài đặt - thử nghiệm:.................................................................................192
9.5.1 Yêu cầu phần cứng: ................................................................................192
9.5.2 Yêu cầu phần mềm: ................................................................................193
9.5.3 Giao diện chương trình:..........................................................................193
Chương 10: Tổng kết ............................................................................... 205
10.1 Kết luận: ....................................................................................................205
10.2 Hướng phát triển: ......................................................................................207
Tài liệu tham khảo ...................................................................................... 210
Phụ Lục A: Hướng dẫn sử dụng công cụ Sun Wireless ToolKit 2.3 ...... 211
Phụ Lục B: Xây dựng và Sử dụng Web Service....................................... 217
Phụ Lục C: Giới thiệu các thư viện JSR ................................................... 222
Danh Sách Các Hình

Hình 1.1 Các thiết bị J2ME hỗ trợ ..............................................................................6


Hình 1.2 Các thành phần của J2ME............................................................................7
Hình 1.3 Configurations và các thiết bị ......................................................................9
Hình 1.4 Cấu trúc chương trình J2ME......................................................................11
Hình 1.5 Cấu trúc chương trình MIDP .....................................................................11
Hình 2.1 Cấu trúc thiết bị MID .................................................................................17
Hình 3.1 Command Exit ...........................................................................................34
Hình 3.2 Command Label .........................................................................................36
Hình 3.3 Ánh xạ soft-button......................................................................................36
Hình 4.1 Sơ đồ các lớp giao diện đồ hoạ ..................................................................40
Hình 4.2 Giao diện đối tượng DateField...................................................................46
Hình 4.3 Giao diện đối tượng Gauge chế độ tương tác ............................................48
Hình 4.4 Giao diện đối tượng Gauge chế độ không tương tác .................................49
Hình 4.5 Giao diện đối tượng StringItem .................................................................52
Hình 4.6 Giao diện đối tượng TextField ...................................................................56
Hình 4.7 Giao diện đối tượng ChoiceGroup chế độ một lựa chọn ...........................59
Hình 4.8 Giao diện đối tượng ChoiceGroup chế độ nhiều lựa chọn.........................60
Hình 4.9 Giao diện đối tượng List dạng menu..........................................................67
Hình 4.10 Giao diện đối tượng List cho phép chọn nhiều lựa chọn .........................68
Hình 4.11 Giao diện đối tượng TextBox...................................................................71
Hình 4.12 Giao diện đối tượng Alert ........................................................................76
Hình 4.13 Giao diện Ticker.......................................................................................77
Hình 5.1 Các phương thức vẽ đường cong ...............................................................94
Hình 5.2 Các phương thức vẽ hình chữ nhật ............................................................95
Hình 5.3 Các phương thức hỗ trợ vẽ Text ................................................................97
Hình 5.4 Các định dạng trong Text Graphic.............................................................97
Hình 5.5 Các phương thức tạo font.........................................................................100
Hình 5.6 Vẽ bằng đối tượng Immutable Image ......................................................101
Hình 5.7 Vẽ bằng đối tượng Mutable Image ..........................................................102
Hình 5.8 Các định dạng vị trí trong Graphics .........................................................103
Hình 7.1 Lược đồ các lớp trong thư viện GCF .......................................................125
Hình 7.2 Kết nối UDP.............................................................................................138
Hình 7.3 Kết Nối TCP.............................................................................................141
Hình 7.4 Lược đồ lớp thư viện WMA.....................................................................145
Hình 8.1 Hoạt động của Web Service.....................................................................152
Hình 8.2 Một client truy xuất đến nhiều web services cùng lúc.............................154
Hình 8.3 Một web service có thể triệu tập đến các web services khác...................155
Hình 8.4 Web Service Endpoint..............................................................................162
Hình 9.1 Kiến trúc chương trình ứng dụng.............................................................174
Hình 9.2 Mô hình mã hoá password .......................................................................176
Hình 9.3 Lược đồ use case ......................................................................................177
Hình 9.4 Mô hình thực thể kết hợp ER ...................................................................183
Hình 9.5 Ràng buộc chu trình .................................................................................189
Hình 9.6 Mô hình cơ sở dữ liệu ..............................................................................190
Hình 9.7 Mô hình Lớp.............................................................................................192
Hình 9.8 Sơ đồ các màn hình ..................................................................................194
Hình 9.9 Màn hình welcome...................................................................................195
Hình 9.10 Màn hình đăng nhập...............................................................................196
Hình 9.11 Confirm ..................................................................................................197
Hình 9.12 Menu chức năng.....................................................................................198
Hình 9.13 Màn hình đăng ký học phần lý thuyết....................................................199
Hình 9.14 Màn hình đăng ký học phần thực hành ..................................................200
Hình 9.15 Màn hình xem thời khoá biểu ................................................................201
Hình 9.16 Màn hình xem kết quả học tập ...............................................................202
Hình 9.17 Màn hình xem phiếu đăng ký.................................................................203
Hình 9.18 Màn hình xem thời khoá biểu ................................................................204
Hình 10.1 Hướng phát triển thực tế ........................................................................207
Hình A.1 Công cụ Sun WirelessToolkit 2.3 ...........................................................211
Hình A.2 Màn hình chính của công cụ ...................................................................212
Hình A.3 Tạo project mới .......................................................................................212
Hình A.4 Các options cho project ...........................................................................213
Hình A.5 Chỉnh sửa nội dung file Jad và Jar ..........................................................214
Hình A.6 Biên dich project .....................................................................................215
Hình A.7 Đóng gói ứng dụng..................................................................................216
Hình B.1 Tạo project Web Service .........................................................................217
Hình B.2 Khai báo lớp và hàm................................................................................218
Hình B.3 Export nhiều hàm cùng lúc......................................................................219
Hình B.4 Màn hình thực thi Web Service của IE ...................................................219
Hình B.5 File WSDL...............................................................................................220
Hình B.6 Công cụ Stub Generator ..........................................................................221
Hình B.7 Các options của công cụ Stub Generator.................................................221
Danh Sách Các Bảng
Bảng 2.1 Cấu trúc file manifest.................................................................................19
Bảng 2.2 Cấu trúc file JAD .......................................................................................20
Bảng 3.1 Lớp MIDlet ................................................................................................27
Bảng 3.2 Lớp Display ...............................................................................................29
Bảng 3.3 Lớp Displayable.........................................................................................32
Bảng 3.4 Các Command Type ..................................................................................37
Bảng 3.5 Command và CommandListener ...............................................................38
Bảng 3.6 Item và ItemStateListener..........................................................................39
Bảng 4.1 Lớp Screen.................................................................................................42
Bảng 4.2 Lớp Form ...................................................................................................44
Bảng 4.3 Lớp Item ....................................................................................................45
Bảng 4.4 Lớp DateField ............................................................................................46
Bảng 4.5 Lớp Gauge .................................................................................................49
Bảng 4.6 Lớp StringItem...........................................................................................51
Bảng 4.7 Các Ràng Buộc của TextField ...................................................................53
Bảng 4.8 Lớp TextField ............................................................................................55
Bảng 4.9 Lớp ChoiceGroup ......................................................................................58
Bảng 4.10 Lớp Image................................................................................................62
Bảng 4.11 Định dạng ImageItem ..............................................................................62
Bảng 4.12 Lớp ImageItem ........................................................................................63
Bảng 4.13 So sánh List và ChoiceGroup ..................................................................65
Bảng 4.14 Lớp List....................................................................................................66
Bảng 4.15 So sánh TextField và TextBox ................................................................69
Bảng 4.16 Lớp TextBox............................................................................................70
Bảng 4.17 Lớp Alert..................................................................................................73
Bảng 4.18 AlertType.................................................................................................75
Bảng 4.19 Lớp Ticker ...............................................................................................77
Bảng 5.1 Truy vấn kích thước Canvas......................................................................79
Bảng 5.2 Lớp Canvas ................................................................................................81
Bảng 5.3 Giao tiếp với Application Manager ...........................................................81
Bảng 5.4 Mã Phím.....................................................................................................83
Bảng 5.5 Sự kiện keyPressed ....................................................................................84
Bảng 5.6 Sự kiện Game Action.................................................................................85
Bảng 5.7 Bắt sự kiện trong Game Action .................................................................86
Bảng 5.8 Sự kiện con trỏ...........................................................................................87
Bảng 5.9 Lớp Graphics .............................................................................................90
Bảng 5.10 Các phương thức vẽ .................................................................................93
Bảng 5.11 Xử lý Text................................................................................................96
Bảng 5.12 Giá trị Anchor ..........................................................................................96
Bảng 5.13 Xử lý Font chữ.........................................................................................98
Bảng 5.14 Các giá trị Font ........................................................................................99
Bảng 5.15 Vẽ hình ảnh............................................................................................101
Bảng 5.16 Giá trị Image Anchor .............................................................................103
Bảng 5.17 Các phương thức tịnh tiến .....................................................................103
Bảng 5.18 Vùng xén................................................................................................105
Bảng 6.1 Mô hình Record Store..............................................................................107
Bảng 6.2 Lớp RecordStore......................................................................................109
Bảng 6.3 Lớp RecordEnumeration .........................................................................117
Bảng 6.4 Các giá trị hằng để sắp xếp record...........................................................118
Bảng 6.5 Lớp RecordListener .................................................................................121
Bảng 7.1 Lớp Connector .........................................................................................128
Bảng 7.2 Mode Kết Nối ..........................................................................................128
Bảng 7.3 Các Request Method chính......................................................................130
Bảng 7.4 Các phương thức set/get Request Method...............................................131
Bảng 7.5 Các phương thức truy vấn HTTP Header................................................134
Bảng 7.6 Lấy thông số kết nối ................................................................................137
Bảng 7.7 Lớp DatagramConnection .......................................................................139
Bảng 7.8 Lớp Datagram ..........................................................................................140
Bảng 7.9 Thuộc tính của SocketConnection...........................................................142
Bảng 7.10 Lớp SocketConnection ..........................................................................143
Bảng 7.11 Các interfaces chính của WMA.............................................................144
Bảng 9.1 Danh sách các Use Case ..........................................................................178
Bảng 9.2 Table ChuyenNganh ................................................................................184
Bảng 9.3 Table SV ..................................................................................................184
Bảng 9.4 Table MonHoc .........................................................................................185
Bảng 9.5 Table GV .................................................................................................185
Bảng 9.6 Table Lop.................................................................................................185
Bảng 9.7 Table Lop_MonLT ..................................................................................186
Bảng 9.8 Table Lop_MonTH..................................................................................187
Bảng 9.9 Table PhanCongTH .................................................................................187
Bảng 9.10 Table DangKyLT...................................................................................187
Bảng 9.11 Table DangKyTH ..................................................................................187
Bảng 9.12 Table ThongBao ....................................................................................188
Các chữ viết tắt, thuật ngữ được sử dụng

API Application Program Interface


CDC Connected Device Configuration
CLDC Connected Limited Device Configuration
Đặc tả qui định các thư viện gốc J2ME phải hỗ trợ cho một dòng
Configuration
phần cứng.
DES Thuật toán mã hóa khóa bí mật 64 bits
GCF General Connection Framework
IIS Internet Information Services-Web server chuẩn trên Windows
J2EE Java 2 Enterpise Edition, phiên bản Java cho những dự án lớn.
J2ME Java 2 Micro Edition, phiên bản Java cho những thiết bị nhỏ.
Java 2 Standard Edition, phiên bản Java ra đời đầu tiên, dành cho
J2SE
PC thông thường.
JCP Tổ chức Java Community Process
JDK Java Development Kits
Java Specification Requests, những yêu cầu cần bổ sung cho các
JSR
phiên bản Java.
JSR-172 Thư viện truy xuất web service cho ngôn ngữ J2ME.
JSR-177 Thư viện mã hóa và bảo mật cho ngôn ngữ J2ME.
KVM Máy ảo Java cho môi trường CLDC.
MIDlet Tên gọi chung cho các ứng dụng J2ME.
MIDP Mobile Information Device Profile.
Multimedia Message Service, tin nhắn hình ảnh, âm thanh, video
MMS
cho di động.
PDA Personal Digital Assistant.
Profile Các tập thư viện cấp cao định nghĩa trên nền Configuration.
RMS RecordStore Management System, cơ chế lưu trữ của J2ME.
Short Message Service, tin nhắn thông thường cho điện thoại di
SMS
động.
Simple Object Access Protocol, định dạng thông điệp của Web
SOAP
Service.
Symbian Hệ điều hành cho điện thoại di động của hãng Symbian.
UDDI Universal Description, Discovery, and Integration
Web Service Giao thức gọi hàm từ xa dựa trên XML và HTTP.
WMA Wireless Message API
WSDL Web Service Definition Language
XML Extensible Markup Language
Java Mobile

Lời Nói Đầu

Mạng điện thoại di động xuất hiện tại Việt Nam từ đầu những năm 1990 và
theo thời gian, số lượng các thuê bao cũng như các nhà cung cấp dịch vụ di động tại
Việt Nam ngày càng tăng. Cùng với sự phát triển của số lượng thuê bao di động là
sự đa dạng hoá các dịch vụ hướng đến thiết bị di động. Ngày nay điện thoại di động
không chỉ còn mang chức năng gọi điện hay nhắn tin thông thường mà còn là một
thiết bị giải trí, tra cứu thông tin rất tiện lợi. Do đó, xây dựng các ứng dụng cho điện
thoại di động đang là một yêu cầu tất yếu trong xu thế hiện nay. Ngành công nghiệp
phần mềm cho các thiết bị di động được xem như một mảnh đất màu mỡ và hứa hẹn
đem lại nhiều tỉ đô la doanh thu.
Hai hướng phát triển ứng dụng trên điện thoại di động phổ biến hiện nay là
sử dụng ngôn ngữ C++ trên nền hệ điều hành Symbian và J2ME. Các ứng dụng viết
trên nền Symbian có các ưu thế truy cập trực tiếp các tài nguyên của điện thoại cũng
như hỗ trợ hệ thống tập tin, thư mục… như máy tính cá nhân vì được hỗ trợ trực
tiếp bởi hệ điều hành. Tuy nhiên hệ điều hành Symbian lại có kích thước khá lớn
nên chỉ có ở các thế hệ điện thoại tương đối cao cấp, và xây dựng ứng dụng dùng
Symbian API cũng phức tạp hơn.
Đối trọng với Symbian API là công nghệ J2ME với kích thước nhỏ gọn,
tiện dụng, được hỗ trợ bởi hầu hết các thế hệ điện thoại mới ra đời, kể cả các điện
thoại có hệ điều hành Symbian. J2ME không những là một ngôn ngữ hướng đến các
thiết bị di động mà còn là ngôn ngữ chính để lập trình trên các thiết bị gia dụng, thẻ
tín dụng điện tử và các thiết bị thông minh khác. Chúng ta có thể nói đối tượng của
ngôn ngữ J2ME là rộng hơn rất nhiều so với C++ trên nền Symbian. Tại thời điểm
hiện tại, ngôn ngữ J2ME không hỗ trợ được nhiều tính năng như C++ trên Symbian
nhưng lại có những ưu điểm trội hơn.
J2ME là một ngôn ngữ nhỏ, gọn nhưng rất chặt chẽ và dễ nắm bắt, với
những lập trình viên đã có kinh nghiệm với Java việc lập trình với J2ME trở nên rất

1
Java Mobile

dễ dàng. J2ME còn là một ngôn ngữ được các tổ chức mã nguồn mở ủng hộ mạnh
mẽ và phát triển rất nhanh chóng, JCP (Java Community Process-
http://www.jcp.org) là một chương trình do Sun thành lập luôn tiếp thu các ý kiến
và đưa ra các đặc tả mới dành cho Java nói chung và J2ME nói riêng. Các đặc tả
này thường có tiếp đầu ngữ JSR và là các tính năng bổ sung mới cho J2ME.
Những JSR quan trọng có thể được nhắc đến như JSR-82 (Bluetooth), JSR
205 (Gửi tin nhắn SMS, MMS), JSR-172 (Web service), JSR-177 (Security and
Trust Services), JSR 184 (3D Game)… Các đặc tả này ngày càng phong phú và
phần nào phát triển nhanh hơn cả sự phát triển của phần cứng.
Thật khó so sánh giữa các dòng ngôn ngữ lập trình với nhau vì mỗi loại đều
có ưu và khuyết điểm riêng. Trong luận văn của mình, chúng tôi chọn nghiên cứu
về J2ME vì những ưu điểm khá rõ ràng đã nêu trên, mặt khác chúng tôi cũng muốn
thử sức ở một lãnh vực khá mới mẻ là tiếp cận với phần mềm mã nguồn mở.
Về chương trình ứng dụng, tính khả thi và thực tế ngày càng được đề cao.
Chúng tôi nhận thấy xu hướng mở rộng các ứng dụng trên web sang điện thoại di
động đang được chú trọng. Thương mại điện tử (e-commerce) đang tiến dần sang
thương mại di động (m-commerce). Với thực trạng Việt Nam hiện nay, số người sở
hữu máy vi tính cá nhân, đặc biệt là máy tính xách tay chưa nhiều nhưng tỉ lệ số
người có điện thoại di động lại khá cao. Việc chuyển các ứng dụng thương mại từ
môi trường web sang môi trường di động sẽ khiến sự tiện dụng tăng cao, số người
sử dụng dịch vụ trực tuyến chắc chắn sẽ tăng nhanh vì đối với nhiều người chiếc
điện thoại di động dễ sử dụng hơn rất nhiều so với chiếc máy tính "phức tạp và khó
hiểu".
Ứng dụng chúng tôi chọn thực hiện để bước chân vào lãnh vực khá mới mẻ
này là ứng dụng "Đăng Ký Học Phần" qua mạng di động. Đối với sinh viên khoa
công nghệ thông tin, hệ thống đăng ký học phần SMS qua môi trường web là một
ứng dụng rất quen thuộc. Chúng tôi muốn phát triển ứng dụng của mình như một
mở rộng của hệ thống đăng ký học phần này trên điện thoại di động nhằm hỗ trợ các
bạn sinh viên có thể sử dụng các tiện ích của hệ thống mà không cần phải có máy

2
Java Mobile

tính kết nối mạng. Với ứng dụng này, tính tiện dụng của hệ thống đăng ký học phần
SMS đã được mở rộng. Chỉ cần có một điện thoại di động hỗ trợ GPRS các bạn sinh
viên có thể đăng ký học phần ngay cả khi đang về quê ăn tết ở những vùng internet
chưa phổ biến nhưng đã phủ sóng di động hay khi đang di chuyển trên tàu xe… Vì
một số điều kiện đặc biệt của điện thoại, hiện nay ứng dụng này chỉ chạy trên
chương trình giả lập. Tuy nhiên, chúng tôi hi vọng trong một tương lai rất gần, khi
các thế hệ điện thoại mới có giá thành vừa phải ra đời và hỗ trợ một số công nghệ
như WebService, mã hoá… mà chúng tôi đang sử dụng để xây dựng phần mềm thì
ứng dụng này có thể được áp dụng rộng rãi trong thực tế cho sinh viên của khoa.
Cần phải nói thêm, ứng dụng hiện tại hoàn toàn có thể sử dụng được trong thực tế
Việt Nam nhưng có một số đòi hỏi về thiết bị khá đắt tiền (xin xem thêm Chương
10, phần Kết Luận), chứ không chỉ mới là lý thuyết trên giấy tờ.
Với việc xây dựng thành công hệ thống đăng ký học phần qua mạng điện
thoại di động, chúng tôi rất tự tin về việc xây dựng các hệ thống thương mại di động
lớn hơn. Trong tương lai gần, khách hàng có thể ngồi trên taxi mua vé máy bay, đặt
chỗ khách sạn, xem lại tài khoản ngân hàng… với chiếc điện thoại di động nhỏ bé.
Chiếc điện thoại di động sẽ trở thành một công cụ giao dịch không thể thiếu trong
thời đại mới, thời đại của thương mại điện tử toàn cầu.
Luận văn được trình bày thành hai phần lớp:
Phần 1: Giới thiệu về lý thuyết nền tảng của J2ME, các thư viện, các kỹ thuật lập
trình, đóng gói ứng dụng di động.
Chương 1. Tổng quan về J2ME : Giới thiệu tổng quan về J2ME, các đặc điểm và
các thành phần con.
Chương 2. Giới thiệu CLDC và MIDP: Trình bày chi tiết về hai thành phần quan
trọng của J2ME dành cho điện thoại di động, môi trường phát triển ứng dụng J2ME.
Chương 3. Các vấn đề cơ bản của chương trình MIDlet: Chương này sẽ trình bày
những đặc điểm quan trọng nhất của một ứng dụng J2ME, các bước cơ bản để xây
dựng ứng dụng này.

3
Java Mobile

Chương 4. Giao diện đồ họa cấp cao: Trình bày về thư viện đồ họa cấp cao như
Form, List, TextBox… trong J2ME.
Chương 5. Giao diện đồ họa cấp thấp: Trình bày về lập trình đồ họa cấp thấp, các
phương thức vẽ, xử lý font, game action … trong J2ME.
Chương 6. Lưu trữ thông tin với RMS: Trình bày về Record Management System,
một cơ chế lưu trữ riêng của J2ME.
Chương 7. Lập trình mạng vơi GCF: Trình bày về khả năng lập trình mạng trong
J2ME.
Phần 2: Giới thiệu về Web Service, một công nghệ rất mới để xây dựng các ứng
dụng thương mại điện tử phân tán và giới thiệu chi tiết về ứng dụng cùng những
đánh giá, tổng kết.
Chương 8. Giới thiệu về ứng dụng phân tán và web service
Chương 9. Trình bày chi tiết về ứng dụng "Đăng Ký Học Phần"
Chương 10. Đánh giá, tổng kết các kết quả đạt được và hướng phát triển trong
tương lai.

Tuy đã đầu tư khá nhiều thì giờ và công sức vào luận văn này nhưng chắc
chắn chúng tôi cũng không tránh khỏi những sai sót. Rất mong nhận được ý kiến
đóng góp và sự thông cảm của quý thầy cô và các bạn! Xin chân thành cảm ơn!

Kim Anh – Anh Tuấn

4
Java Mobile

Phần 1: Kiến thức nền tảng J2ME

Chương 1: Tổng quan về J2ME

1.1 Giới thiệu J2ME (Java 2 Micro Edition)


J2ME là một nhánh của ngôn ngữ lập trình JAVA được phát triển nhằm hướng
tới việc lập trình cho các thiết bị “nhỏ” (micro) có bộ nhớ, khả năng hiển thị và xử
lý hạn chế.
Ban đầu Java được xây dựng chỉ gồm một phiên bản duy nhất, ngày nay được
biết đến với tên J2SE (Java 2 Standard Edition), với phương châm là “viết một lần,
chạy trên mọi môi trường” (“Write once, run anywhere”). Java được hình thành trên
ý tưởng xây dựng một ngôn ngữ mà lập trình viên chỉ cần viết một lần duy nhất
nhưng ứng dụng có thể chạy trên bất cứ môi trường nào có hỗ trợ máy ảo Java (Java
Virtual Machine). Để làm được việc này, Java sử dụng một phương thức biên dịch
mã nguồn tương đối khác so với các ngôn ngữ lập trình truyền thống. Bộ biên dịch
Java không biên dịch mã nguồn trực tiếp sang mã máy mà biên dịch sang một dạng
mã trung gian mà máy ảo Java hiểu được (mã bytecode). Khi có nhu cầu sử dụng
ứng dụng, máy ảo Java sẽ đọc mã trung gian này và dịch ra mã máy và thực thi; nhờ
vào quá trình trung gian đó một ứng dụng Java có thể chạy trên bất kỳ môi trường
nào có cài đặt máy ảo Java tương thích.
Được giới thiệu lần đầu vào năm 1995, ngày nay mục tiêu Java nhắm đến cũng
đã thay đổi khá nhiều. Java hiện nay không chỉ nhắm đến họ máy tính để bàn đơn
thuần; hai năm sau ngày đầu được ra mắt, một phiên bản Java mới là J2EE (Java 2
Enterprise Edition) đã được giới thiệu nhắm tới việc phát triển các ứng dụng có qui
mô lớn hơn.
Phiên bản mới nhất được thêm vào dòng ngôn ngữ Java là J2ME (Java 2 Micro
Edition). J2ME nhắm đến việc phát triển ứng dụng cho các ứng dụng có năng lực
hạn chế như đầu giải mã kỹ thuật số TV set-top boxes, điện thoại di động …

5
Java Mobile

1.2 Lý do chúng ta cần J2ME


Ngày nay ngành công nghiệp sản xuất thiết bị di động trên thế giới đang phát
triển nhanh chóng. Các thiết bị di động ngày càng hiện đại hơn, “thông minh” hơn
và ngày càng có nhiều tính năng nổi bật. Đơn cử như chiếc điện thoại di động, ngày
nay chúng không chỉ đơn thuần đảm nhận chức năng hội thoại mà còn có thêm
nhiều chức năng như chụp ảnh, nghe nhạc, xem phim … như một “trung tâm giải
trí”. Các thiết bị gia dụng khác như lò vi ba, TV… cũng ngày càng được trang bị
những tính năng hiện đại hơn. Nhu cầu phát triển phần mềm cho các thiết bị di
động, gia dụng ngày càng tăng cao và được đánh giá là một ngành công nghệ có thể
đem lại nhiều tỉ đô la doanh thu. Một thực tế đặt ra cho các nhà phát triển phần
mềm trên các thiết bị này là hiện nay không có một chuẩn hóa nào dành cho các nhà
sản xuất phần cứng. Các thiết bị trên thị trường hiện nay rất đa dạng và mang nhiều
đặc điểm cũng như cấu hình khác nhau. Trước thực tế đó, việc có thể chạy trên
nhiều môi trường là một lợi thế rất lớn của ngôn ngữ Java. Các nhà phát triển Java
đã cho ra đời ngôn ngữ J2ME hướng đến việc phát triển phần mềm cho các thiết bị
di động. Ngôn ngữ J2ME thực sự là một ngôn ngữ nhỏ gọn, dễ nắm bắt, chặt chẽ và
thích hợp cho các thiết bị có khả năng hạn chế. Các thiết bị di động trên thị trường
hiện nay, đặc biệt là điện thoại di động hầu hết đều hỗ trợ rất tốt ngôn ngữ J2ME và
J2ME thực sự đã trở thành một trong những ngôn ngữ phổ biến nhất trong lãnh vực
lập trình di động.

Hình 1.1 Các thiết bị J2ME hỗ trợ

6
Java Mobile

1.3 Các thành phần của J2ME:

Hình 1.2 Các thành phần của J2ME


Khái niệm thiết bị di động là tương đối rộng lớn. Chúng bao hàm những thiết bị
có kích thước vật lý khác nhau nhiều lần và cho dù cùng kích thước những thiết bị
này vẫn có khả năng xử lý cũng như hiển thị khác nhau ( những chiếc điện thoại
hiển thị 12,000 pixels cho đến những chiếc PDA 20,000 pixels). Để đáp ứng được
nhu cầu khác nhau của những thiết bị này, bản thân ngôn ngữ J2ME cũng được chia
thành những thành phần nhỏ hơn.
Chúng ta sẽ tìm hiểu hai khái niệm mới là Configurations và Profiles.

1.3.1 Configuration:
Để đáp ứng nhu cầu cho nhiều chủng loại thiết bị khác nhau, Sun đã đưa ra khái
niệm Configuration. Khái niệm Configuration có mối liên hệ chặt chẽ với máy ảo
Java. Nói chính xác hơn, một Configuration qui định những thành phần và những
thư viện gốc của ngôn ngữ Java mà máy ảo phải hỗ trợ cho configuration đó.
Việc phân chia thành những Configurations khác nhau chủ yếu dựa vào khả
năng bộ nhớ, năng lực hiển thị, năng lực xử lý và khả năng kết nối mạng của các
thiết bị. Như chúng ta đã biết, các thiết bị di động rất khác nhau về nguồn tài
nguyên, về khả năng phần cứng. Với những thiết bị có năng lực hạn chế, nếu ta đưa

7
Java Mobile

quá nhiều thư viện hỗ trợ vào máy ảo trên thiết bị đó sẽ gây chậm hệ thống và dư
thừa không cần thiết. Với những thiết bị có khả năng cao hơn, chúng ta sẽ đưa thêm
nhiều thư viện hỗ trợ vào máy ảo giúp ích cho công việc lập trình của các nhà phát
triển. Do đó, nhu cầu phân chia thành nhiều Configurations là việc cần thiết.
Hiện nay Sun đã đưa ra hai loại Configurations khác nhau:
CDC (Connected Device Configuration):
• 512 kb (minimum) bộ nhớ để chạy Java
• 256 kb (minimum) bộ nhớ cấp phát động.
• Kết nối mạng liên tục, băng thông rộng.
CLDC(Connected Limited Device Configuration):
• 128 kb (minimum) bộ nhớ để chạy Java
• 32 kb (minimum) bộ nhớ cấp phát động.
• Giao diện người dùng hạn chế
• Năng lượng tiêu tốn ít (chủ yếu dùng pin)
• Kết nối mạng Wireless, chậm.

Việc phân chia này thực chất cũng chỉ mang tính tương đối. Công nghệ hiện nay
đang phát triển khá nhanh, và việc phát triển này càng làm cho ranh giới giữa các
loại Configuration này trở nên không rõ ràng.

8
Java Mobile

Hình 1.3 Configurations và các thiết bị

1.3.2 Profile:
Configuration thực ra chỉ cung cấp một số rất ít các lớp và người phát triển ứng
dụng hầu như không thể chỉ làm việc đơn thuần với các configuration này. Ta có thể
thấy điều này qua một ví dụ: các configuration không hỗ trợ các công cụ về giao
diện (GUI), do đó nếu chỉ dùng configuration thì lập trình viên phải xây dựng tất cả
các chức năng giao diện từ đầu. Vì lý do này Sun đã linh hoạt và đưa thêm một khái
niệm mới nằm ở tầng trên của configuration, đó là Profiles.
Ta có thể xem Profile là một mở rộng của khái niệm Configuration. Profile định
nghĩa các thư viện giúp lập trình viên phát triển phát triển ứng dụng cho một dạng
thiết bị nào đó. Ví dụ Mobile Information Device Profile (MIDP) định nghĩa các
hàm API cho các thành phần giao diện, nhập liệu và xử lý sự kiện, lưu trữ, kết nối
mạng và xử lý thời gian,… phù hợp với màn hình hiển thị và khả năng xử lý của các
thiết bị di động. Profile MIDP được định nghĩa trên nền tảng của CLDC. Ngoài ra
chúng ta còn một số Profile tiêu biểu khác như
– PDA Profile: tương tự MIDP, nhưng với thị trường là các máy PDA với màn
hình và bộ nhớ lớn hơn

9
Java Mobile

– Foundation Profile: cho phép mở rộng các tính năng của CDC với phần lớn
các thư viện của bộ Core Java2 1.3
– Ngoài ra còn có Personal Basis Profile, Personal Profile, RMI Profile, Game
Profile.
Luận văn chủ yếu chỉ đề cập đến Profile MIDP và các thư viện liên quan để
phục vụ cho việc viết ứng dụng trên điện thoại di động.

1.3.3 Máy ảo Java


Như chúng ta đã biết, một chương trình Java sẽ được biên dịch thành mã trung
gian sau đó chính máy ảo Java sẽ biên dịch phần mã này sang mã máy để thực thi.
Máy ảo Java sẽ chịu trách nhiệm việc cung cấp tính năng bảo mật, cấp phát và thu
hồi bộ nhớ và quản lý việc điều phối các tiến trình. Chúng ta có thể nói chính máy
ảo Java làm cho chương trình của chúng ta “chạy”.
Với CDC, máy ảo Java có cùng các đặc tính như J2SE. Tuy nhiên, với CLDC,
Sun đã phát triển riêng một dạng máy ảo chuyên biệt được gọi là K Virtual
Machine, gọi tắt là KVM. Chính những hạn chế về tài nguyên của các thiết bị di
động đã đề ra nhu cầu về sự ra đời của KVM. KVM không phải là một máy ảo Java
“truyền thống”:
• Máy ảo chỉ cần 40-80 kb bộ nhớ
• Chỉ đòi hỏi 20-40 kb bộ nhớ động (heap)
• Có thể chạy với bộ vi xử lý 16-bit và xung nhịp 25 MHz.

Đến đây chúng ta có thể hình dung phần nào cấu trúc tổng thể của một chương
trình J2ME như sau:

10
Java Mobile

Hình 1.4 Cấu trúc chương trình J2ME


Nếu chương trình được biên dịch với CDC, chương trình sẽ chạy trên các máy
ảo “truyền thống” và mang các đặc tính như chương trình J2SE.
Nếu chương trình được biên dịch với CLDC, chương trình sẽ chạy với máy ảo
chuyên biệt KVM và những đặc tính riêng do CLDC đòi hỏi.
Với chương trình xây dựng bởi MIDP, chúng ta có cấu trúc chuyên biệt sau:

Hình 1.5 Cấu trúc chương trình MIDP


Tầng dưới cùng là hệ điều hành có hỗ trợ máy ảo Java (KVM), bên trên là
CLDC và trên cùng là MID Profile. Lúc này khái niệm “Viết một lần, chạy bất cứ

11
Java Mobile

môi trường nào” của Sun không còn đúng hoàn toàn vì đã xuất hiện máy ảo chuyên
biệt KVM. Một số chương trình viết bằng MIDP sẽ không chạy trên môi trường
J2SE và ngược lại. Tuy nhiên chúng ta phải cảm kích các nỗ lực của Sun đã giúp
cho Java trở thành một trong những ngôn ngữ có khả năng độc lập với môi trường
bên dưới nhất hiện nay, điều này đúng với cả môi trường thiết bị di động.
Ở những phần tiếp theo chúng ta sẽ tìm hiểu kỹ hơn về hai thành phần cơ bản
của J2ME là Configuration và Profile.

12
Java Mobile

Chương 2: Giới thiệu CLDC và MIDP

2.1. CLDC

2.1.1. Yêu cầu phần cứng:


Khi đề ra yêu cầu về phần cứng việc xem xét các chi tiết như bộ xử lý, bộ nhớ…
và các phần mềm hiện có trên các thiết bị di động là việc vô cùng quan trọng. Nhằm
mục đích phục vụ tối đa các thiết bị hiện có trên thị trường, CLDC chỉ đề ra các yêu
cầu về bộ nhớ và không đề ra yêu cầu nào cho các thành phần khác. Yêu cầu tối
thiểu để có thể sử dụng CLDC như sau:
• 128 kilobytes để chạy JVM và các thư viện của CLDC. Không phân biệt loại
bộ nhớ sử dụng (Rom, Flash,…), bộ nhớ của thiết bị phải bảo lưu được nội
dung lâu dài, ngay cả khi ngắt điện. Bộ nhớ này thường được gọi là
nonvolatile memory.
• 32 kilobytes bộ nhớ trống để cấp phát các đối tượng (objects). Bộ nhớ này
thường được gọi là volatile memory (hay là “heap”).

2.1.2. Yêu cầu phần mềm:


CLDC có yêu cầu tối thiểu về mặt phần mềm. Hệ điều hành phải tương thích với
JVM và có chức năng quản lý các ứng dụng Java, bao gồm:
• Cho phép chọn và kích hoạt ứng dụng
• Cho phép gỡ bỏ ứng dụng khỏi thiết bị

2.1.3. Máy ảo Java:


Do các thiết bị di động dùng CLDC thường có tài nguyên hạn chế nên Sun đã đề
ra máy ảo Java KVM phục vụ riêng cho các thiết bị này. Máy ảo KVM thực chất là
một bộ phận con của các máy ảo trên môi trường J2SE và J2EE nên cũng có nhiều
hạn chế và khác biệt so với hai phiên bản trên.

13
Java Mobile

Một số hạn chế:


• Không hỗ trợ kiểu dữ liệu float: Việc sử lý số float đòi hỏi nhiều tài
nguyên xử lý, ngoài ra các thiết bị di động không có những cấu hình phần
cứng dành riêng cho việc xứ lý số float nên trong J2ME chúng ta không
thể khai báo các biến, mảng float, các hàm cũng không nhận tham số và
trả về các số float.
• Phương thức finalize: Trong J2SE, chúng ta có thể khai báo phương thức
finalize (tương tự như phương thức destructor). Garbage Collector sẽ gọi
phương thức này trước khi hủy bỏ một đối tượng, phương thức này
thường được dùng để thu hồi các tài nguyên hệ thống như sockets, file
handles… trước khi đối tượng bị “phá hủy”. Tuy nhiên trong J2ME chúng
ta không có phương thức finalize.
• Error Handling: Trong J2ME chúng ta vẫn được hỗ trợ các công cụ về bẫy
lỗi (chủ yếu thông qua try và catch). Tuy nhiên khả năng về xử lý lỗi của
J2ME cũng hạn chế hơn với hai phiên bản còn lại.
• Không hỗ trợ việc sử dụng code của các ngôn ngữ lập trình khác
• Không hỗ trợ Reflection: Trong J2SE và J2EE, chúng ta có thể dùng các
lớp Reflection để tìm hiểu thông số môi trường máy ảo Java đang thực thi.
• Không hỗ trợ ThreadGroup: mỗi thread được quản lý riêng biệt, không
còn lớp ThreadGroup. Nếu muốn điểu khiển một lúc nhiều threads chúng
ta có thể dùng mảng hoặc Vector.

J2ME cũng còn một số điểm khác biệt so với J2SE và J2EE, một trong những
khác biệt chính là quá trình Class Verify (tạm dịch là “kiểm tra lớp”). Các lớp trước
khi được load sẽ thông qua một quá trình “kiểm tra” về sự hợp lệ và tính nguyên
vẹn. Đây là một cơ chế quan trọng để bảo đảm an toàn (security) của Java. Quá
trình này trong J2SE và J2EE có thể chiếm đến 50 kbytes bộ nhớ, trong J2ME
chúng được chia thành 2 giai đoạn:

14
Java Mobile

• Tiền kiểm tra (Pre-verification): Trước khi một lớp được nạp vào thiết bị,
một phần mềm sẽ được sử dụng để thêm vào một số thông số bổ sung vào
file class. Quá trình này giảm thời gian và bộ nhớ cần thiết để máy ảo thực
hiện giai đoạn 2 trong quá trình kiểm tra. File class sau khi được “tiền
kiểm tra” sẽ tăng dung lượng khoảng 5%
• Kiểm tra nội thiết bị (In-device verification): Khi thiết bị nạp các file class
đã được tiền kiểm tra, công cụ kiểm tra trong thiết bị sẽ thực hiện một vài
kiểm tra để xác nhận tính hợp lệ của đoạn code. Nếu phát hiện một lỗi nào
đó bộ kiểm tra sẽ phát sinh báo cáo và từ chối nạp lớp đối tượng vào bộ
nhớ. Quá trình này đòi hỏi ít bộ nhớ và tài nguyên hơn nhiều lần so với
trong J2SE và J2EE.
CLDC không hỗ trợ tất cả các lớp và thư viện được hỗ trợ trong ngôn ngữ Java
truyền thống mà chỉ hỗ trợ những thư viện thật sự cần thiết đối với thiết bị di động.
Ngoài ra trong CLDC chúng ta cũng được hỗ trợ việc truy vấn một số thuộc tính
của hệ thống:
• Lấy thông tin về platform của thiết bị:
System.getProperty("microedition.platform")
• Lấy thông tin về bảng mã mặc định:
System.getProperty("microedition.encoding")
• Lấy trông tin về version và tên của configuration:
System.getProperty("microedition.configuration")
• Lấy thông tin về Profile:
System.getProperty("microedition.profiles")
Ngoài ra chúng ta có thể truy cập lớp Runtime để lấy các thông số về thiết bị như:
Runtime rtime= Runtime.getRuntime();
System.out.println("Total memory: " + rtime.totalMemory());
//thông tin về tổng bộ nhớ
System.out.println("Free memory: " + rtime.freeMemory());
//thông tin về bộ nhớ trống

15
Java Mobile

2.2. MIDP:

2.2.1. Yêu cầu phần cứng:

• Màn hình ít nhất phải có 96 x 54 pixels


• Có ít nhất một thiết bị nhập liệu: bàn phím hoặc màn hình cảm ứng.
• Có ít nhất 128 kilobytes bộ nhớ non-volatile để chạy các thành phần của MID
• Có ít nhất 8 kilobytes bộ nhớ non-volatile để lưu các cấu hình chương trình và dữ
liệu
• Có ít nhất 32 kilobytes để chạy Java
• Có kết nối không dây (wireless network)

2.2.2. Yêu cầu phần mềm:


Mặc dù hệ điều hành của từng thiết bị có thể khác nhau nhưng phải đáp ứng
được các yêu cầu tối thiểu sau:
• Hệ điều hành phải hỗ trợ việc xử lý ngắt, xử lý exception và hỗ trợ xử lý đồ
họa bitmap để xuất dữ liệu ra màn hình
• Hệ điều hành phải nhận được tín hiệu nhập liệu (input) và chuyển dữ liệu đó
cho máy ảo Java
• Hệ điều hành phải hỗ trợ việc đọc/ghi vào bộ nhớ non-volatile. Không đòi hỏi
hệ điều hành phải định nghĩa file system nhưng phải cho phép ghi dữ liệu dạng
persistent (không bị mất đi khi tắt máy, ngắt điện).
• Phải hỗ trợ truy xuất mạng, đặc biệt phải có tính năng đọc/ghi dữ liệu thông
qua mạng không dây (wireless network).

2.2.3. Cấu trúc MID Profile:

16
Java Mobile

Hình 2.1 Cấu trúc thiết bị MID

Tầng dưới cùng là phần cứng của thiết bị di động. Bên trên phần cứng ta có hệ
điều hành điều khiển các hoạt động.
Bên trên hệ điều hành ta có thể chia thành 2 phần riêng biệt. Chúng ta sẽ thấy
phần bên phải là các chương trình native application (tạm dịch là “chương trình
nguyên gốc”). Trước khi J2ME ra đời, thông thường đây là loại chương trình duy
nhất có trên các thiết bị. Đây là loại chương trình được nhà sản xuất đưa sẵn vào
máy di động lúc sản xuất như chương trình chọn tiếng chuông, chỉnh thông số điện
thoại, chỉnh giờ… Chính nhờ J2ME ra đời chúng ta mới có chức năng cài đặt thêm
các chương trình được viết thêm vào điện thoại.
CLDC là nền tảng cơ bản cho MID Profile, các chương trình MIDP (MIDP
Applications) có thể sử dụng các lớp được cung cấp bởi cả CLDC và MIDP. Ngoài
ra chúng ta còn có các lớp OEM (original equipment manufacturer) là các lớp do
các nhà sản xuất cung cấp thêm cho điện thoại (các hãng như Nokia, Samsung,
Motorola… thường có thêm nhiều lớp cấp cao hỗ trợ cho lập trình viên) và bên trên
là các ứng dụng được xây dựng từ các lớp này, các ứng dụng này thường chỉ chạy
trên các điện thoại của hãng đã cung cấp thư viện lơp OEM.

17
Java Mobile

2.2.4. MIDlet Suite:


Chúng ta gọi chương trình Java chạy trên thiết bị di động là một MIDlet. MIDlet
sẽ sử dụng các lớp cung cấp bởi CLDC và MIDP. Một MIDlet Suite (một bộ
MIDlet) chứa một hay nhiều ứng dụng MIDlet được nén chung trong một file JAR
(Java Archive).
Cấu trúc file Jar:
Ngoài các file lớp và resource, trong file Jar còn có một tập tin được gọi là
manifest. Đây là tập tin mô tả nội dung của toàn file Jar. Tập tin này có tên
manifest.mf và bản thân nó cũng được nén trong file Jar. Trong file manifest chúng
ta có thể định nghĩa các thuộc tính của file jar nhưng quan trọng nhất là 6 thuộc tính
sau:
- MIDlet-Name
- MIDlet-Version
- MIDlet-Vendor
- MIDlet-<n> (mỗi một MIDlet cần một mẫu thông tin này)
- MicroEdition-Profile
- MicroEdition-Configuration
Nếu 1 trong 6 thông tin này thiếu thì thiết bị sẽ từ chối chạy các ứng dụng trong file
Jar này.
Bảng sau mô tả các thuộc tính có thể định nghĩa trong file manifest:
Thuộc tính Mục đích Bắt buộc
MIDlet-Name Tên của bộ MIDlet Có
MIDlet-Version Số phiên bản Có
MIDlet-Vendor Cho biết người tạo MIDlet Suite Có
MIDlet-<n> Tham chiếu đến từng MIDlet trong bộ Có
MIDlet (trong file Jar), mỗi một MIDlet cần
một mẫu tin này, mẫu tin này gồm 3 mẫu tin
con:
Tên MIDlet

18
Java Mobile

File Icon MIDlet (có thể không cần)


Tên lớp sẽ được nạp khi thực thi MIDlet
này
MicroEdition- Tên profile cần thiết để chạy MIDlet này, Có
Profile thường là MIDP1.0 hoặc MIDP2.0
MicroEdition Configuration cần để chạy MIDlet (thường Có
Configuration là CLDC 1.0)
MIDlet-Icon File icon (.pgn) của bộ MIDlet Không
MIDlet-Description Mô tả (text) của bộ MIDlet Không
MIDlet-Info-URL Địa chỉ trang web nhà phát triển MIDlet Không
Bảng 2.1 Cấu trúc file manifest
Đây là một ví dụ đơn giản của file manifest:
MIDlet-Name: Todo List
MIDlet-Version: 1.0
MIDlet-Vendor: Core J2ME
MIDlet-1: TodoList, /images/Todo.png, Todo.TodoMIDlet
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0

File JAD (Java Application Descriptor File):


Bên cạnh file Jar, một bộ ứng dụng MIDlet còn có thêm file JAD (.jad) để cung
cấp thông tin về các MIDlet trong file JAR. Việc đặt ra file JAD có một số mục đích
sau:
• Cung cấp thông tin về nội dung file Jar. Từ thông tin này, bộ quản lý ứng dụng
trên thiết bị mới quyết định ứng dụng này có thích hợp để chạy trên thiết bị hay
không.
• Cung cấp các tham số dùng cho MIDlet để tránh thay đổi file JAR. File JAR
chứa mã ứng dụng nên cần tránh bị thay đổi.

19
Java Mobile

Danh sách các thuộc tính trong file Jad:


Thuộc tính Mục đích Bắt buộc
MIDlet-Name Tên của bộ MIDlet Có
MIDlet-Version Số phiên bản Có
MIDlet-Vendor Cho biết người tạo MIDlet Suite Có
MIDlet-<n> Tham chiếu đến từng MIDlet trong bộ Có
MIDlet (trong file Jar), mỗi một MIDlet cần
một mẫu tin này, mẫu tin này gồm 3 mẫu tin
con:
Tên MIDlet
File Icon MIDlet (có thể không cần)
Tên lớp sẽ được nạp khi thực thi MIDlet
này
MIDlet-Jar-URL Địa chỉ URL của file Jar Có
MIDlet-Jar-Size Kích thước file Jar tính bằng byte Có
MIDlet-Data-Size Kích thước tối thiểu tính bằng byte để ghi Không
các dữ liệu của chương trình (persistent
data)
MIDlet-Description Mô tả MIDlet (dạng text) Không
MIDlet-Delete- Thông báo nhắc nhở khi xóa MIDlet Không
Confirm
MIDlet-Install- URL nhận thông báo về quá trình cài đặt Không
Notify
Bảng 2.2 Cấu trúc file JAD
Ta cũng có thể định nghĩa thêm các thuộc tính riêng, bắt đầu bằng “MIDlet-“ tùy
theo mục đích của lập trình viên. Những thuộc tính sau phải giống nhau ở file Jad
và file manifest (nằm trong file Jar):
- MIDlet-Name
- MIDlet-Version

20
Java Mobile

- MIDlet-Vendor
- MIDlet-<n> for each MIDlet
- MIDlet-Jar-URL
Nếu các thuộc tính này không giống nhau, ứng dụng sẽ bị thiết bị từ chối. Với
các thuộc tính còn lại, nếu file Jad và file manifest khác nhau thì thuộc tính trong
file Jad sẽ được ưu tiên hơn.

Sau đây là một ví dụ đơn giản về file Jad:


MIDlet-Name: Todo List
MIDlet-Version: 1.0
MIDlet-Vendor: Core J2ME
MIDlet-Jar-URL: http://www.corej2me.com/TodoMIDlet.jar
MIDlet-Jar-Size: 17043
MIDlet-1: TodoList, /images/Todo.png, Todo.TodoMIDlet

Ở đây có một câu hỏi được đặt ra: Tại sao phải ghép nhiều ứng dụng MIDlet
thành một file nén dạng JAR. Mục đích của việc kết hợp này giúp cho các ứng dụng
MIDlet được nén chung này có thể chia xẻ chung các tài nguyên với nhau. Một ví
dụ có thể đề cập đến là việc chia sẻ chung các Record Store: trong môi trường
J2ME chúng ta không có khái niệm file system; mọi nhu cầu lưu trữ dữ liệu được
thông qua các Record. Trong một bộ MIDlet Suite thì tên các Record phải phân biệt
và các ứng dụng MIDlet cùng chung trong một bộ sẽ có thể chia sẻ các Record này
với nhau. Điều này khá thuận lợi, nó có thể giúp chúng ta viết các games cùng chia
sẻ danh sách người chơi, danh sách các người chơi có điểm cao nhất…
Khi nạp ứng dụng vào thiết bị ta cùng lúc nạp hai file .Jar và .Jad; file .Jad sẽ là
file thực thi và file .Jar chứa mã thực thi của chương trình

21
Java Mobile

2.2.5. Môi trường phát triển ứng dụng J2ME


Phần này chúng ta sẽ tìm hiểu về các phần mềm cần thiết dùng để phát triển một
ứng dụng J2ME, cách cài đặt và cấu hình các phần mềm này. Ngoài ra chúng ta sẽ
nghiên cứu về các tools phát triển được hỗ trợ thêm.
Để viết một ứng dụng J2ME chúng ta cần ít nhất 3 chương trình sau:
Java Development Kit (JDK) , version 1.3 hoặc cao hơn (phiên bản mới nhất tính
đến lúc luận văn được thực hiện là phiên bản 1.42)
http://java.sun.com/products/jdk/
Connected, Limited Device Configuration (CLDC):
http://java.sun.com/products/cldc
Mobile Information Device Profile(MIDP):
http://java.sun.com/products/midp/
Ghi chú: Ở đây xem Microsoft Windows như hệ điều hành mặc định được sử dụng,
nếu người dùng sử dụng hệ điều hành khác thì phải có một số điều chỉnh phù hợp
với hệ điều hành đó.
Cài đặt các phần mềm:
• Cài đặt JDK:
File cài đặt JDK có dạng file thực thi (.exe), chúng ta chỉ cần chạy và làm theo
các hướng dẫn sẽ cài đặt thành công bộ JDK (giả sử thư mục cài đặt là C:\jdk1.3.1)
Set biến môi trường (Environment Variable):
Việc set biến môi trường giúp chúng ta chạy trình biên dịch từ bất cứ vị trí nào,
không cần phải gõ tên và đường dẫn đầy đủ của trình biên dịch.
– Vào Control Panel, Chọn System.
– Chọn Environment (hoặc Advanced/Environment)
– Tìm mục PATH, thêm thư mục \bin của thư mục JDK (ví dụ C:\JDK\bin)
vào biến môi trường PATH (PATH=…………..;c:\jdk\bin;)
• Cài đặt CLDC và MIDP:
File CLDC và MIDP có dạng zip, ta giải nén vào chung một thư mục (ví dụ
C:\J2ME).

22
Java Mobile

Thư mục J2ME có dạng:


C:\J2ME
j2me_cldc (thư mục chứa CLDC)
midp1.0.1.fcs (thư mục chứa MIDP)
Sau cùng ta set hai biến môi trường PATH và CLASSPATH như sau:
PATH=C:\jdk1.3.1\bin;C:\j2me\j2me_cldc\bin;C:\j2me\midp1.0.3fcs\bin;
CLASSPATH=C:\j2me\midp1.0.3fcs\classes;. (dấu "." chỉ thư mục hiện hành)
Lúc này ta đã đủ công cụ để xây dựng ứng dụng J2ME. Chúng ta có nhiều công cụ
hỗ trợ cho quá trình biên dịch và thực thi MIDlet nhưng ban đầu chúng ta sẽ tìm
hiểu cách sử dụng những công cụ cơ bản nhất và là công cụ chuẩn của J2ME.
Quá trình biên dịch và thực thi ứng dụng J2ME phải qua một số thao tác bằng dòng
lệnh (command lines), chúng ta giả sử thư mục chứa mã nguồn là thư mục
C:\Midlets.
Ta sẽ xây dựng một ứng dụng J2ME đơn giản để mô phỏng quá trình biên dịch và
thực thi, ứng dụng có tên Welcome và file source code có tên Welcome.java
C:\Midlets\Welcome\Welcome.java
• Quá trình biên dịch và Pre-verify:
Để biên dịch ta chuyển đến thư mục chứa ứng dụng (C:\Midlets\Welcome\) và
gọi lệnh:
javac -bootclasspath c:\j2me\midp1.0.3fcs\classes Welcome.java
hoặc
javac –bootclasspath %CLASSPATH% Welcome.java
(CLASSPATH là biến môi trường đã được định nghĩa trước thay cho
c:\j2me\midp1.0.3.fcs\classes;.)
Javac là chương trình biên dịch của bộ JDK, thông số -bootclasspath ra lệnh cho
chương trình dich lấy các file lớp cơ sở tại thư mục c:\j2me\midp1.0.3fcs\classes
(Đây là file lớp cơ sở của MIDP). Nếu không có thông số này, file lớp cơ sở của
JDK sẽ được sử dụng, file lớp cơ sở này khác với file của MIDP nên J2ME có thể
không sử dụng được.

23
Java Mobile

Sau quá trình này file Welcome.class sẽ được tạo ra và mặc địch ở chung thư mục
với file mã nguồn.
Sau khi có file class ta cần thực hiện việc “pre-verify” (đã được đề cập ở phần trước
của luận văn).
Ta thực thi dòng lệnh:
preverify -classpath c:\j2me\midp1.0.3fcs\classes;. -d . Welcome
hoặc
preverify –classpath %CLASSPATH% –d . Welcome
Tương tự, thông số classpath chỉ ra vị chí các file class tại thư mục
c:\j2me\midp1.0.3fcs\classes và thư mục hiện hành (dấu “.”). Thông số -d chỉ ra thư
mục output kết quả là thư mục hiện hành.

Quá trình Pre-verify này là bắt buộc, nếu không thực hiện công đoạn này thiết
bị di động sẽ từ chối thực thi ứng dụng

• Thực thi ứng dụng MIDlet:


Ta thực thi câu lệnh:
midp -classpath . Welcome
Thông số class path chỉ ra thư mục chứa file cần thực thi, ở đây là thư mục hiện
hành, tên ứng dụng là Welcome (file Welcome.class đã được pre – verify).
Trên đây là quá trình cơ bản nhất để biên dịch và thực thi một ứng dụng J2ME,
để sử dụng những tính năng cao hơn (tạo MIDlet Suite chứa nhiều MIDlet, tạo file
Jad, file Jar) xin vui lòng xem file hướng dẫn trong đĩa CD đính kèm hoặc xem tài
liệu của các bộ biên dịch. Để tiết kiệm thời gian, chúng ta thường dùng các công cụ
tiện ích như Sun Wireless Toolkit, xin xem phần phụ lục để biết cách sử dụng.

24
Java Mobile

Chương 3: Các vấn đề cơ bản của chương


trình MIDlet

3.1. Cấu trúc cơ bản:


Chúng ta gọi chung các chương trình J2ME là MIDlet. Các chương trình MIDlet
này đều được kế thừa từ lớp MIDlet. Không giống như chương trình trên máy PC,
các chương trình MIDlet không cần hàm main() để thực thi. Trước hết chúng ta sẽ
xem xét về “vòng đời” (lifecycle) của các ứng dụng MIDlet.
Một chương trình MIDlet khi được nạp vào thiết bị có những trạng thái sau:
– Paused: Một chương trình MIDlet sẽ được đưa vào trạng thái paused sau khi
thực hiện phương thức khởi tạo (constructor) và trước khi được chương trình
quản lý ứng dụng (application manager) trên thiết bị gọi thực thi. Trong quá
trình hoạt động, chương trình MIDlet cũng có thể bị đưa trở lại trạng thái
paused bởi thiết bị (khi cần trả lời cuộc gọi đến …) hoặc bởi chính chương
trình MIDlet.
– Active: Chương trình MIDlet đang thực thi.
– Destroyed: Chương trình MIDlet đã giải phóng tất cả tài nguyên và đã được
tắt bởi trình quản lý ứng dụng trên thiết bị.

3.2. Xây dựng một ứng dụng MIDlet:


Chúng ta xây dựng một ứng dụng MIDlet bằng cách kế thừa (extends) lớp
MIDlet. Lớp này thực chất là một interface và chúng ta phải khai báo ba hàm sau
đây: startApp(), pauseApp() và destroyApp(). Đây là một ví dụ về một chương trình
MIDlet đơn giản:

public class Shell extends MIDlet


{

25
Java Mobile

// phương thức khởi tạo (constructor) không bắt buộc phải có


public Shell(){ … }
// Được application manager gọi trước khi thực thi MIDlet
public void startApp(){…}
// Được gọi trước khi tạm dừng MIDlet
public void pauseApp(){ …}
// Được gọi trước khi kết thúc chương trình
public void destroyApp(boolean unconditional){… }
}

3.3. Lớp MIDlet:


Như đã đề cập, mọi ứng dụng của ta đều kế thừa từ lớp MIDlet. Lơp này được
khai báo như sau:

public abstract class MIDlet {



protected abstract void startApp()
throws MIDletStateChangeException;
protected abstract void pauseApp();
protected abstract void destroyApp(boolean
unconditional) throws
MIDletStateChangeException;
}
Ba hàm được nêu ở trên là ba hàm bắt buộc chúng ta phải xây dựng khi tạo ứng
dụng MIDlet. Lớp MIDlet được chứa trong package javax.microedition.midlet
Sau đây là danh sách các hàm thường dùng trong lớp MIDlet:
Phương thức: Mô tả:
abstract void destroyApp Hàm này được gọi khi có nhu cầu tắt MIDlet. Đây
(boolean unconditional) là nơi giải phóng các tài nguyên đã dùng.
abstract void pauseApp() Hàm này được gọi để giải phóng các tài nguyên

26
Java Mobile

trước khi tạm dừng chương trình.


abstract void startApp() Được gọi khi MIDlet sắp được đưa vào trạng thái
thực thi (active state).
final void notifyDestroyed() Báo cho application manager biết chương trình
MIDlet đã giải phóng tài nguyên và cần được tắt.
(sau khi gọi destroyApp)
final void notifyPause() Báo cho application manager biết chương trình
MIDlet đã giải phóng tài nguyên và muốn vào trạng
thái tạm dừng (sau khi gọi pauseApp)
final void resumeRequest() Báo cho application manager ta cần đưa MIDlet
vào trạng thái hoạt động trở lại. (Sau đó application
manager sẽ gọi startApp).
final String getAppProperty Lấy các thông số của chương trình (từ file jad và
(String key) file manifest).
Bảng 3.1 Lớp MIDlet
Ở đây chúng tôi xin mô tả hai quá trình quan trọng nhất của một ứng dụng MIDlet
là quá trình khởi nạp và quá trình thoát ứng dụng:
– Quá trình nạp:
• User chọn kích hoạt ứng dụng MIDlet
• Application manager khởi tạo các biến, gọi phương thức khởi tạo
(constructor).
• Ứng dụng MIDlet sau khi được nạp vào bộ nhớ sẽ được đưa vào trạng thái
paused (nhưng hàm pauseApp() sẽ không được gọi).
• Application manager gọi hàm startApp(). Thực chất hàm startApp() sẽ
được gọi mỗi khi ứng dụng được đưa vào trạng thái thực thi (active); khi ta
tạm ngưng ứng dụng và có nhu cầu kích hoạt trở lại hàm này cũng được
gọi.
– Quá trình thoát:
• User chọn thoát chương trình

27
Java Mobile

• Hàm destroyApp() được gọi, hàm này phải bảo đảm việc giải phóng tài
nguyên.
• Hàm notifyDestroyed() được gọi để báo cho application manager ứng dụng
đã giải phóng hết tài nguyên và sẵn sàng bị tắt.

3.4. Lớp MIDletStateChangeException:


Khi tìm hiểu về package javax.microedition.midlet, còn một lớp quan trọng
chúng ta phải chú ý đến là lớp MIDletStateChangeException. Ứng dụng MIDlet có
hai hàm có khả năng tạo ra (throw) Exception này là hàm destroyApp() và hàm
startApp().
Như chúng ta đã biết, trước khi ứng dụng được đưa vào trạng thái active thì hàm
startApp() sẽ được gọi. Nếu trong quá trình gọi hàm này dẫn đến phát sinh lỗi (thiết
bị hết tài nguyên, tài nguyên cần dùng đang bị ứng dụng khác chiếm…) thì
MIDletStateChangeException sẽ được tạo ra. Trong quá trình thoát, hàm
destroyApp() cũng có thể phát sinh exception này, ví dụ như khi chúng ta thoát mà
chương trình đang nhận dữ liệu hết sức quan trọng từ network ta có thể phát sinh
exception để dừng việc thoát.
Ta xem xét hàm destroyApp(boolean condition):
Tham số condition ở đây có một ý nghĩa khá thú vị, nếu tham số này là true dù
chúng ta có phát sinh exception MIDletStateChangeException thì ứng dụng vẫn
thoát; chỉ khi nào tham số này là false thì exception MIDletStateChangeException
mới có khả năng hủy việc thoát chương trình.

3.5. Display
Ứng dụng của chúng ta chắc chắn có nhu cầu xuất dữ liệu ra màn hình. Việc
này trong một ứng dụng MIDlet do một đối tượng thuộc lớp display đảm nhiệm.
Lớp này nằm trong package javax.microedition.lcdui, package này chứa hầu như tất
cả các lớp phục vụ cho việc phát triển giao diện của ứng dụng.
Chúng ta sẽ xem xét một số hàm quan trọng nhất của lớp Display:

28
Java Mobile

Phương thức: Mô tả:


static Display getDisplay(MIDlet m) Lấy đối tượng Display của MIDlet
Displayable getCurrent() Lấy đối tượng Displayable hiện thời (sẽ đề
cập sau)
void setCurrent (Alert alert, Tạo đối tượng alert (sẽ đề cập sau)
Displayable nextDisplayable)
void setCurrent (Displayable
nextDisplayable)
boolean isColor() Cho biết thiết bị có hỗ trợ màu hay không?
int numColors() Có bao nhiêu màu được hỗ trợ?
Bảng 3.2 Lớp Display
Một MIDlet sẽ có một và chỉ một đối tượng Display để điều khiển việc thể hiện dữ
liệu. Đối tượng Display không có phương thức khởi tạo mà được khởi tạo trực tiếp
từ phương thức static của lớp.
Ví dụ:
Display display=Display.getDisplay(this);
Tham số đầu vào là một MIDlet, ở đây chúng ta gọi hàm từ lớp kế thừa từ
MIDlet nên có thể truyền vào con trỏ this. Thực ra công dụng chính của Display là
cho phép hiển thị đối tượng nào lên màn hình hiện thời. Các đối tượng có thể hiển
thị lên màn hình là các đối tượng thuộc lớp Displayable (sẽ được giới thiệu sau), ví
dụ như form, TextBox, Canvas,Screen…
Ta xét ví dụ sau:
public class Vidu extends MIDlet
{
Form mainForm;

Vidu{
mainForm=new Form(…….);
}

29
Java Mobile

public void startApp()


{
………
Display display=Display.getDisplay(this);
Display.setCurrent(mainFrom);
……….
}
………………………….
}

Ban đầu ta khởi tạo một form để thể hiện lên màn hình, sau khi ứng dụng
MIDlet được nạp vào bộ nhớ constructor được gọi để tạo form. Sau đó, phương
thức startApp() được gọi, trong phương thức này ta chọn Form mainForm để thể
hiện lên màn hình bằng lệnh setCurrent. Khi ứng dụng bị tạm ngưng (paused) và
phục hồi trở lại (resume) thì hàm startApp() cũng được gọi và form lại được thể
hiện trên màn hình. Đến đây chúng ta có thể hình dung được phần nào tác dụng của
đối tượng Display.

3.6. Lớp Displayable:


Như đã đề cập, một ứng dụng MIDlet chỉ có một đối tượng Display duy nhất và
đối tượng Display này dùng để thể hiện các đối tượng Displayable lên màn hình.
Như tên của lớp Displayable cho chúng ta thấy, đây là các đối tượng có khả năng
hiển thị thông tin lên màn hình thiết bị. Lớp Displayable bao gồm 2 lớp con là lớp
Screen và lớp Canvas. Cụ thể chúng được định nghĩa như sau:

abstract public class Displayable;


public abstract class Canvas extends Displayable;
public abstract class Screen extends Displayable;

30
Java Mobile

Lớp Screen còn được chia thành những lớp con nhỏ hơn như: TextBox, List,
Form và Alert. Đây là những lớp giao diện cấp cao (vì phần lớn các công việc thể
hiện của các lớp này đã được cài đặt sẵn). Các đối tượng của lớp Canvas được gọi là
những đối tượng đồ họa cấp thấp, các lớp này cho phép chúng ta xử lý các giao tác
đồ họa ở tầng dưới, xử lý màu sắc và chủ yếu dùng trong quá trình viết games. Ở
những phần sau chúng ta sẽ tìm hiểu kỹ hơn về các lớp giao diện ở cấp thấp lẫn cấp
cao.

* Tạo một đối tượng Displayable:


Thông thường chúng ta không tạo trực tiếp một đối tượng thuộc lớp Displayable
mà sử dụng các lớp con của nó. Để viết các ứng dụng đồ họa ta thường kế thừa từ
lớp Canvas:

public class GameScreen extends Canvas


{
draw images, shapes, text …
}

Khi xây dựng các ứng dụng tiện ích (ít dùng đến các chức năng đồ họa) ta sẽ dùng
các lớp đồ họa cấp cao như Form, TextBox … hoặc kế thừa từ các lớp này.

Các hàm chính của lớp Displayable:


Phương thức: Mô tả:
void addCommand(Command cmd) Thêm một đối tượng Command vào đối
tượng Displayable
void removeCommand (Command Xóa bỏ một đối tượng Command từ đối
cmd) tượng Displayable
void setCommandListener Thêm CommandListener vào đối tượng
(CommandListener l) Displayble

31
Java Mobile

boolean isShown() Kiểm tra đối tượng Displayable có được


thể hiện trên thiết bị hay không?
Bảng 3.3 Lớp Displayable
*Ghi chú: Các đối tượng Command và CommandListener sẽ được đề cập chi tiết ở
phần sau.

Tại thời điểm này chúng ta có thể hình dung một Command như một nút ấn điều
khiển trong ứng dụng của chúng ta, CommandListener có tác dụng chuyển các sự
kiện khi người dùng kích hoạt một Command đến lớp xử lý của ứng dụng. Để “bắt”
được các sự kiện được chuyển tới khi người dùng kích hoạt một Command, ứng
dụng của chúng ta phải cài đặt hàm commandAction. Ví dụ như sau:

public void commandAction(Command c, Displayable s)


{
if (c == cmExit)
{
destroyApp(true);
notifyDestroyed();
}
}

3.7. Quản lý các sự kiện (event)


Ngày nay, việc xử lý sự kiện là một trong những vấn đề cơ bản nhất của một
chương trình. Có thể nói, trong thế giới phần mềm ngày nay không một chương
trình nào lại không có khả năng tương tác với người dùng, do đó việc quản lý các sự
kiện phát sinh là một vấn đề mà bất cứ phần mềm nào cũng phải thực hiện. Quá
trình xử lý các sự kiện phát sinh bao gồm 3 quá trình cơ bản:
• Phần cứng (thiết bị di động) phải cảm nhận được khi có một sự kiện phát
sinh: người dùng ấn một phím, một cable được cắm vào hay rút ra.

32
Java Mobile

• Phần mềm trên thiết bị (hệ điều hành) phải nhận biết được có sự kiện phát
sinh
• Hệ điều hành chuyển thông tin về sự kiện cho ứng dụng, bắt đầu từ đây là
công việc của những lập trình viên J2ME. Tùy theo các thông tin về sự
kiện mà chúng ta phải đưa ra các giải pháp thích hợp

Trong phần này chúng ta sẽ chỉ nghiên cứu về các sự kiện được phát sinh ở
những ứng dụng sử dụng các chức năng đồ họa ở mức cao (Form, TextBox…), còn
các sự kiện phát sinh ở những ứng dụng sử dụng các thư viện đồ họa ở mức thấp
như các games sẽ được đề cập sau.
Thực chất để nhận được thông báo từ hệ điều hành về các sự kiện phát sinh lớp
ứng dụng chính của chúng ta phải cài đặt (implement) các “listener”. Trong J2ME
hỗ trợ sẵn cho chúng ta 2 listener là CommandListener và ItemStateListener. Lớp
CommandListener có hàm commandListener() và tương ứng lớp ItemStateListener
có hàm itemStateChange(), đây là 2 hàm chúng ta cần cài đặt để nhận biết các sự
kiện xảy ra. Trước khi đi sâu vào xử lý các sự kiện chúng ta sẽ tìm hiểu 2 tác nhân
chính phát sinh một sự kiện là Command và Item.

3.7.1. Command & CommandListener


Ta định nghĩa Command là một đối tượng giữ thông tin về một sự kiện (Event).
Nói một cách đơn giản nhất thì command như một nút ấn (button) trên ứng dụng di
động, khi ta chọn nút này thì sẽ phát sinh một sự kiện tương ứng.

33
Java Mobile

Hình 3.1 Command Exit

Trong ví dụ trên ta thấy Command “Exit” tương ứng với một nút ấn trên điện
thoại. Việc xem một Command tương ứng với một nút ấn trên thiết bị là một quan
niệm nhằm đơn giản hóa vấn đề nhưng không hoàn toàn chính xác. Nếu chúng ta
xem xét các hạn chế về kích thước về màn hình và số lượng nút ấn có trên thiết bị
thì vấn đề sẽ trở nên phức tạp hơn, có những form số lượng command có thể nhiều
hơn số nút ấn chức năng trên thiết bị, lúc này các command được tổ chức theo dạng
menu. Trước tiên, ta sẽ tìm hiểu các công việc phải làm để thêm một command vào
ứng dụng:
• Tạo một command để lưu giữ thông tin về event
• Thêm command này vào Form, TextBox hay Alert… (các đối tượng
displayable)
• Thêm một listener vào các Form hay TextBox … trên.
Khi phát hiện một event được kích hoạt, bộ listener sẽ gọi hàm commandListener()
và truyền các thông tin về event làm thông số cho hàm. Sau đây là một đoạn code ví
dụ:
public class TestCommand extends MIDlet implements CommandListener
{

34
Java Mobile

private Form fmMain; // Tạo một form


private Command cmExit; // Tạo một command để thoát khỏi ứng dụng
...
fmMain = new Form("Core J2ME"); // Khởi tạo form
cmExit = new Command("Exit", Command.EXIT, 1); // Khởi tạo command
...
fmMain.addCommand(cmExit); // Thêm command vào form
fmMain.setCommandListener(this); // Thêm bộ listener cho form
...
//hàm dùng để bắt các sự kiện
public void commandAction(Command c, Displayable s)
{
if (c == cmExit)//nếu là command exit, thoát chương trình
{
destroyApp(true);
notifyDestroyed();
}
}
}

Qua ví dụ trên ta thấy việc tạo một command và xử lý nó tương đối đơn giản.
Điểm quan trọng cần chú ý là lớp ứng dụng của ta phải cài đặt một bộ listener
(trong ví dụ trên ta implements CommandListener) và phải cung cấp hàm
commandListener để xử lý các events.
Khi chúng ta tạo một Command có ba thông số cần cung cấp:

35
Java Mobile

Label: Đoạn văn bản được xem như nhãn của command. Như trong hình 3.1, “Exit”
là nhãn của command. Như trong hình 3.2, ta thấy đây cũng là label của command
nhưng được thể hiện ở dạng khác: dạng menu.

Hình 3.2 Command Label


Type: Thật thuận tiện nếu ta có thể ánh xạ một command với một nút trên thiết bị
(ta gọi là “soft-button”). Giả sử ta có một command tên help và ánh xạ được với
HELP Button trên thiết bị thì thật trực quan và dễ dàng cho người dùng.
Thông số Type giúp chúng ta làm chuyện này: Ta chọn Command.HELP. Nếu thiết
bị không có nút help, thông số này không có ý nghĩa và command được đối xử như
các command thông thường. Tuy nhiên, ta cần lưu ý khi ta tặt type là
Command.HELP thì không có nghĩa khi ta chọn command này các hướng dẫn sẽ
được phát sinh mà ta cần phải làm việc này trong hàm commandAction(). Thông số
type chỉ giúp việc ánh xạ các nút soft-button được dễ dàng.

Hình 3.3 Ánh xạ soft-button

36
Java Mobile

Các type được hỗ trợ:


Giá trị Mô tả
BACK Dùng để đi ngược lại màn hình trước đó.
CANCEL Dùng để hủy công việc đang thực hiện
EXIT Dùng để thoát chương trình
HELP Cung cấp thông tin trợ giúp
ITEM Dùng để ánh xạ một Command với một item trên màn hình. Giả
sử khi ta dùng giao diện List, khi chọn một item ta có thể gắn item
này với một command để phát sinh một sự kiện nào đó.
OK Xác nhận một yêu cầu nào đó hoặc thoát khỏi màn hình thông
báo.
SCREEN Thông thường thiết bị không có các soft button tương ứng với các
command dạng này. Việc thể hiện các command sẽ tùy vào từng
thiết bị (sẽ có các ví dụ)
STOP Dừng một công việc đang thực hiện.
Bảng 3.4 Các Command Type
Như đã đề cập, các type chỉ có ý nghĩa khi thiết bị có một nút tương ứng dành
riêng cho type này (như nút help của thiết bị hình 3.3).
Priority: Độ ưu tiên, dùng để sắp xếp các command từ trên xuống dưới hay trái sang
phải khi được thể hiện chung dạng menu. Hình 3.2 thể hiện command Upload có độ
ưu tiên cao hơn command Download. Giá trị này càng cao thì độ ưu tiên càng thấp.
Sau đây là các hàm chính của lớp Command và CommandListener (hai lớp này nằm
trong package javax.microedition.lcdui).
Lớp javax.microedition.lcdui.Command
Cú pháp Ý nghĩa
Command (String label, int Hàm khởi tạo, các thông số đã được trình bày
cmdType, int priority) bên trên
int getCommandType() Cho biết Type của Command

37
Java Mobile

int getLabel() Cho biết Label của Command


int getPriority() Cho biết độ ưu tiên
Lớp javax.microedition.lcdui.CommandListener
void commandAction(Command Được gọi khi command c nằm trên đối tượng
c, Displayable d) Displayable d phát sinh một sự kiện
Bảng 3.5 Command và CommandListener

3.7.2. Item và ItemStateListener


Sự kiện (event) không chỉ được phát sinh thông qua kích hoạt commands mà
còn có thể được phát sinh thông qua các items. Một item là một bộ phận có thể gắn
kèm lên trên các form. ChoiceGroup, DateField, Gauge và TextField là các dạng
khác nhau của Item và mỗi dạng đều có thể phát sinh các sự kiện (chúng ta sẽ tìm
hiểu về các items này trong phần Đồ Họa Cấp Cao). Items chỉ có thể được sử dụng
như một thành phần của form, khác với Commands có thể được sử dụng trong
Form, TextBox, List và Canvas.
Khi chúng ta thêm một Item vào Form, để xử lý được các sự kiện phát sinh ta
phải cài đặt một Listener (ở đây là ItemStateListener). Khi có một thay đổi trên Item
(ví dụ như ta chọn một mục trong ChoiceGroup hay thay đổi dữ liệu của một
DateField) thì đối tượng listener sẽ được thông báo có một sự kiện phát sinh cùng
các thông tin về sự kiện này. Sự kiện này sẽ kích hoạt hàm itemStateChanged()
được chúng ta cài đặt.
Hiện tại MIDP hỗ trợ các loại Items sau: ChoiceGroup, DateField, Gauge,
ImageItem, StringItem và TextField. Ở đây có một ngoại lệ là hai loại StringItem và
ImageItem không hỗ trợ phát sinh sự kiện mặc dù chúng là lớp con của lớp Item.
Chúng ta cài đặt một listener trong lớp Form, khi một Item phát sinh sẽ kích hoạt
hàm itemStateChanged(), tuy nhiên không phải khi chúng ta thay đổi giá trị nhiều
items cùng lúc thì itemStateChanged() sẽ được gọi đủ bấy nhiêu lần. Ở đây có một
luật được đề ra:

38
Java Mobile

• Nếu một Item bị thay đổi, hàm itemStateChanged() phải được gọi đối với
Item này trước khi những thay đổi trên những Item sau đó được nhận
biết.
• Nếu chính bản thân MIDlet thay đổi giá trị một Item (giả sử chúng ta dùng
mã lệnh để thay đổi chứ không phải do người dùng), hàm
itemStateChanged() không được gọi.
• Nếu thiết bị nhận biết được người dùng chuyển từ Item này sang Item
khác (chuyển focus) thì hàm itemStateChanged() phải được gọi trước khi
chuyển sang Item kế tiếp.

Sau đây là các hàm quan trọng khi sử dụng Item:


Lớp javax.microedition.lcdui.Item
Cú pháp Ý nghĩa
String getLabel() Lấy nhãn của Item
void setLabel(String label) Đặt nhãn cho label
Lớp javax.microedition.lcdui.ItemStateListener
void itemStateChanged(Item item) Được gọi khi giá trị item thay đổi
Bảng 3.6 Item và ItemStateListener

39
Java Mobile

Chương 4: Giao diện đồ họa cấp cao

MIDP hỗ trợ thiết kế giao diện dưới hai cấp độ:


• Giao diện cấp cao (high-level interfaces): chủ yếu dùng cho các chương trình ứng
dụng. Ở cấp độ này, MIDP cung cấp sẵn các thành phần giao diện thường dùng
(như textbox, choicegroup, alert...) và hỗ trợ việc hiển thị các thành phần giao
diện này lên màn hình thiết bị. Người viết chương trình chỉ cần gọi các phương
thức hiển thị đã được cung cấp mà không cần quan tâm đến các phương thức đồ
hoạ đã được sử dụng bên dưới.
• Giao diện cấp thấp (low-level interfaces): chủ yếu sử dụng trong các chương
trình games. Các lớp đồ hoạ ở cấp độ này cung cấp các phương thức vẽ trực tiếp
các đối tượng đồ hoạ (như điểm, đường thẳng, đường tròn...)lên màn hình và bắt
sự kiện phím bấm.
Tất cả các lớp hỗ trợ đồ hoạ được đóng gói trong package javax.microedition.cldui.
Trong đó, lớp Screen và các lớp kế thừa từ nó là các thành phần giao diện cấp cao;
lớp Canvas thuộc phần giao diện cấp thấp.

Hình 4.1 Sơ đồ các lớp giao diện đồ hoạ

40
Java Mobile

public class Display


public abstract class Displayable
public abstract class Screen extends Displayable
public abstract class TextBox extends Screen
public abstract class List extends Screen

public abstract class Item


public class ChoiceGroup extends Item implements Choice
public class DateField extends Item
public class TextField extends Item
public class Gauge extends Item
public class ImageItem extends Item
public class StringItem extends Item

pubilc abstract class Canvas extends Displayable


public class Command
public class Ticker
public class Graphics
public interface Choice

41
Java Mobile

4.1. Screen:
Lớp Screen không được sử dụng trực tiếp như một đối tượng trong chương trình
mà các lớp con của nó (Textbox, List, Alert, Form) mới là các thành phần hiển thị
trên màn hình. Tại một thời điểm chỉ có duy nhất một đối tượng thuộc một trong
các lớp này hiển thị trên màn hình. Đây là điểm khác biệt khi so sánh với các lớp
con của lớp Item sau này.
Lớp Screen cũng định nghĩa sẵn một đối tượng Ticker kết buộc với nó. Đối tượng
này thể hiện một chuỗi ký tự tự động cuộn liên tục từ phải sang trái màn hình.

Các phương thức và chức năng tương ứng của lớp Screen:
Lớp Screen: javax.microedition.lcdui.Screen
Phương thức Chức năng
String getTitle () Lấy tiêu đề của Screen
void setTitle (String s) Gán tiêu đề cho Screen
Ticker getTicker () Lấy biến Ticker của Screen
void setTicker (Ticker ticker) Gán biến Ticker cho Screen
Bảng 4.1 Lớp Screen

42
Java Mobile

4.2. Form:
Form là lớp thông dụng nhất trong các đối tượng Displayable. Nếu khi sử dụng
Texbox, List, Alert, ta chỉ có thể hiển thị một đối tượng duy nhất tại một thời điểm
thì khi sử dụng Form, chúng ta có thể hiển thị nhiều đối tượng có chức năng tương
tự tại cùng một thời điểm. Để làm được điều này, ta chỉ cần tạo một đối tượng thuộc
lớp Form và gắn vào đối tượng này một hay nhiều đối tượng thuộc lớp con của lớp
Item (TextField, DateField, ChoiceGroup, Gauge, ImageItem, StringItem). Lớp
Form cũng hỗ trợ sẵn chức năng cuộn màn hình nếu thiết bị không hiển thị hết tất cả
các Item trong một màn hình.
Lớp Form hỗ trợ sẵn các phương thức thêm, xoá, sửa các thành phần trong Form
một cách dễ dàng. Khi gắn một đối tượng thành phần - một đối tượng thuộc lớp con
của Item - vào Form, ta sẽ nhận được một giá trị trả về tương ứng với chỉ mục của
thành phần đó trong Form. Với chỉ mục này, ta có thể tham chiếu đến thành phần
này khi cần tra cứu hay thay đổi thông tin đối tượng.
Các phương thức và chức năng tương ứng của lớp Form:
Lớp Form: javax.microedition.lcdui.Form
Phương thức Chức năng
Form (String title) Khởi tạo một Form
Form (String title, Item[] items) Khởi tạo một Form và thêm các Item vào
Form
int append (Image image) Thêm một biến Image vào Form
int append (Item item) Thêm một biến Item vào Form
int append (String string) Thêm một biến String vào Form
void delete (int itemNum) Xoá một Item khi biết chỉ mục của nó
void insert (int itemNum, Item item) Chèn một Item vào vị trí chỉ mục cho trước
Item getItem (int ItemNum) Lấy một biến Item khi biết chỉ mục của nó
void set (int itemNum, Item item) Thay biến Item ở chỉ mục cho trước bằng
biến Item mới

43
Java Mobile

void setItemStateListener( Thêm biến Listener vào Form


ItemStateListener iListener)
int size () Lấy số Item trong Form
Bảng 4.2 Lớp Form

44
Java Mobile

4.3. Item:
Một Item là một thành phần có thể thêm vào Form. Các lớp con của Item gồm:
ChoiceGroup, DateField, TextField, Gauge, ImageItem và StringItem.
Item thường được dùng chung với lớp ItemStateListener. Khi muốn bắt sự kiện
của 1 Item, ta chỉ cần kết buộc Item đó với 1 biến listener thuộc lớp
ItemStateListener. Biến listener này sẽ lắng nghe các sự kiện và tự gọi phương thức
itemStateChanged() khi Item kết buộc với nó có sự thay đổi. Trong phương thức
này, ta có thể viết xử lý cho các sự kiện cần bắt của Item.

Vd: tạo 1 DateField cho Form và gắn biến listener để bắt sự kiện:
private Form fmMain;
private DateField fdToday;
...
fmMain = new Form (“Core J2ME”);
dfToday = new DateField (“Today: ”, DateField.DATE);
...
public void itemStateChanged(Item item) {
if (item == dfToday)
//xử lý
}

Các phương thức và chức năng tương ứng của lớp Item:
Lớp Item: javax.microedition.lcdui.Item
Phương thức Chức năng
String getLabel () Lấy nhãn của Item
void setLabel (String label) Gán nhãn cho Item
Bảng 4.3 Lớp Item

45
Java Mobile

4.3.1. DateField:
Dùng để hiển thị một đối tượng ngày giờ (java.util.Date) và cho phép người
dùng thay đổi giá trị ngày giờ này bằng các phím bấm của thiết bị di động. Giao
diện DateField dễ dùng, khi tạo mới một đối tượng DateField, ta có thể lựa chọn
cho phép người dùng chỉ thay đổi giá trị ngày tháng, giờ phút hay cả hai :

Hình 4.2 Giao diện đối tượng DateField

Các phương thức và chức năng tương ứng của lớp DateField:
Lớp DateField: javax.microedition.lcdui.Date
Phương thức Chức năng
DateField (String label, int mode) Khởi tạo một đối tượng DateField
DateField (String label, int mode, Khởi tạo một đối tượng DateField với
TimeZone timeZone) múi giờ cho trước
Date getDate () Lấy giá trị ngày tháng của đối tượng
void setDate (Date date) Gán giá trị ngày tháng của đối tượng
int getInputMode () Lấy thông tin kiểu nhập liệu
void setInputMode () Gán kiểu nhập liệu
Bảng 4.4 Lớp DateField
Có thể chọn 1 trong 3 kiểu nhập liệu cho đối tượng DateField:
• DATE: chỉ cho phép người dùng thay đổi giá trị ngày tháng
• TIME: chỉ cho phép người dùng thay đổi giá trị giờ phút

46
Java Mobile

• DATE_TIME: cho phép người dùng thay đổi giá trị cả ngày tháng lẫn
giờ phút
VD:
//tạo 1 biến DateField cho phép người dùng nhập ngày tháng
DateField dfDate = new DateField(“Ngay thang”,DateField.DATE);
//gán ngày tháng hiện thời cho biến dfDate
dfDate.setDate(new Date());
//cho phép người dùng thay đổi thông tin ngày tháng và giờ phút
dfDate.setInputMode(DateField.DATE_TIME);
....
//lấy thông tin ngày tháng của biến dfDate (thường để lấy giá trị mới mà người dùng vừa nhập )
Date dNewDate=new Date;
dNewDate=dfDate.getDate();

47
Java Mobile

4.3.2. Gauge:
Gauge dùng để biểu diễn tiến độ hoàn thành một việc nào đó (download, upload...)
hoặc cấp độ từ thấp đến cao (của âm lượng, độ khó...). Gauge đặc trưng bởi hai giá
trị: giá trị hiện hành và giá trị cực đại cho phép. Giá trị hiện hành này luôn được duy
trì giữa 0 và giá trị cực đại. Gauge gồm hai dạng:
• Chế độ tương tác (Interactive mode): Trong chế độ này, đối tượng
Gauge sẽ được vẽ dạng các thanh song song có chiều cao tăng dần
biểu thị các cấp độ từ thấp đến cao. Người sử dụng có thể điều chỉnh
giá trị hiện thời của Gauge bằng các phím bấm. VD: điều chỉnh âm
lượng cao thấp.

Hình 4.3 Giao diện đối tượng Gauge chế độ tương tác

• Chế độ không tương tác (Non-interactive mode): Đối tượng được biểu
diễn dạng các thanh song song có chiều cao bằng nhau, người dùng
không được phép thay đổi giá trị của nó. Người lập trình sẽ lập trình
cho đối tượng này tự động cập nhật giá trị theo thời gian.

48
Java Mobile

Hình 4.4 Giao diện đối tượng Gauge chế độ không tương tác

Các phương thức và chức năng tương ứng của lớp Gauge:
Lớp Gauge: javax.microedition.lcdui.Gauge
Phương thức Chức năng
Gauge (String label, boolean interactive, Khởi tạo một đối tượng Gauge
int maxValue, int initValue)
int getValue () Lấy giá trị hiện thời của Gauge
void setValue (int value) Gán giá trị cho đối tượng Gauge
int getMaxValue () Lấy giá trị cực đại cho phép của Gauge
void setMaxValue (int maxValue) Gán giá trị cực đại cho phép cho
Gauge
boolean isInteractive () Kiểm tra Gauge có thuộc chế độ tương
tác không
Bảng 4.5 Lớp Gauge
VD:
//tạo 1 biến Gauge cho phép người dùng điều chỉnh âm thanh (chế độ tương tác)
Gauge gVolume= new Gauge (“Volume”, true, 6, 2);
//gắn Gauge vào Form
fmMain.append(gVolume);
fmMain.setCommandListener(this);

49
Java Mobile

//tạo 1 biến Gauge biểu diễn tiến trình Download (chế độ không tương tác):
Gauge gDownload = new Gauge(“Download Progress”, false, 20,1);
//gắn Gauge vào Form
fmMain.append(gDownload);
fmMain.setCommandListener(this);
//cập nhật giá trị liên tục cho Gauge bằng cách sử dụng 1 biến timer
//khoảng cách mỗi lần cập nhật là 1000 mili giây
Timer tTimer = new Timer();
DTTask ttTimerTask = new DTTask(); //class DTTask extends TimerTask
tTimer.scheduleAtFixedRate (ttTimerTask, 0, 1000);

//lớp DDTask được viết bên trong MIDlet


private class DTTask extends TimerTask{
public final void run () {
//nếu giá trị hiện tại của gDownload < giá trị cực đại thì tiếp tục tăng, không thì
dừng lại
if (gDownload.getValue() < gDownload.getMaxValue())
gDownload.setValue(gDownload.getValue()+1);
else
cancel(); //xoá bộ định thời

}
}

50
Java Mobile

4.3.3. String Item:


Đối tượng StringItem dùng để hiển thị 1 đoạn văn bản lên màn hình. Người dùng
chỉ đựơc phép xem mà không được thay đổi nội dung đoạn văn bản này.

Các phương thức và chức năng tương ứng của lớp StringItem:
Lớp StringItem: javax.microedition.lcdui.StringItem
Phương thức Chức năng
StringItem (String label, String text) Khởi tạo một đối tượng StringItem
String getText () Lấy nội dung đoạn văn bản
void setText (String text) Gán nội dung đoạn văn bản cần hiển thị
Bảng 4.6 Lớp StringItem
Để lấy giá trị nhãn (label) hay thay đổi nội dung nhãn có thể dùng các phương thức
getLabel(), setLabel(String label) của lớp Item.
VD:
//tạo một đối tượng StringItem
StringItem siText = new StringItem(“User: ”, “John”);
//gắn vào form
fmMain.append(siText);
...
//sau đó muốn hiển thị 1 nội dung khác, chỉ cần thay đổi label và text của đối tượng,
//không cần tạo 1 đối tượng StringItem mới.
siText.setLabel(“UserID: ”);
siText.setText(“12345”);

51
Java Mobile

Hình 4.5 Giao diện đối tượng StringItem


Đối tượng lớp String cũng có thể append() vào Form để hiển thị 1 đoạn văn bản
nhưng không có hai phần nhãn và nội dung riêng biệt như StringItem. Tuỳ yêu cầu
của chương trình mà người lập trình có thể lựa chọn đối tượng phù hợp để sử dụng.

52
Java Mobile

4.3.4. TextField:
Lớp TextField được sử dụng khi ứng dụng cần người dùng nhập liệu. Không chỉ
nhập dữ liệu text mà còn có thể nhập số, password, địa chỉ... Để hỗ trợ cho người
lập trình, MIDP đã định nghĩa sẵn một số các ràng buộc (constraints) để đối tượng
tự động kiểm tra tính hợp lệ của dữ liệu nhập vào. Các ràng buộc này là các hằng
lớp của lớp TextField gồm:
o EMAILADDR: người dùng chỉ được phép nhập dữ liệu đúng chuẩn
của một địa chỉ email.
o NUMERIC: chỉ được phép nhập số (có thể là âm hay dương), nếu
muốn giới hạn các giá trị được phép nhập thì ứng dụng phải tự xử lý.
o PASSWORD: dữ liệu nhập vào sẽ đựơc hiển thị lên màn hình với
dạng các dấu *.
o PHONENUMBER: dữ liệu nhập phải đúng chuẩn của số điện thoại.
o URL: dữ liệu nhập phải có dạng 1 URL
và có thể được sử dụng khi kiểm tra ràng buộc cho đối tượng TextBox. Các ràng
buộc này được biểu diễn với dạng một số nguyên kiểu int, giá trị được đề cập trong
bảng sau:
Tên ràng buộc Giá trị Biểu diễn nhị phân
ANY 0 00000000 00000000 00000000
EMAILADDR 1 00000000 00000000 00000001
NUMERIC 2 00000000 00000000 00000010
PHONENUMBER 3 00000000 00000000 00000011
URL 4 00000000 00000000 00000100
PASSWORD 65536 (0x10000) 00000001 00000000 00000000
CONSTRAINT_MASK 65635 (0xFFFF) 00000000 11111111 11111111
Bảng 4.7 Các Ràng Buộc của TextField
Các giá trị của ràng buộc là các số nguyên liên tục nên các ràng buộc này phải sử
dụng độc lập, không được kết hợp với nhau vì có thể gây sai sót.

53
Java Mobile

Vd: TextField.EMAILADDR | TextField.NUMERIC


= 00000000 00000000 00000001
OR 00000000 00000000 00000010
-----------------------------------------
= 00000000 00000000 00000011
= TextField.PHONENUMBER

Ngoại trừ PASSWORD có thể kết hợp với một trong các ràng buộc còn lại bằng
toán tử OR mà không gây nhầm lẫn cho chương trình.

Vd: TextField.ANY | TextField.PASSWORD


= 00000000 00000000 00000000
OR 00000001 00000000 00000000
------------------------------------------
= 00000001 00000000 00000000

MIDP cũng cung cấp sẵn giá trị CONSTRAINT_MASK để có thể dễ dàng kiểm tra
lại ràng buộc nào đã được sử dụng bằng cách dùng toán tử AND giữa giá trị ràng
buộc của đối tượng TextField và CONSTRAINT_MASK

Vd:
tfPassword.getConstraints() 00000001 00000000 00000000
TextField.CONSTRAINT_MASK 00000000 11111111 11111111
------------------------------------------
AND 00000000 00000000 00000000
Sau đó lấy giá trị này so sánh với các ràng buộc để biết đối tượng TextField đó đã
được áp ràng buộc nào.

54
Java Mobile

Các phương thức và chức năng tương ứng của lớp TextField:
Lớp TextField: javax.microedition.lcdui.TextField
Phương thức Chức năng
TextField (String label, String text, Khởi tạo đối tượng TextField với maxSize là
int maxSize, int constraints) số ký tự tối đa người dùng có thể nhập và
constraints là các ràng buộc khi nhập
void delete (int offset, int length) Xóa length ký tự từ vị trí offset
void insert (String src, int pos) Chèn chuỗi src vào TextField từ vị trí pos
void insert (char[] data, int offset, Chèn các length ký tự từ vị trí offset trong
int length, int position) chuỗi data vào TextField từ vị trí position
void setChars (char[] data, int Gán giá trị cho TextField bằng length ký tự
offset, int length) từ vị trí offset trong chuỗi data
void setString (String text) Gán giá trị text cho TextField
int getChars (char[] data) lấy giá trị TextField ra một mảng ký tự
String getString () lấy giá trị TextField
int getConstraints () Lấy giá trị ràng buộc của TextField
void setConstraints (int constraints) Gán giá trị ràng buộc cho TextField
int getMaxsize () Lấy kích thứơc tối đa của TextField
void setMaxsize (int maxSize) Gán kích thứơc tối đa của TextField
int getCaretPosition () Lấy vị trí con trỏ hiện thời
int size () Lấy kích thước thật của TextField (số ký tự
hiện tại của TextField)
Bảng 4.8 Lớp TextField
VD:
//tạo các đối tượng TextField để nhập địa chỉ mail, số điện thoại
TextField tfAddr = new TextField (“Addr:”,””,20,TextField.EMAILADDR);
TextField tfPhone = new TextField (“Phone:”, ””, 10,
TextField.PHONENUMBER);
//gắn vào Form

55
Java Mobile

fmMain.append (tfAddr);
fmMain.append (tfPhone);

Hình 4.6 Giao diện đối tượng TextField

56
Java Mobile

4.3.5. ChoiceGroup:
Lớp ChoiceGroup được sử dụng để biểu diễn một danh sách các khả năng cho
người dùng lựa chọn. ChoiceGroup kế thừa từ interface Choice, gồm hai dạng:
• Cho phép chọn nhiều khả năng (Multiple ): Thể hiện danh sách các
khả năng lên màn hình dạng checkbox và cho phép người đánh dấu check
lên các lựa chọn.
• Chỉ được phép chọn một khả năng (Exclusive ): Thể hiện danh sách
các khả năng lên màn hình cùng các radio button và chỉ cho phép người
dùng chọn duy nhất một khả năng.

Các phương thức và chức năng tương ứng của lớp ChoiceGroup:
Lớp ChoiceGroup: javax.microedition.lcdui.ChoiceGroup
Phương thức Chức năng
ChoiceGroup (String label, int Khởi tạo đối tượng ChoiceGroup với
choiceType) choiceType là loại lựa chọn
Choice.EXCLUSIVE hay Choice.MULTIPLE
Với Exclusive ChoiceGroup phần tử đầu tiên
tự động được gán là phần tử được chọn.
ChoiceGroup (String label, int Khởi tạo đối tượng ChoiceGroup, cho trước
choiceType, String[] strElements, các khả năng lựa chọn và biểu tượng của từng
Image[] iElements) khả năng
int append (String strPart, Image Thêm một phần tử (1 khả năng) vào
iPart) ChoiceGroup (vào cuối danh sách)
int delete (int position) Xoá phần tử ở vị trí position của ChoiceGroup
void insert (int position, String Chèn một phần tử vào vị trí position
strPart, Image iPart)
void set (int position, String Gán giá trị và biểu tượng cho phần tử ở vị trí
strPart, Image iPart) position

57
Java Mobile

String getString (int position) Lấy giá trị của phần tử ở vị trí position
Image getImage (int position) Lấy biểu tượng của phần tử ở vị trí position
int getSelectedIndex () Lấy vị trí của phần tử được chọn
void setSelectedIndex (int MULTIPLE: gán giá trị được chọn hay không
position, boolean selected) (selected) cho phần tử ở vị trí position
EXCLUSIVE: gán giá trị cho phần tử ở vị trí
position là được chọn (không phụ thuộc giá trị
selected)
int getSelectedFlags (boolean[] Lưu thông tin kết quả lựa chọn vào mảng
selectedArr)
void setSelectedFlags (boolean[] Gán kết quả lựa chọn cho đối tượng
selectedArr) ChoiceGroup
boolean isSelected (int position) Kiểm tra phần tử ở vị trí position có được chọn
không
int size () Lấy số phần tử của ChoiceGroup
Bảng 4.9 Lớp ChoiceGroup
*Bắt sự kiện cho đối tượng ChoiceGroup:
Có thể dùng hai cách để bắt sự kiện cho đối tượng ChoiceGroup:
• ItemStateListener: khi Form chứa đối tượng ChoiceGroup đã gọi
phương thức setItemStateListener() thì khi người dùng chọn vào bất cứ
khả năng nào, phương thức itemStateChanged() sẽ được gọi thực hiện.
Cách này nên dùng cho ChoiceGroup dạng chỉ cho phép chọn một khả
năng hoặc một số trường hợp đặc biệt
• CommandListener: Khi gắn đối tượng ChoiceGroup vào Form thì tạo
thêm một Command (tên là “OK” chẳng hạn). Khi người dùng chọn xong
thì nhấn chọn Command này và chương trình sẽ gọi phương thức
commandAction() để xử lý. Cách này có thể sử dụng để bắt sự kiện cho
cả hai loại ChoiceGroup cũng như các đối tượng Item khác.
Vd:

58
Java Mobile

//Tạo một đối tượng ChoiceGroup chỉ cho phép chọn một khả năng:
ChoiceGroup cgExclusive = new ChoiceGroup( “Email Options”,
Choice.EXCLUSIVE);
//lần lượt thêm các phần tử cho đối tượng, không kèm biểu tượng
cgExclusive.append(“Read”, null);
cgExclusive.append(“Forward”, null);
int iReplyIndex = cgExclusive.append(“Reply”, null);
cgExclusive.append(“Delete”, null);

//gán “Reply” là phần tử được chọn


cgExclusive.setSelectedIndex(iReplyIndex, true);
//gắn vào Form
fmMain.append(cgExclusive);
fmMain.setItemStateListener(this);
....
//bắt sự kiện
public void itemStateChanged(Item item) {
if (item==cgExclusive) {
...
}
}

Hình 4.7 Giao diện đối tượng ChoiceGroup chế độ một lựa chọn

59
Java Mobile

//tạo 1 đối tượng ChoiceGroup cho phép chọn nhiều khả năng:
ChoiceGroup cgMultiple = new ChoiceGroup( “Multiple Choice”,
Choice.MULTIPLE);
//lần lượt thêm các phần tử cho đối tượng, không kèm biểu tượng
cgMultiple.append(“Auto Indent”, null);
cgMultiple.append(“Replace Tabs”, null);
cgMultiple.append(“Wrap Text”, null);
//tạo 1 command OK để bắt sự kiện
Command cmOK = new Command (“OK”, Command.Screen, 1);
//gắn vào Form
int iChoiceGroupIndex = fmMain.append(cgMultiple);
fmMain.addCommand(cmOK);
fmMain.setCommandListener(this);
....
//xử lý sự kiện
public void commandAction (Command c, Displayable d) {
if (c==cmOK) {
...
}
}

Hình 4.8 Giao diện đối tượng ChoiceGroup chế độ nhiều lựa chọn

60
Java Mobile

4.3.6. Image và ImageItem:

4.3.6.1. Image:
Chứa dữ liệu ảnh đồ hoạ, gồm hai dạng :
• Cố định (Immutable): thường đựơc nạp từ resource của ứng dụng, từ
file hay chuyển từ dạng Image có thể thay đổi (Mutable) sang. Dạng hình
ảnh này chủ yếu được dùng làm biểu tượng cho các thành phần đồ hoạ khác
như ChoiceGroup, Form, List, Alert....Một khi đã tạo đối tượng kiểu
Immutable Image thì không thể thay đổi hình ảnh đựơc nữa.
• Có thể thay đổi (Mutable): có thể thay đổi một cách dẽ dàng. Khi tạo
đối tượng kiểu Mutable Image, một vùng nhớ trống sẽ được cấp phát dựa
trên kích thước khi khai báo. Khi muốn hiển thị Image dạng này lên màn
hình phải gọi phương thức paint() của lớp Canvas sẽ được đề cập trong
phần đồ hoạ cấp thấp.

Các phương thức và chức năng tương ứng của lớp Image:
Lớp Image: javax.microedition.lcdui.Image
Phương thức Chức năng
static Image createImage (String Tạo một đối tượng Immutable Image từ
name) resource
static Image createImage (Image Tạo một đối tượng Immutable Image từ một
source) đối tượng Image source khác
static Image createImage (byte[] Tạo một đối tượng Immutable Image từ mảng
data, int offset, int length) dữ liệu (lấy length bytes từ vị trí offset của
mảng byte data)
static Image createImage (int tạo một đối tượng Mutable Image, cho trứơc
width, int height) kích thứơc dài rộng của ảnh
Graphics getGraphics () Lấy đối tượng Graphics tương ứng của
Mutable Image

61
Java Mobile

int getHeight () Lấy chiều cao của đối tượng Image


int getWidth () Lấy chiều rộng của đối tượng Image
boolean isMutable () kiểm tra đối tượng có là Mutable Image không
Bảng 4.10 Lớp Image

4.3.6.2. ImageItem:
Lớp ImageItem cung cấp các phương thức để điều khiển và sắp xếp các đối tượng
Image đựơc gắn trong Form. Lớp ImageItem đã cung cấp sẵn các định dạng vị trí
sẵn cho hình ảnh, bao gồm:

Định dạng Giá trị nhị phân Ý nghĩa


LAYOUT_DEFAULT 00000000 00000000 dùng định dạng mặc
định của thiết bị
LAYOUT_LEFT 00000000 00000001 canh trái
LAYOUT_RIGHT 00000000 00000010 canh phải
LAYOUT_CENTER 00000000 00000011 canh giữa
LAYOUT_NEWLINE_BEFORE 00000001 00000000 xuống hàng trước khi
vẽ Image
LAYOUT_NEWLINE_AFTER 00000010 00000000 xuống hàng sau khi vẽ
Image.
Bảng 4.11 Định dạng ImageItem
Các định dạng trên có thể dùng kết hợp với nhau trong một đối tượng ImageItem
bằng phép toán OR .

Vd: ImageItem.LAYOUT_RIGHT 00000000 00000010


ImageItem.LAYOUT_NEWLINE_AFTER 00000010 00000000
--------------------------------------
logical OR 00000010 00000010

62
Java Mobile

Các phương thức và chức năng tương ứng của lớp ImageItem:
Lớp ImageItem: javax.microedition.lcdui.ImageItem
Phương thức Chức năng
ImageItem (String label, Image Tạo một đối tượng ImageItem từ đối tượng
img, int layout, String altText) Image img, với định dạng layout, và chuỗi thay
thế altText(chuỗi này dùng thay thế cho image
khi không thể hiện được lên màn hình thiết bị)
Image getImage () Lấy đối tượng Image của ImageItem
void setImage (Image img) Gán đối tượng Image cho ImageItem
int getLayout() Lấy giá trị định dạng của ImageItem
void setLayout (int layout) Gán giá trị định dạng cho ImageItem
String getAltText () Lấy giá trị chuỗi thay thế
void setAltText () Gán giá trị chuỗi thay thế
Bảng 4.12 Lớp ImageItem
Vd:
//tạo Immutable Image từ File và hiển thị trong Form
Image img = Image.createImage(“image.png”);
//.png (Portable NetWork Graphics) là định dạng file ảnh trong thiết bị di động
ImageItem imageItem = new ImageItem (null, img,
ImageItem.LAYOUT_CENTERImageItem.LAYOUT_NEWLINE_BEFORE,null);
fmMain.append(imageItem);

//tạo đối tượng ChoiceGroup có các biểu tượng tương ứng cho các khả năng lựa chọn
Image image[] = { Image.createImage(“/up.png”),
Image.createImage(“/down.png”),
Image.createImage(“/help.png”)} ;
String options[] = {“Upload”, “Download”, “Help”};
//Tạo đối tượng ChoiceGroup dùng mảng
ChoiceGroup cgImage = new ChoiceGroup (“Select option”,
Choice.EXCLUSIVE, options, images);

63
Java Mobile

4.4. List:
List dùng để hiển thị các danh sách các khả năng cho người dùng lựa chọn. List
gồm 3 dạng:
• Multiple: cho phép người dùng lựa chọn nhiều khả năng, tương tự
Multiple ChoiceGroup.
• Exclusive: cho phép người dùng lựa chọn duy nhất một khả năng,
tương tự Exclusive ChoiceGroup.
• Implicit: chỉ hiển thị danh sách các khả năng lựa chọn dạng menu.
* Bắt sự kiện cho các đối tượng List:
Để bắt sự kiện cho đối tượng List, phải gán đối tượng ở trạng thái lắng nghe, nghĩa
là sử dụng phương thức setCommandListener() cho đối tượng List này. Sau đó bắt
sự kiện và xử lý sự kiện trong phương thức commandAction().
Exclusive và multiple List không tự động gửi sự kiện. Do đó, ta phải gắn một
command (vd: command Save)vào đối tượng List để lấy trạng thái của đối tượng
sau khi người dùng lựa chọn. Khi người dùng chọn command Save tức người dùng
đã chọn xong các khả năng, ta sẽ bắt sự kiện này và xử lý sự kiện trong phương
thức commandAction().
Implicit List gửi sự kiện mỗi khi người dùng lựa chọn một phần tử trong List. Khi
đó, nếu đã gán listener cho đối tượng thì sự kiện phát sinh sẽ gọi phương thức
commandAction().

* So sánh giữa lớp List và lớp ChoiceGroup:


Giống nhau:
• Cả hai đều kế thừa từ interface Choice
• Cả hai đều cho phép tạo đối tượng hỗ trợ một lựa chọn duy nhất(radio
button ) hoặc nhiều lựa chọn (checkbox).
• Có thể thêm các đối tượng Command khác hiển thị cùng lúc trên màn
hình để hỗ trợ việc bắt sự kiện.
Khác nhau:

64
Java Mobile

ChoiceGroup List
Hiển thị trên ChoiceGroup là 1 phần của List là thực thể duy nhất hiển
màn hình Form. Nghĩa là có thể có các thị trên màn hình.
thành phần giao diện khác được
hiển thị đồng thời với
ChoiceGroup
Phân loại ChoiceGroup gồm 2 dạng: List gồm 3 dạng:
MULTIPLE (check box), MULTIPLE (check box),
EXCLUSIVE (radio button) EXCLUSIVE (radio button) và
IMPLICIT (menu)
Bắt sự kiện 2cách: Chỉ có 1 cách duy nhất là dùng
ItemStateListener: gọi phương CommandListener. List gọi
thức itemStateChanged()) khi commandAction() để bắt sự
người dùng lựa chọn một phần kiện (Implicit List tự gọi hàm
tử bất kỳ. này khi người dùng chọn 1
CommandListener: gắn một phần tử bất kỳ, 2 dạng List còn
Command để lắng nghe và gọi lại phải thêm 1 command để
phương thức commandAction() bắt)
khi có sự kiện phát sinh
Bảng 4.13 So sánh List và ChoiceGroup
Các phương thức và chức năng tương ứng của lớp List:
Lớp List: javax.microedition.lcdui.List
Phương thức Chức năng
List (String title, int listType) Tạo một đối tượng List rỗng (chưa có các
phần tử) với listType thuộc 1 trong 3 dạng:
Choice.IMPLICIT, Choice.EXPLICIT,
Choice.MULTIPLE.
List (String tile, int listType, Tạo một đối tượng List cho trước phần tử và
String[] strElements, Image[] biểu tượng dưới dạng mảng strElements và

65
Java Mobile

imElements ) imElements.
int append (String strPart, Image Thêm một phần tử vào cuối danh sách
imPart)
void delete (int position) Xoá một phần tử ở vị trí position
void insert (int position, String Chèn một phần tử vào vị trí position
strPart, Image imPart)
void set (int position, String strPart, Gán giá trị (thay thế bằng phần tử mới) cho
Image imPart) phần tử ở vị trí position
String getString (int position) Lấy giá trị phần tử ở vị trí position
Image getImage (int position) Lấy biểu tượng phần tử ở vị trí position
int getSelectedIndex () Lấy vị trí phần tử được chọn
void setSelectedIndex (int position, MULTIPLE: gán giá trị được chọn hay
boolean selected) không (selected) cho phần tử ở vị trí position
EXCLUSIVE, IMPLICIT: gán giá trị cho
phần tử ở vị trí position là được chọn (không
phụ thuộc giá trị selected)
int getSelectedFlags (boolean[] Lưu thông tin kết quả lựa chọn vào mảng
selectedArr)
void setSelectedFlags (boolean[] Gán kết quả lựa chọn cho đối tượng List
selectedArr)
boolean isSelected (int position) Kiểm tra phần tử ở vị trí position có được
chọn không
int size () Lấy số phần tử của List
Bảng 4.14 Lớp List
VD: //tạo đối tượng Implicit List với các phần tử cho trước:
//tạo mảng các phần tử
String options[]={“Next”, “Previous”, “New”};
//tạo mảng các biểu tượng
Image images[]={Image.createImage(“/next.png”),

66
Java Mobile

Image.createImage(“/prev.png”), Image.createImage(“/new.png”),}
List lsImplicit = new List (“Document option:”, Choice.IMPLICIT, options,
images);
//gán đối tượng vào trạng thái lắng nghe
lsImplicit.setCommandListener(this);
//bắt sự kiện và xử lý
public void commandAction(Command c, Displayable s) {
if (c == List.SELECT_COMMAND) {
switch (lsImplicit.getSelectedIndex()) {
case 0:
System.out.println("Next");
break;
case 1:
System.out.println("Previous");
break;
case 2:
System.out.println("New");
break;
}
}
}

Hình 4.9 Giao diện đối tượng List dạng menu

67
Java Mobile

//tạo đối tượng Multiple hay Exclusive List:


List lsMultiple = new List (“Multiple choice”, Choice.MULTIPLE);
List lsExclusive = new List (“Exclusive choice”, Choice.Exclusive);
//thêm command Save để bắt sự kiện
Command cmSave = new Command (“Save”, Command.SCREEN, 1);
lsMultiple.addCommand(cmSave);
//gán đối tượng ở trạng thái lắng nghe
lsMultiple.SetCommandListener(this);
//bắt sự kiện
public void commandAction (Command c, Displayable d) {
if (c==cmSave) {
// xử lý sự kiện
}
}

Hình 4.10 Giao diện đối tượng List cho phép chọn nhiều lựa chọn

68
Java Mobile

4.5. TextBox:
TextBox là dạng giao diện dành cho người dùng nhập liệu, tương tự TextField.
* So sánh giữa lớp TextBox và lớp TextField:
Giống nhau:
• Cả hai lớp đều sử dụng chung các kiểu ràng buộc của lớp TextField
(gồm TextField.ANY, TextField.EMAILADDR, TextField.NUMERIC,
TextField.PASSWORD, TextField.PHONENUMBER, TextField.URL)
• Số ký tự nhập vào có thể nhỏ hơn hay bằng số ký tự tối đa của đối
tượng được gán khi khởi tạo. Chức năng cuộn màn hình được hỗ trợ nếu
màn hình không đủ hiển thị toàn bộ nội dung nhập.
Khác nhau:
TextField TextBox
Hiển thị TextField là 1 phần của Form. TextBox là thực thể duy nhất
trên màn Nghĩa là có thể có các thành phần hiển thị trên màn hình.
hình giao diện khác được hiển thị đồng
thời với TextField
Bắt sự kiện 2 cách: Chỉ có thể thêm một Command
CommandListener và dùng CommandListener để
ItemStateListener lắng nghe và bắt sự kiện
Bảng 4.15 So sánh TextField và TextBox
Các phương thức và chức năng tương ứng của lớp TextBox:
Lớp TextBox: javax.microedition.lcdui.TextBox
Phương thức Chức năng
TextBox (String title, String text, int Tạo một đối tượng TextBox với maxSize là
maxSize, int constraints) số ký tự tối đa được phép nhập và
constraints là các ràng buộc nhập liệu.
void delete (int offset, int length) Xóa length ký tự từ vị trí offset
void insert (String source, int Chèn chuỗi source vào TextBox từ vị trí

69
Java Mobile

position) position
void insert (char[] data, int offset, int Chèn các length ký tự từ vị trí offset trong
length, int position) chuỗi data vào TextBox từ vị trí position
void setChars (char[] data, int offset, Gán giá trị cho TextBox bằng length ký tự
int length) từ vị trí offset trong chuỗi data
void setString (String text) Gán giá trị text cho TextBox
int getChars (char[] data) lấy giá trị TextBox ra một mảng ký tự
String getString () lấy giá trị TextBox
int getConstraints () Lấy giá trị ràng buộc của TextBox
void setConstraints (int constraints) Gán giá trị ràng buộc cho TextBox
int getMaxSize () Lấy kích thước tối đa của TextBox
void setMaxSize (int maxSize) Gán kích thước tối đa của TextBox
int getCaretPosition () Lấy vị trí con trỏ hiện thời
int size () Lấy số ký tự của dữ liệu nhập vào TextBox
Bảng 4.16 Lớp TextBox
VD:
//tạo một đối tượng TextBox:
TextBox tbName = new TextBox (“Pls enter your name”, null, 20,
TextField.ANY);
//gắn command Save bắt sự kiện
Command cmSave = new Command (“Save”, Command.SCREEN, 1);
tbName.addCommand(cmSave);
// lắng nghe sự kiện
tbName.SetCommandListener(this);

//bắt sự kiện
public void commandAction (Command c, Displayable d) {
if(c==cmSave) {
//xử lý sự kiện
...

70
Java Mobile

}
}

Hình 4.11 Giao diện đối tượng TextBox

71
Java Mobile

4.6. Alert và AlertType:

4.6.1. Alert:
Đối tượng Alert có dạng một hộp thoại hiển thị thông báo đến người dùng, có thể có
hiển thị hình ảnh kèm theo hoặc không. Một đối tượng Alert gồm 3 thành phần: tiêu
đề, nội dung thông báo và hình ảnh đính kèm.
Alert gồm hai loại:
• Không giới hạn thời gian hiển thị (Modal): Alert hiển thị trên màn
hình cho đến khi người dùng bấm nút tắt.
• Giới hạn thời gian hiển thị (Timed): Alert chỉ hiển thị trên màn hình
trong thời gian nhất định và tự động tắt khi đến hạn.

Các phương thức và chức năng tương ứng của lớp Alert:
Lớp Alert: javax.microedition.lcdui.Alert
Phương thức Chức năng
Alert (String title) Tạo một đối tượng Alert với kiểu mặc
định của thiết bị
Alert (String title, String strText, Tạo đối tượng Alert với tiêu đề title, nội
Image iImage, AlertType atType) dung strText, hình iImage và loại atType
cho trước
Image getImage () Lấy đối tượng Image của Alert
void setImage () Gán đối tượng Image cho Alert
String getString () Lấy nội dung thông báo của Alert
void setString (String str) Gán nội dung thông báo cho Alert
int getDefaultTimeout() Lấy thời gian Alert được phép hiển thị
(timeout) mặc định của thiết bị
int getTimeout () Lấy thời gian Alert được phép hiển thị
void setTimeout (int miliseconds) Gán giá trị thời gian Alert được phép hiển

72
Java Mobile

thị tính theo mili giây


AlertType getType() Lấy kiểu của Alert
void setType(AlertType type) Gán kiểu cho Alert
Bảng 4.17 Lớp Alert
Mỗi thiết bị có dạng Alert cũng như thời gian hiển thị Alert mặc định. Dùng phương
thức getDefaultTimeout() của lớp Alert để kiểm tra, nếu giá trị trả về là
Alert.FOREVER thì dạng mặc định là không giới hạn thời gian hiển thị (Modal)
nếu không thì đó chính là thời gian hiển thị mặc định của Alert tính theo đơn vị mili
giây và Alert mặc định là loại giới hạn thời gian hiển thị.
Có hai cách để hiển thị Alert lên màn hình:
• Dùng phương thức Display.setCurrent (Alert, Displayable) : Khi
Modal Alert bị ngừơi dùng tắt hay Timed Alert hết thời hạn hiển thị thì
đối tượng Displayable sẽ được hiển thị lên màn hình.
VD:
Form fmMain =new Form (“Form Main”);
Alert alTest = new Alert (“Alert”);
alTest.setTimeout(Alert.FOREVER);
...
display.setCurrent(alTest, fmMain);

• Dùng phương thức Display.setCurrent (Alert): đối tượng Displayable


đang được hiển thị trước khi gọi phương thức này sẽ được gọi hiển thị lại
sau khi đối tượng Alert hết hạn.
VD:
Alert alTest = new Alert (“Alert”);
alTest.setTimeout (Alert.FOREVER);
...
display.setCurrent (alTest);

73
Java Mobile

Lớp Alert là lớp con của Screen, Screen là lớp con của Displayable nhưng đối
tượng Alert không được phép gọi trực tiếp một số hàm sau của lớp Displayable:
• addCommand(Command)
• removeCommand(Command)
• setCommandListener(CommandListener)
Điều này nghĩa là đối tượng Alert không được phép gắn thêm nút (đối tượng
Command ) cũng như không xử lý và bắt sự kiện. Đối tượng này chỉ có chức năng
gửi thông báo đến người dùng chứ không thêe nhận phản hồi từ người dùng. Nếu
đối tượng Alert gọi các hàm này thì sẽ bị phát sinh Exception IllegalStateException.

4.6.2. AlertType:
AlertType là lớp định nghĩa sẵn các loại Alert cho thiết bị, hỗ trợ âm thanh tương
ứng khiAlert hiển thị. Gồm năm loại:
• Báo giờ (alarm)
• Nhắc lại (confirmation)
• Báo lỗi (error)
• Thông báo (info)
• Cảnh báo (warning)
Âm thanh của Alert có thể được chơi bằng một trong hai cách:
• Nếu đối tượng Alert được gán loại Alert trước thì âm thanh tương ứng
của loại Alert này sẽ được phát khi đối tượng hiển thị lên màn hình.
VD:
Alert alWarning = new Alert (“Alert”, “Message”, null,
AlertType.WARNING);

hay
Alert alTest =new Alert (“Alert”, “Message”, null, null);
alTest.setType(AlertType.WARNING);

74
Java Mobile

• Phát âm thanh Alert trực tiếp mà không cần tạo một đối tượng Alert
nghĩa là chỉ phát âm thanh thông báo mà không hiển thị lên màn hình,
bằng cách dùng phương thức: AlertType.<Type>.playSound (Display);
cách này có thể dùng khi chỉ cần báo cho ngưòi dùng biết về sự kiện mà
không cần hiển thị thông tin trực tiếp lên màn hình. Các sự kiện khác
nhau có thể được thông báo bằng các âm thanh khác nhau.
VD: AlertType.CONFIRMATION.playSound(fmMain);
Hay AlertType.ALARM.playSound(fmMain);

Các loại AlertType được định nghĩa trước:


Giá trị Ý nghĩa
ALARM Báo giờ hoặc nhắc nhở
CONFIRMATION Thông báo hoàn tất 1 công việc nào đó
ERROR Báo lỗi
INFO Thông báo chung
WARNING Khuyến cáo
Bảng 4.18 AlertType
Lớp AlertType chỉ hỗ trợ một phương thức duy nhất là
boolean playSound (Display display) để gọi thực hiện chức năng play sound của đối
tượng AlertType.

VD:
//tạo một đối tượng Alert có kèm hình ảnh và âm thanh dạng thông báo khi hiển thị
Image img = Image.createImage(“/coffee.png”);
Alert alAlert= new Alert (“Hello”, “It’s time for coffee”, img, AlertType.INFO);
//gán kiểu Modal Alert
alAlert.setTimeout(Alert.FOREVER);
….

75
Java Mobile

//gọi hiển thị Alert


display.setCurrent(alAlert, fmMain);

Hình 4.12 Giao diện đối tượng Alert

76
Java Mobile

4.7. Ticker:
Ticker là lớp hỗ trợ hiển thị chuỗi ký tự cuộn liên tục trên màn hình. Đối tượng
Ticker có thể được gắn vào bất kỳ đối tượng Screen nào, kể cả Alert. Vị trí chuỗi ký
tự ở trên hay dưới màn hình, cũng như tốc độ cuộn phụ thuộc vào đặc tả MIDP.

Các phương thức và chức năng tương ứng của lớp Ticker:
Lớp Ticker: javax.microedition.lcdui.Ticker
Phương thức Chức năng
Ticker (String strText) Tạo một đối tượng Ticker với nội dung
chuỗi cuộn strText cho trước
String getString () Lấy chuỗi ký tự của Ticker
void setString (String strText) Gán chuỗi ký tự cho Ticker
Bảng 4.19 Lớp Ticker
VD:
//tạo đối tượng Ticker
Ticker tkMessage = new Ticker (“Wellcome to J2ME, have a nice day!!!”);
//gắn vào form
fmMain.setTicker(tkMessage);

Hình 4.13 Giao diện Ticker

77
Java Mobile

Chương 5: Giao diện đồ họa cấp thấp

Đồ hoạ cấp thấp trong J2ME được hỗ trợ chủ yếu qua hai lớp chính là Canvas và
Graphics.
Lớp Canvas có dạng một phông có kích thước cố định và những gì vẽ lên phông
này sẽ được hiển thị cho người dùng. Lớp Canvas cũng hỗ trợ các phương thức bắt
sự kiện ở cấp thấp
Lớp Graphics cung cấp những đối tượng để vẽ lên Canvas (hay được gọi là
những ngữ cảnh đồ họa (graphics context)). Lớp Graphics hỗ trợ vẽ các đối tượng
đường thẳng, đừơng tròn, hình chữ nhật, text… cũng như các phương thức chọn
màu và font chữ.

5.1. Canvas:
Canvas là lớp con của lớp Displayable (ngang cấp với lớp Screen), nghĩa là
có thể gắn thêm các đối tượng Command vào Canvas để bắt sự kiện như Form. Khi
sử dụng, không tạo trực tiếp một đối tượng Canvas mà xây dựng một lớp kế thừa
lớp này và xử lý các chức năng đồ hoạ của chương trình bên trong lớp con này.
VD:
class MyFirstCanvas extends Canvas implements CommandListener{

Command cmdExit =new Command(“Exit”, Command.EXIT, 1);
addCommand(cmdExit);
setCommandListener(this);

}
MyFirstCanvas mfcCanvas = new MyFisrtCanvas(this);
display.setCurrent(mfcCanvas);

78
Java Mobile

5.1.1. Hệ toạ độ:


Tương tự hệ toạ độ trong lập trình Windows, gốc toạ độ (0,0) nằm ở góc trái trên
của màn hình. Tung độ y tăng dần theo chiều dọc từ trên xuống, hoành độ x tăng
dần theo chiều từ trái sang phải. Độ dày mặc định của các đối tượng đồ hoạ trong
J2ME là 1 pixel.
Đối tượng Canvas đặc trưng bởi 2 giá trị là chiều dài và chiều rộng. Hai giá trị này
là cố định cho các đối tượng Canvas khác nhau đựơc tạo lập trong cùng một thiết bị
và phụ thuộc vào loại thiết bị di động.

Các phương thức của lớp Canvas để truy vấn các giá trị này:
Lớp Canvas: javax.microedition.lcdui.Canvas
Phương thức Chức năng
int getWidth () Lấy giá trị độ rộng đối tượng Canvas
int getHeight () Lấy giá trị độ dài đối tượng Canvas
Bảng 5.1 Truy vấn kích thước Canvas

5.1.2. Vẽ trên đối tượng Canvas:


Canvas và Screen là hai lớp con của lớp Displayable nên cùng kế thừa phương thức
abstract paint() của lớp cha. Trong khi phương thức paint() trong lớp Screen và các
lớp con của nó đã được dựng sẵn để vẽ các đối tượng đồ hoạ cấp cao(title, ticker,
form, textbox, list, alert…) lên màn hình thì trong lớp Canvas, phương thức này vẫn
được khai báo với từ khoá abstract, nghĩa là phải viết xử lý cho phương thức này ở
lớp con của Canvas (lớp kế thừa mà ta xây dựng để vẽ lên màn hình).

abstract public class Displayable {


abstract void paint(Graphics g);
}

79
Java Mobile

public abstract class Canvas extends Displayable {


protected abstract void paint(Graphics g);
}

public abstract class Screen extends Displayable {


abstract void paintContent(Graphics g);
paint(Graphics g){
// gắn tiêu đề
//gắn đối tượng Ticker

paintContent(g);
}
}

public class Form extends Screen {


void paintContent(Graphics g){… }
}

public class TextBox extends Screen {


void paintContent(Graphics g) {… }
}

public class List extends Screen implements Choice {


void paintContent(Graphics g){… }
}

public class Alert extends Screen{


void paintContent(Graphics g){… }
}

80
Java Mobile

Các phương thức hỗ trợ vẽ của lớp Canvas:


Lớp Canvas: javax.microedition.lcdui.Canvas
Phương thức Chức năng
abstract void paint (Graphic g) vẽ đối tượng g lên Canvas
final void repaint () yêu cấu vẽ Canvas
final void repaint (int x, int y, int yêu cấu vẽ một vùng của Canvas ((x,y) là
width, int height) toạ độ góc trái trên; width, height là kích
thước vùng cần vẽ lại)
final void serviceRepaints() xử lý các yêu cầu vẽ còn treo
boolean isDoubleBuffered () kiểm tra thiết bị có hỗ trợ hai buffer không
Bảng 5.2 Lớp Canvas

Phương thức paint() được dùng để xử lý các sự kiện vẽ trong đối tượng Canvas.
Nhưng khi cần yêu cầu thiết bị vẽ lại màn hình thì không gọi trực tiếp phương thức
này mà gọi phương thức repaint(). Phương thức repaint() này sẽ gọi hàm paint() để
vẽ lại toàn bộ hay một phần màn hình.
Phương thức serviceRepaint() yêu cầu tất cả các yêu cầu vẽ trước đó phải được thực
hiện ngay. Do đó, khi gọi phương thức này các tiến trình khác sẽ bị block cho đến
khi tất cả các phương thức vẽ được thực hiện.

Các phương thức hỗ trợ giao tiếp với Application Manager:


Lớp Canvas: javax.microedition.lcdui.Canvas
Phương thức Chức năng
void showNotify () Được gọi trước khi application manager vẽ
đối tượng canvas lên màn hình
void hideNotify () Được gọi sau khi application manager xoá
đối tượng canvas khỏi màn hình
Bảng 5.3 Giao tiếp với Application Manager
Các phương thức này đựơc khai báo trong lớp Canvas với kiểu protected

81
Java Mobile

protected void showNotify(){ };


protected void hideNotify(){ };
và được gọi bởi application manager trước khi vẽ và sau khi xoá đối tượng canvas
lên màn hình. Do đó, không gọi trực tiếp các phương thức này trong chương trình.
Mà chỉ nên viết code trong các phương thức này để cấp phát, khởi tạo các biến cũng
như tạo lập hay hủy các tiến trình xử lý cho việc vẽ các đối tượng lên Canvas.

5.1.3. Bắt sự kiện trong các đối tượng Canvas:


Đối tượng canvas có thể hỗ trợ bắt sự kiện dưới hai cấp độ:
• bắt sự kiện cấp cao: thêm một hay nhiều đối tượng Command vào đối
tượng Canvas và bắt sự kiện thông qua các Command này (dùng
CommandListener)
• bắt sự kiện cấp thấp: bắt sự kiện các phím số trên thiết bị cũng như các sự
kiện con trỏ, sự kiện trong game…

5.1.3.1 Bắt sự kiện cấp cao:


Lớp Canvas cũng là lớp con của Displayable như lớp Screen do đó cũng kế thừa các
phương thức hỗ trợ Command như lớp Screen, gồm:
• addCommand(Command)

• isShown()
• removeCommand(Command)
• setCommandListener(CommandListener)
VD:
class TestCanvas extends Canvas implements CommandListener {
private Command cmExit; // Exit MIDlet

...
cmExit = new Command("Exit", Command.EXIT, 1);
addCommand(cmExit);
setCommandListener(this);

82
Java Mobile

...
public void commandAction(Command c, Displayable d) {
if (c == cmExit) {...}
}
}

5.1.3.2 Bắt sự kiện cấp thấp:


Sử dụng mã phím(key code)
Mã phím là các giá trị nguyên gán cho các phím tương ứng trong thiết bị di động.
Các mã phím này được gán với các tên tương ứng cho dễ nhớ như:
public static final int KEY_NUM0 = 48;
public static final int KEY_NUM1 = 49;

Bảng mã phím các phím bàn phím ITU-T (0-9, *, #)
Lớp Canvas: javax.microedition.lcdui.Canvas
Tên Giá trị
KEY_NUM0 48
KEY_NUM1 49
KEY_NUM2 50
KEY_NUM3 51
KEY_NUM4 52
KEY_NUM5 53
KEY_NUM6 54
KEY_NUM7 55
KEY_NUM8 56
KEY_NUM9 57
KEY_STAR 42
KEY_POUND 35
Bảng 5.4 Mã Phím

83
Java Mobile

Lớp Canvas hỗ trợ việc bắt sự kiện các phím này bằng các phương thức:
Lớp Canvas: javax.microedition.lcdui.Canvas
Phương thức Chức năng
void keyPressed (int keyCode) được gọi khi người dùng nhấn phím
void keyReleased (int keyCode) được gọi khi người dùng nhả phím
void keyRepeated (int keyCode) được gọi khi người dùng nhấn 1 phím nhiều
lần (một số thiết bị không hỗ trợ phương thức
này)
boolean hasRepeatEvents () kiểm tra thiết bị có hỗ trợ nhấn 1 phím nhiếu
lần không
String getKeyName () lấy tên phím tương ứng của mã phím
Bảng 5.5 Sự kiện keyPressed
Các phương thức keyPressed(), keyReleased() và keyRepeated() được khai báo
trong lớp Canvas với thuộc tính protected.
protected void keyPressed (int keyCode){ };
protected void keyReleased (int keyCode){ };
protected void keyRepeated (int keyCode){ };
Do đó, muốn bắt sự kiện nào thì ta chỉ cần khai báo phương thức tương ứng trong
lớp kế thừa Canvas và viết code xử lý cho phương thức đó.
Vd:
protected void keyPressed(int keyCode) {
switch (keyCode) {
KEY_NUM1: …
break;
KEY_NUM2: …
break;

}
}

84
Java Mobile

5.1.4. Game action:


MIDP cũng hỗ trợ lập trình game bằng cách định nghĩ sẵn một bộ các phím bấm xử
lý sự kiện game. Mỗi sự kiện game cũng được gán bởi một số nguyên như sự kiện
phím bấm. Các sự kiện chính bao gồm các sự kiện sang trái, sang phải, lên, xuống
và bắn. Với các loại điện thoại có hỗ trợ các phím di chuyển thì các sự kiện này sẽ
được gán trực tiếp cho các phím đó. Nếu không, có thể gán các sự kiện này với các
phím số 2, 4, 6, 8, 5.

Lớp Canvas:
javax.microedition.lcdui.Canvas
Tên sự kiện Mô tả Giá
trị
UP di chuyển lên trên 1
DOWN di chuyển xuống dưới 6
LEFT di chuyển sang trái 2
RIGHT di chuyển sang phải 5
FIRE bắn 8
GAME_A Tuỳ chọn 9
GAME_B Tuỳ chọn 10
GAME_C Tuỳ chọn 11
GAME_D Tuỳ chọn 12
Bảng 5.6 Sự kiện Game Action

85
Java Mobile

Các phương thức sử dụng cho lập trình game:


Lớp Canvas: javax.microedition.lcdui.Canvas
Phương thức Chức năng
int getKeyCode lấy mã phím tương ứng với hành động game
(int gameAction)
int getGameAction xác định hành động game tương ứng với mã phím cho trước
(int keyCode)
Bảng 5.7 Bắt sự kiện trong Game Action
VD:
//lấy mã phím tương ứng cho các hành động trong game:

int keyFire = getKeyCode(FIRE);


int keyRight = getKeyCode(RIGHT);

//lấy loại hành động game để xử lý
protected void keyRepeated (int keyCode) {
switch (getGameAction (keyCode)) {
case Canvas.FIRE: …
break;
case Canvas.LEFT:…
break;
}
}
Một hành động game có thể gán cho nhiều phím bấm, chẳng hạn gán cho cả phím
chức năng (trái, phải, lên, xuống) lẫn các phím số. Khi đó, người dùng có thể bấm
phím chức năng sang trái hay phím số 4 đều phát sinh sự kiện game LEFT như
nhau.

86
Java Mobile

5.1.5. Sự kiện con trỏ:


MIDP cũng hỗ trợ các phương thức để lập trình trên thiết bị di động có sử
dụng con trỏ như chuột hay màn hình cảm ứng.
Lớp Canvas: javax.microedition.lcdui.Canvas
Phương thức Chức năng
boolean hasPointerEvents() kiểm tra thiết bị có hỗ trợ con trỏ không
boolean hasPointerMotionEvents() kiểm tra thiết bị có khả năng nhận các
chuyển động của con trỏ không
void pointerDragged(int x, int y) được gọi khi người dùng rê con trỏ,
(x,y) là toạ độ con trỏ.
void pointerPressed(int x, int y) được gọi khi người dùng nhấn nút con
trỏ
void pointerReleased(int x, int y) được gọi khi người dùng nhả con trỏ
Bảng 5.8 Sự kiện con trỏ
Các sự kiện con trỏ cũng được xử lý tương tự các sự kiện phím bấm. Nếu thiết bị có
hỗ trợ xử lý sự kiện con trỏ, các phương thức pointerDragged(), pointerPressed(),
pointerReleased() sẽ được gọi khi người dùng rê, nhấn nút hay nhả con trỏ. Các
phương thức pointerDragged(), pointerPressed(), pointerReleased() cũng được khai
báo trong lớp Canvas với thuộc tính protected nên nếu muốn xử lý sự kiện con trỏ
cho chương trình phải khai báo hàm với tên tương ứng trong lớp con của chương
trình và viết xử lý bên trong
VD:
protected void pointerPressed(int x, int y) {
// xác định vị trí điểm đầu
startx = x;
starty = y;
}
protected void pointerDragged(int x, int y) {
// xác định vị trí điểm hiện tại

87
Java Mobile

currentx = x;
currenty = y;
repaint();
}
protected void pointerReleased (int x, int y) {
//xác định vị trí điểm cuối
endx = x;
endy = y;
repaint();
}

88
Java Mobile

5.2. Graphics:
Đối tượng Graphics dùng để vẽ lên màn hình Canvas. Lớp Graphics cung cấp sẵn
trên 30 phương thức hỗ trợ vẽ các đối tượng hình học cơ bản (đường thẳng, đường
tròn, hình chữ nhật…), text, cũng như điều khiển màu sắc, phông chữ…
Có thể sử dụng lớp Graphics trong hai trường hợp:
• Trong phương thức paint() của lớp Canvas:
protected void paint(Graphics g){

}
đối tượng Graphics này chỉ có giá trị bên trong phương thức paint(),
ra khỏi phương thức này thì không còn dùng để vẽ lên Canvas được
nữa.
• Trong các đối tượng mutable image:
Các immutable image thường được tạo từ file hay resource, có tính
cố định, không thay đổi. Do đó, người ta thường dùng immutable
image làm biểu tượng cho các thành phần trong ChoiceGroup, Form,
List hay Alert.
Ngược lại, đối tượng mutable image chỉ là một vùng nhớ có kích
thước cố định được cấp khi khởi tạo.
VD: Image iImage=Image.createImage(80,20);
Graphics gGraphics=iImage.getGraphics();
Đối tượng Graphics được tạo theo cách này có giá trị cùng với đối
tượng Image. Khi đối tượng Image bị huỷ thì đối tượng Graphics
tương ứng cũng bi huỷ theo.

89
Java Mobile

Các phương thức và chức năng của lớp Graphics:


Lớp Graphics: javax.microedition.lcdui.Canvas
Phương thức Chức năng
void setColor (int RGB) Gán giá trị màu sắc, kết hợp các giá trị 3
màu cơ bản (đỏ, lục, xanh dương) trong
một số nguyên
void setColor (int red, int green, Gán giá trị màu sắc theo các thành phần
int blue) riêng biệt
int getColor () Lấy giá trị màu
int getBlueComponent() Lấy giá trị thành phần màu xanh dương
trong đối tượng
int getGreenComponent() Lấy giá trị thành phần màu xanh lục trong
đối tượng
int getRedComponent() Lấy giá trị thành phần màu đỏ trong đối
tượng
void setGrayScale (int value) Gán giá trị grayscale
int getGrayScale () Lấy giá trị grayscale hiện tại
int getStrokeStyle () Lấy kiểu nét vẽ
void setStrokeStyle (int style) Gán kiểu nét vẽ, style có thề mang 1 trong
2 giá trị Graphics.DOTTED hay
Graphics.SOLID
Bảng 5.9 Lớp Graphics
(Grayscale là một số nguyên kiểu int có giá trị từ 0 đến 255 biểu thị độ sáng của
màu xám (shade of gray) )

5.2.1. Màu sắc:


Màu sắc trong đối tượng Graphics được tạo từ 3 màu cơ bản là đỏ, xanh lục và xanh
dương(RGB) được biểu diễn bởi 24 bit màu, mỗi màu chiếm 8 bit. Nếu thiết bị
không hỗ trợ hiển thị màu hay chỉ hỗ trợ với số màu ít hơn thì thiết bị sẽ tự chuyển

90
Java Mobile

đổi để hiển thị ra màu gần nhất so với yêu cầu. Grayscale dùng để hiển thị các sắc
độ màu khác nhau trên màn hình trắng đen.
Khi gán màu cho đối tượng Graphics, có thể dùng một trong 2 cách:
• Kết hợp 3 màu (đỏ, xanh dương và xanh lục) trong một số nguyên
kiểu int hay biểu diễn từng thành phần trong từng số int. Khi kết hợp 3
màu với nhau, mỗi màu được biểu diễn bởi 8 bit và xếp theo thứ tự từ cao
xuống thấp là đỏ, xanh lục và xanh dương.
R R R R R R R R G G G G G G G G B B B B B B B B
RED GREEN BLUE

Do đó, để kết hợp 3 giá trị màu này vào một số nguyên kiểu int, ta phải dịch
bit để có kết quả chính xác. Giá trị màu đỏ sẽ dịch trái 16bits, giá trị màu
xanh lục dịch trái 8 bits và giá trị màu xanh dương chiếm 8 bit thấp nhất.
VD:
int red=0; 0 0 0 0 0 0 0 0
int reen=127; 0 1 1 1 1 1 1 1
int blue=255; 1 1 1 1 1 1 1 1
int color=(red<<16) | (green<<8) | blue;

0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
RED GREEN BLUE

g.setColor(color); //g là đối tượng kiểu Graphics

//Gán giá trị cho từng màu cơ bản riêng biệt:

int red=0;
int green=127;
int blue=255;
g.setcolor(red, green, blue);

91
Java Mobile

Tương tự, khi lấy giá trị màu, ta cũng có thể lấy ra dưới dạng kết hợp hay từng màu
riêng biệt. Nếu lấy giá trị màu dưới dạng kết hợp, để có được giá trị màu cho từng
màu cơ bản cần phải bỏ đi các bit không thích hợp.
Vd:
int color, red, green, blue;
color= g.getColor(); //g là đối tượng kiểu Graphics
red=(color & 0xFF0000)>>16;
green=(color & 0xFF00)>>8;
blue=color & 0xFF;
Có thể kiểm tra thiết bị di động có màn hình màu không bằng phương thức:
javax.microedition.lcdui.Display.isColor().
Ngoài ra có thể lấy số màu thiết bị có hỗ trợ bằng phương thức
javax.microedition.lcdui.Display.numColors().
, nếu thiết bị chỉ có màn hình trắng đen thì giá trị trả về là giá trị grayscale mặc
định.

92
Java Mobile

5.2.2. Nét vẽ:


Kiểu nét vẽ (stroke style): Khi vẽ đường thẳng, đường tròn, hay hình chữ nhật, ta
có thể lựa chọn kiểu nét vẽ là nét liền (Graphics.SOLID) hay cách khoảng
(Graphics.DOTTED). Nét liền là giá trị mặc định của các kiểu vẽ.
Các phương thức vẽ:
Lớp Graphics: javax.microedition.lcdui.Canvas
Phương thức Chức năng
void drawLine (int x1, int y1, int x2, Vẽ đường thẳng từ điểm (x1, y1) đến
int y2) điểm (x2, y2)
void drawArc (int x, int y, int width, vẽ đường cong góc arcAngle bắt đầu từ
int height, int startAngle, int acrAngle) góc startAngle nội tiếp hình chữ nhật xác
định bởi góc trái trên (x,y) và chiều dài
hai cạnh width, height
void fillArc (int x, int y, int width, int vẽ đường cong góc arcAngle bắt đầu từ
height, int startAngle, int acrAngle) góc startAngle nội tiếp hình chữ nhật xác
định bởi góc trái trên (x,y) và chiều dài
hai cạnh width, height và tô màu bên
trong đường cong vừa vẽ.
void drawRect (int x, int y, int width, vẽ hình chữ nhật với góc trái trên (x,y) và
int height) chiều dài hai cạnh width, height
void drawRoundRect (int x, int y, int vẽ hình chữ nhật với các góc tròn. arcW
width, int height, int arcW, int arcH) và arcH là kích thước của hình chữ nhật
ngoại tiếp góc cong
void fillRect (int x, int y, int width, int tô hình chữ nhật
height)
void fillRoundRect (int x, int y, int tô hình chữ nhật góc tròn
width, int height, int arcW, int arcH)
Bảng 5.10 Các phương thức vẽ

93
Java Mobile

VD:
g.drawArc(5, 5, 75, 75, 0, 225);
g.drawArc(80, 70, 75, 100, 90, 225);

g.fillArc(5, 5, 75, 100, 0, 360);


g.fillArc(75, 100, 75, 50, 90, 300);

Hình 5.1 Các phương thức vẽ đường cong


Hình chữ nhật gồm 4 loại:
• Hình chữ nhật thường, không tô
• Hình chữ nhật góc cong, không tô
• Hình chữ nhật thường, tô đặc
• Hình chữ nhật góc tròn, tô đặc
Hình chữ nhật góc tròn là hình chữ nhật trong đó các góc được vẽ theo dạng đường
cong chứ không phải là góc vuông như hình chữ nhật thông thường. Trong đó các
góc cong là ¼ đường cong nội tiếp hình chữ nhật kích thước rộng dài tương ứng là
arcW và arcH.
VD:

94
Java Mobile

g.drawRect(1, 1, 60, 40);


g.drawRoundRect(70, 50, 60, 40, 30, 40);

g.fillRect(1, 1, 60, 40);


g.fillRoundRect(70, 50, 60, 40, 30, 40);

Hình 5.2 Các phương thức vẽ hình chữ nhật

Các phương thức hỗ trợ vẽ text :


Lớp Graphics: javax.microedition.lcdui.Graphics
Phương thức Chức năng
void drawChar (char character, int x, vẽ ký tự character lên màn hình
int y, int anchor)
void drawChars (char[] data, int vẽ chuỗi ký tự data với chiều dài length
offset, int length, int x, int y, int từ vị trí offset lên màn hình
anchor)
void drawString (String str, int x, int vẽ chuỗi str lên màn hình
y, int anchor)

95
Java Mobile

void drawSubstring (String str, int vẽ chuỗi con có chiều dài len , từ vị trí
offset, int len, int x, int y, int anchor) offset của chuỗi str lên màn hình
Font getFont() lấy đối tượng Font hiện tại
void setFont () gán Font cho đối tượng Graphics
Bảng 5.11 Xử lý Text
Khi vẽ text lên màn hình, bất kể đó là một ký tự hay một chuỗi ký tự, ta phải
cung cấp đủ ba tham số: x, y và anchor. Trong đó, (x, y) là toạ độ điểm gốc, và
anchor là vị trí tương đối của điểm gốc so với đoạn text sẽ được hiển thị. Các vị trí
tương đối của anchor đã được định nghĩa sẵn trong lớp Graphics, gồm:
Lớp Graphics: javax.microedition.lcdui.Graphics
Tên anchor Mô tả Vị trí
LEFT lề trái của ký tự / chuỗi chiều ngang
HCENTER điểm giữa của ký tự / chuỗi chiều ngang
RIGHT lề phải của ký tự / chuỗi chiều ngang
TOP điểm cao nhất của ký tự / chuỗi chiều dọc
BASELINE dòng chuẩn của ký tự / chuỗi chiều dọc
BOTTOM điểm cao nhất của ký tự/ chuổi chiều dọc
Bảng 5.12 Giá trị Anchor
Khi sử dụng, biến anchor thường được kết hợp bởi hai kiểu định vị theo chiều
ngang và chiều dọc để được vị trí tương đối của điểm gốc.
VD:
//vẽ chuỗi “Hello J2ME” với góc trái trên trùng góc trái trên của
màn hình
g.drawString (str, 0, 0, Graphics.TOP|
Graphics.LEFT);
//vẽ chuỗi “Hello J2ME” ngay giữa màn hình, nghĩa là điểm
giữa trùng với điểm giữa của màn hình
g.drawString (str, getWidth()/2, getHeight()/2,
Graphics.BASELINE| Graphics.HCENTER );

96
Java Mobile

//vẽ chuỗi “Hello J2ME” với phải dưới trên trùng góc phải dưới
của màn hình
g.drawString (str, getWidth(), getHeight(),
Graphics.BOTTOM | Graphics.RIGHT);
Hình 5.3 Các phương thức hỗ trợ vẽ Text

Hình 5.4 Các định dạng trong Text Graphic

97
Java Mobile

5.2.3. Font chữ:


Lớp Font:
Lớp Font: javax.microedition.lcdui.Font
Phương thức Chức năng
static Font getFont (int face, tạo đối tượng Font
int style, int size)
static Font getDefaultFont () tạo đối tượng Font mặc định
int getFace () lấy face hiện tại
int getStyle () lấy kiểu chữ (đậm, in nghiêng, gạch dưới)
int getSize () lấy cỡ chữ
boolean isPlain () kiểm tra có đang dùng kiểu chữ thường không
boolean isBold () kiểm tra có đang dùng kiểu chữ đậm không
boolean isItalic () kiểm tra có đang dùng kiểu chữ in nghiêng
không
boolean isUnderlined () kiểm tra có đang dùng kiểu chữ gạch dưới
không
int getHeight () lấy kích thước font (khoảng cách giữa 2 dòng
chữ)
int getBaselinePosition () lấy độ cao chữ
int charWidth (char ch) lấy độ rộng của ký tự ch
int charsWidth (char[] ch, int lấy độ rộng của chuỗi ký tự ch dạng mảng char
offset, int length)
int stringWidth (String str) lấy độ rộng chuỗi ký tự ch dạng String
int substringWidth (String lấy độ rộng chuỗi con của chuỗi ký tự ch dạng
str, int offset, int length) String bắt đầu từ vị trí offset với độ dài length
Bảng 5.13 Xử lý Font chữ

98
Java Mobile

Lớp Font không có phương thức khởi tạo nghĩa là không cần “new” để tạo đối
tượng mới, thay vào đó, ta gọi thực hiện một trong hai phương thức getFont() hay
getDefaultFont() để tạo đối tượng Font.
Các thuộc tính cần quan tâm khi tạo mớo một font gồm: face, kiểu chữ (style) và
kích thước. Các định dạng của mỗi loại thuộc tính đã được định nghĩa sẵn trong lớp
Font với, gồm:

Lớp Font: javax.microedition.lcdui.Font


Loại Tên thuộc tính Mô tả Giá trị
thuộc tính
FACE_SYSTEM 0
Face FACE_MONOSPACE 32
FACE_PROPORTIONAL 64
STYLE_PLAIN chữ thường 0
STYLE_BOLD in đậm 1
Style
STYLE_ITALIC in nghiêng 2
STYLE_UNDERLINED gạch dưới 4
SIZE_SMALL cỡ chữ nhỏ 8
Size SIZE_MEDIUM cỡ chữ trung bình 0
SIZE_LARGE cỡ chữ lớn 16
Bảng 5.14 Các giá trị Font
Trong đó, thuộc tính face và cỡ chữ của font chỉ được sử dụng duy nhất một loại
định dạng cho một đối tượng. Riêng với thuộc tính kiểu chữ, có thể kết hợp các
định dạng trong cùng một đối tượng Font bằng toán tử OR.
VD:

99
Java Mobile

//tạo đối tượng Font có thuộc tính Face kiểu system, cỡ chữ
trung bình và có kiểu chữ in nghiêng và đậm:
Font font= Font.getFont( Font.FACE_SYSTEM,
Font.STYLE_BOLD | Font.STYLE_ITALIC |
Font.STYLE_UNDERLINED,
Font.SIZE_MEDIUM);

Hình 5.5 Các phương thức tạo font

//lấy thuộc tính face, cỡ chữ của đối tượng Font


int face = font.getFace();
int size = font.getSize();

//kiểm tra kiểu chữ đối tượng Font:


//cách 1:
int style = font.getStyle();
if (style== (Font.STYLE_BOLD | Font.STYLE_ITALIC))

//cách 2: sử dụng các phương thức kiểm tra isPlain(), isBold(), isItalic() và isUnderlined()
if (font.IsBold() && font.IsItalic())

100
Java Mobile

5.2.4. Vẽ các đối tượng hình ảnh (image):


Lớp Graphics hỗ trợ một phương thức duy nhất để vẽ hình ảnh lên màn hình, đó là:
Lớp Graphics: javax.microedition.lcdui.Graphics
Phương thức Mô tả
void drawImage (Image img, int x, int vẽ đối tượng Image img lên màn hình
y, int anchor)
Bảng 5.15 Vẽ hình ảnh

Đây chỉ là bước cuối cùng để vẽ một hình ảnh lên màn hình, các bước trước đó
dùng để tạo đối tượng Image cũng như load hình ảnh lên đối tượng đó. Đối tượng
Image gồm hai loại: có thể thay đổi hình ảnh (Mutable Image) và hình ảnh cố định
(Immutable Image).

Các bước để vẽ đối tượng Image lên màn hình:


• Immutable Image:
1. Tạo đối tượng hình ảnh (thường là load trực
tiếp từ file):
Image img= Image.createImage
(“\imageTest.png”);
2. Hiển thị đối tượng lên màn hình:
protected void paint (Graphics g) {

g.drawImage(img, 10, 10,
Graphics.LEFT | Graphics.TOP);
}
Hình 5.6 Vẽ bằng đối tượng Immutable Image

101
Java Mobile

• Mutable Image:
Khởi tạo đối tượng, yêu cầu chương trình cấp một
vùng nhớ với kích thước cho trước của hình ảnh:
Image img = Image.createImage(80,100);
Vẽ hình ảnh lên đối tượng :
//lấy đối tượng Graphics tương ứng của đối tượng Image:
Graphics g = img.getGraphics();
//dùng đối tượng Graphics vừa lấy vẽ các hình ảnh lên đối
tượng Image:
g.fillRoundRect (0, 0, 50, 50, 20, 20);

Hiển thị hình vừa vẽ lên màn hình:
protected void paint (Graphics g) {

g.drawImage(img, 10, 10,


Graphics.VCENTER | Graphics.HCENTER);
}
Hình 5.7 Vẽ bằng đối tượng Mutable Image

Khi gọi phương thức vẽ đối tượng Image lên màn hình, ta cũng phải truyền các
tham số x, y, anchor như khi vẽ text. Tuy nhiên, các loại anchor của hình ảnh tương
đối khác với text, đó là không sử dụng anchor BASELINE(đường chẩn của ký tự /
chuỗi) mà thay vào đó là VCENTER để chỉ điểm giữa theo chiều dọc của hình ảnh
Lớp Graphics: javax.microedition.lcdui.Graphics
Tên anchor Mô tả Vị trí
LEFT lề trái của hình ảnh chiều ngang
HCENTER điểm giữa của hình ảnh chiều ngang
RIGHT lề phải của hình ảnh chiều ngang
TOP điểm cao nhất của hình ảnh chiều dọc

102
Java Mobile

VCENTER điểm giữa của hình ảnh chiều dọc


BOTTOM điểm cao nhất của hình ảnh chiều dọc
Bảng 5.16 Giá trị Image Anchor

Hình 5.8 Các định dạng vị trí trong Graphics

5.2.5. Các phương thức tịnh tiến đối tượng:


Để đơn giản khi biểu diễn sự tịnh tiến của các đối tượng hình ảnh trên màn hình,
lớp Graphics cho phép người lập trình vẽ các đối tượng ở vị trí cố định. Khi cần tịnh
tiến các đối tượng trên màn hình thì chỉ cần tịnh tiến gốc toạ độ đến vị trí mới, các
hình ảnh của đối tượng Graphics sẽ tịnh tiến theo.

Lớp Graphics: javax.microedition.lcdui.Graphics


Phương thức Mô tả
void translate(int x, int y) tịnh tiến điểm gốc (0, 0) của đối tượng Graphics
đến vị trí (x,y)
int getTranslateX() lấy khoảng cách trên trục hoành đã bị tịnh tiến
int getTranslateY() lấy khoảng cách trên trục tung đã bị tịnh tiến
Bảng 5.17 Các phương thức tịnh tiến
Khi gọi thực hiện phương thức translate() để tịnh tiến hình ảnh trên màn hình thì chỉ
có gốc tọa độ bị thay đổi vị trí, và cũng chỉ có ý nghĩa trong lần gọi hàm đó. Nếu
gọi thực hiện phương thức repaint() mà không gọi translate() lần nữa thì toạ độ gốc
sẽ trở về vị trí (0,0) ban đầu.
VD:
//khi người dùng nhấn phím mũi tên xuống thì tịnh tiến hình ảnh xuống một pixel:

103
Java Mobile

protected void keyPressed(int keyCode) {


switch (getGameAction(keyCode)) {
...
case DOWN:
if ((translatey + img.getHeight() + 1) > getHeight())
translatey = 0;
else
translatey ++;
break;
...
}
repaint();
}

protected void paint(Graphics g){


if (im != null){
//xoá màn hình
g.setColor(255, 255, 255);
g.fillRect(0, 0, getWidth(), getHeight());
//tịnh tiến gốc toạ độ
g.translate(translatex, translatey);
// luôn vẽ ở vị trí 0,0
g.drawImage(im, 0, 0, Graphics.LEFT | Graphics.TOP);
}
}

104
Java Mobile

5.2.6. Vùng xén (Clipping regions):


Mỗi lần gọi phương thức paint(), toàn bộ màn hình sẽ được vẽ lại. Vùng xén được
dùng để giới hạn lại vùng cần vẽ lại, làm giảm thời gian cần để vẽ lại màn hình.
Bình thường, nếu không tạo vùng xén thì vùng xén mặc định sẽ là hình chữ nhật
bao của màn hình (tức là hình chữ nhật (0,0,Canvas.getWidth(),
Canvas.getHeight()) )

Các phương thức hỗ trợ xén:


Lớp Graphics: javax.microedition.lcdui.Graphics
Phương thức Mô tả
void setClip (int x, int y, int xác định vùng xén (hình chữ nhật góc trái trên
width, int height) (x, y) kích thước hai cạnh là width và height)
void clipRect (int x, int y, int vùng xén là phần giao của vùng xén hiện tại
width, int height) với hình chữ nhật (x, y, width, height)
int getClipX () Lấy toạ độ x góc trái trên của vùng xén
int getClipY () Lấy toạ độ y góc trái trên của vùng xén
int getClipHeight () Lấy độ dài vùng xén
int getClipWidth () Lấy độ rộng vùng xén
Bảng 5.18 Vùng xén

105
Java Mobile

Chương 6: Lưu trữ thông tin với RMS

6.1. Giới thiệu RMS


Việc lưu trữ và truy xuất thông tin có thể xem là một yêu cầu bắt buộc với các
ứng dụng ngày nay. Với các chương trình viết cho máy tính để bàn, công việc này
được các ngôn ngữ lập trình hỗ trợ rất tốt. Chúng ta có thể lưu trữ thông tin vào đĩa
cứng, đĩa CD, các đĩa trên môi trường mạng… Tuy nhiên, công việc lưu trữ thông
tin trên môi trường di động có nhiều khác biệt. Môi trường MIDP không hề đặt ra
bất kỳ một đặc tả nào qui định về hệ thống file (file system) trên các thiết bị di
động, do đó trên các thiết bị này chúng ta không hề có khái niệm file hay directory.
Điều này gây nhiều ngạc nhiên cho những lập trình viên bắt đầu nghiên cứu về
J2ME, tuy nhiên nếu chúng ta biết rằng MIDP hướng đến việc lập trình trên các môi
trường có tài nguyên hạn chế như các đầu thu tín hiệu truyền hình số, máy nhắn tin
pagers… thì việc qui định các chuẩn về hệ thống tập tin là không cần thiết và bất
khả thi.
Điều này không có nghĩa rằng chúng ta không thể lưu trữ thông tin trên các thiết
bị di động, CLDC/MIDP có một công cụ riêng phục vụ cho công việc này, đó là
RMS (Record Management System). Việc lưu trữ sẽ được thực hiện thông qua các
record, chúng ta còn được hỗ trợ các công cụ để lọc thông tin, sắp xếp thông tin, tìm
kiếm thông tin trên các records.

Ghi chú: Khái niệm lưu trữ thông tin ở phần này đề cập đến việc lưu trữ lâu dài,
không bị mất khi ngắt nguồn điện (persistent storage) chứ không đề cập đến việc
lưu trữ lên bộ nhớ trong (RAM).

Lưu trữ thông tin thông qua các Record Store

106
Java Mobile

Thay thế cho hệ thống file, thiết bị MIDP lưu trữ thông tin qua các record stores.
Chúng ta có thể xem các record store này như một bảng dữ liệu gồm nhiều dòng
record. Mỗi dòng record có một số ID và gồm một mảng các bytes. Người ta
thường xem record store như một cấu trúc file phẳng (flat-file).

Record ID Data
1 Mảng các bytes
2 Mảng các bytes
3 Mảng các bytes
……………. ………………….
Bảng 6.1 Mô hình Record Store
Mỗi record có một trường Record ID có kiểu dữ liệu integer, đóng vai trò như
khóa chính trong bảng dữ liệu và một trường “Data” là một mảng các bytes để chứa
dữ liệu. Một tập hợp các record này được gọi là một record store (tương ứng với
một bảng dữ liệu). Một ứng dụng MIDlet có thể có bao nhiêu record store tùy ý (kể
cả không có), mỗi record store được phân biệt bởi tên định danh duy nhất. Mở rộng
ra, các Record Stores của các ứng dụng MIDlet cùng chung một bộ (suite) thì cũng
phải có tên phân biệt.
Tên của record store có thể chứa đến 32 ký tự Unicode (16 bits) và tên này phân
biệt hoa thường.
Các ứng dụng MIDlet không những truy xuất được các record stores do nó tạo ra
mà còn truy xuất được các record stores do các ứng dụng khác trong cùng một bộ
(MIDlet Suite) tạo ra. Đây là một lý do khiến các nhà phát triển đặt ra khái niệm
MIDlet Suite, tuy nhiên các MIDlet không cùng một suite không thể truy xuất
Record Suite của nhau. Đây là một hạn chế của Record Store khi so sánh với hệ
thống file trên các thiết bị khác.
Một record store quản lý hai thông số để quản lý việc truy cập dữ liệu, hai thông
số này tự động được cập nhật khi có record được thêm, xóa hay sửa:

107
Java Mobile

• Số Version : đây là một giá trị integer. Tuy nhiên, có một điều không may là
giá trị khởi điểm của version không được định nghĩa bởi API. Nếu chúng ta
cần biết giá trị ban đầu này, ngay sau khi tạo record mới ta có thể gọi hàm
getVersion().
• Ngày tháng: là một số long, thể hiện số millisecond tính từ nửa đêm ngày
1/1/1970. Chúng ta có thể lấy ra thông số này bằng hàm getLastModified().
Các yêu cầu xử lý record store được thiết bị đồng bộ hóa tự động: khi có hai hay
nhiều yêu cầu xử lý thì yêu cầu đến trước được xử lý trước và các yêu cầu xử lý
khác sẽ được đặt vào hàng đợi.
Các hàm xử lý Record Store thông dụng:
Lớp javax.microedition.rms.RecordStore
Phương thức Mô tả
Constructor: Không có phương thức khởi tạo
static RecordStore Mở một record store, tùy chọn tạo mới
openRecordStore(String nếu record store chưa tồn tại.
recordStoreName, boolean
createIfNeccessary)
void closeRecordStore() Đóng record store
static void deleteRecordStore(String Xóa record store
rcdStoreName)
static String[] listRecordStore() Liệt kê các record stores trong MIDlet
Suite
int addRecord(byte[] data, int offset, int Thêm một record
numBytes)
void setRecord(int recordID,byte[] Thay đổi nội dung một record.
newData,int offset, int numBytes)
void deleteRecord(int RecordID) Xóa một record khỏi record store
byte[] getRecord(int RecordID) Lấy mảng byte chứa nội dung record

108
Java Mobile

int getRecord(int RecordID, byte[] Lấy nội dung record từ vị trí offset đưa
buffer, int offset) vào mảng byte.
int getRecordSize(int RecordID) Lấy kích thước của record
int getNextRecordID() Lấy ID của record tiếp theo
int getNumRecords() Lấy số lượng Record trong Record
Store
long getLastModified() Thời điểm thay đổi cuối cùng của
Record Store
int getVersion() Lấy version của Record Store
String getName() Lấy tên của Record Store
int getSize() Tổng số bytes được sử dụng bởi Record
Store
int getSizeAvailable() Lấy dung lượng còn lại (bytes) được
phép dùng bởi Record Store.
RecordEnumeration enumerateRecords Bổ sung chức năng duyệt các record
(RecordFilter filter, RecordComparator dưới dạng một tập hợp. (sẽ được đề cập
comparator, boolean keepUpdate) sau)
void addRecordListener(RecordListener Thêm một bộ lắng nghe trên Record
listener) Store (sẽ được đề cập sau)
void removeRecordListener Gỡ bỏ bộ nghe (sẽ được đề cập sau)
(RecordListener listener)
Bảng 6.2 Lớp RecordStore
Ghi chú: Record ID được tính bắt đầu từ 1 chứ không phải từ 0 như chỉ số mảng.
Sau đây là một ví dụ về việc nhập xuất dữ liệu thông qua record store bằng kỹ thuật
stream. Ví dụ đã được tinh giản và chỉ trình bày những phân đoạn chính.

//Import các thư viện cần thiết


import java.io.*;
import javax.microedition.midlet.*;

109
Java Mobile

import javax.microedition.rms.*;

public class ReadWriteStreams extends MIDlet {


private RecordStore rs = null; // Record Store
static final String REC_STORE = "db_1"; // Tên của Record Store
public ReadWriteStreams() {
openRecStore(); // Hàm tạo Record Store
writeTestData(); // Hàm ghi dữ liệu
readStream(); // Hàm đọc dữ liệu
closeRecStore(); // Đóng Record Store
deleteRecStore(); // Xóa Record Store
}

public void startApp() {
// Không có giao diện, chương trình sẽ ghi, đọc dữ liệu và thoát
destroyApp(false);
notifyDestroyed();
}
public void openRecStore() {
try {
// Tạo record store mới nếu chưa tồn tại
rs = RecordStore.openRecordStore(REC_STORE, true );
}
catch (Exception e) {
//Xuất thông báo lỗi
}
}
public void closeRecStore() {
try {
rs.closeRecordStore();

110
Java Mobile

}
catch (Exception e) {
//Xuất thông báo lỗi
}
}
public void deleteRecStore(){
if (RecordStore.listRecordStores() != null){
try{
RecordStore.deleteRecordStore(REC_STORE);
}
catch (Exception e){
//Xuất thông báo lỗi
}
}
}
/*--------------------------------------------------
* Tạo 3 mảng để mô phỏng việc ghi dữ liệu
*-------------------------------------------------*/
public void writeTestData() {
String[] strings = {"String 1", "String 2"};
boolean[] booleans = {false, true};
int[] integers = {1 , 2};
writeStream(strings, booleans, integers);
}
/*--------------------------------------------------
* Viết vào record store dùng stream
*-------------------------------------------------*/
public void writeStream(String[] sData, boolean[] bData, int[] iData) {
try{

111
Java Mobile

/* Tạo stream để viết dữ liệu, ở đây ta tạo ra 2 streams, một


stream có tác dụng như buffer, stream còn lại để ghi dữ liệu
vào Record*/
//Buffer
ByteArrayOutputStream strmBytes =
new ByteArrayOutputStream();

DataOutputStream strmDataType =
new DataOutputStream(strmBytes);

byte[] record;
//Ba mảng có kích thước bằng nhau
for (int i = 0; i < sData.length; i++) {
// Ghi dữ liệu
strmDataType.writeUTF(sData[i]);
strmDataType.writeBoolean(bData[i]);
strmDataType.writeInt(iData[i]);
strmDataType.flush();
// Biến dữ liệu trong stream thành dạng mảng để ghi vào
//record, vì các record chỉ chấp nhận dữ liệu dạng mảng
record = strmBytes.toByteArray();
rs.addRecord(record, 0, record.length);
// Xóa hết dữ liệu trong buffer để tiếp tục ghi các phần
//tử tiếp theo của mảng
strmBytes.reset();
}
//Sau khi hoàn tất việc ghi các mảng, đóng các stream
strmBytes.close();
strmDataType.close();
}

112
Java Mobile

catch (Exception e){


//Xuất các thông báo lỗi
}
}
/*--------------------------------------------------
* Đọc lại dữ liệu đã được ghi
*-------------------------------------------------*/
public void readStream(){
try{
// Tạo một mảng có kích thước đủ lớn
// Trong thực tế nên kiểm tra và cấp phát lại kích thước nếu cần
byte[] recData = new byte[50];
// Tạo một stream làm buffer lấy dữ liệu từ mảng recData
ByteArrayInputStream strmBytes =
new ByteArrayInputStream(recData);
// Tạo stream để xuất dữ liệu theo đúng khuôn dạng đã ghi
DataInputStream strmDataType =
new DataInputStream(strmBytes);
for (int i = 1; i <= rs.getNumRecords(); i++){
// Lấy dữ liệu đưa vào mảng
rs.getRecord(i, recData, 0);
// Đọc lại theo đúng thứ tự đã ghi
System.out.println("Record #" + i);
System.out.println("UTF:" + strmDataType.readUTF());
System.out.println("Boolean: " +
strmDataType.readBoolean());
System.out.println("Int: " + strmDataType.readInt());
System.out.println("--------------------");
// Xóa dữ liệu buffer để bắt đầu ghi các phần tử tiếp theo
strmBytes.reset();

113
Java Mobile

}
strmBytes.close();
strmDataType.close();
}
catch (Exception e){
//Xuất các thông báo lỗi
}
}

}

Ví dụ trên đã nêu một cách cơ bản nhất các bước cần thiết để ghi dữ liệu và truy
xuất dữ liệu bằng record store. Ví dụ đã được tinh giản và chỉ nêu các hàm thật cần
thiết. Việc mở, ghi record, đọc record, đóng và xóa record được thể hiện thành từng
hàm riêng biệt để tiện theo dõi. Trong ví dụ trên có một số điểm ta cần chú ý:
Chỉ số RecordID bắt đầu từ 1 chứ không phải từ 0 như chỉ số của các phần tử trong
mảng. Nếu ta cố gắng truy xuất phần tử số 0 sẽ phát sinh lỗi.
Tương tự như các hàm truy xuất I/O khác của Java, các hàm liên quan đến Record
Store cần phải được đưa vào trong khối try – catch vì các hàm này có thể phát sinh
các exceptions.
Trong ví dụ trên chúng ta dùng stream để ghi và xuất dữ liệu có khuôn dạng; do đó
khi chúng ghi theo trình tự nào thì xuất cũng phải theo trình tự đó.

114
Java Mobile

6.2. Duyệt danh sách Record với RecordEnumeration

Ngay trên ví dụ vừa rồi, chúng ta duyệt qua danh sách các records trong record
store bằng dòng lặp. Đây là các tiếp cận được những lập trình viên nghĩ đến ban đầu
vì chúng ta đã nhận định các record như các dòng trong một bảng của CSDL. Tuy
nhiên, MIDP cung cấp cho chúng ta một công cụ thuận tiện và chính xác hơn để
duyệt qua các record trong một record store. Chúng ta đề cập đến khái niệm “chính
xác hơn” ở đây vì lý do khi duyệt bằng vòng lặp thực chất có thể gây nên một
exception trong chương trình. Giả sử chúng ta có 3 record đánh số từ 1 đến 3, vì lý
do nào đó chúng ta xóa record số 2 bằng phương thức deleteRecord(int RecordID)
thì số 2 không bao giờ được sử dụng để gán làm RecordID cho một record khác.
Vậy khi ta duyệt bằng vòng lặp, giả sử i từ 1 đến 3, khi giá trị i=2 sẽ gây ra một lỗi
exception. Khi đó, chúng ta bắt buộc phải duyệt bằng công cụ enumeration. Ngoài
ra, khi chúng ta sử dụng các chức năng lọc (filter) và sắp xếp (sort) các record, giá
trị trả về sẽ là một RecordEnumeration vì các RecordID lúc này không tuân theo bất
kỳ một thứ tự nào cả.
Việc tạo ra một RecordEnumeration là một công việc đơn giản, chỉ tốn một vài
dòng lệnh. Lớp RecordEnumeration không có phương thức khởi tạo (constructor),
ta tạo ra RecordEnumeration bằng phương thức enumerateRecord(…) của lớp
RecordStore
Ví dụ:
RecordEnumeration re = rs.enumerateRecords(null,null,false);
while (re.hasNextElement()) {
// lấy thông tin record tiếp theo ra buffer
String str = new String(re.nextRecord());
//xử lý tùy theo yêu cầu
}

115
Java Mobile

Hàm enumerateRecord nhận vào ba tham số:


• Tham số đầu là bộ lọc (filter), nếu không muốn lọc record ta để null
• Tham số thứ nhì là bộ sắp xếp (sort), nếu không muốn sắp xếp ta cũng để
null. Nếu cả hai tham số trên đều là null thì các record được lấy ra và sắp xếp
theo thứ tự bất kỳ.
• Tham số cuối cùng là một biến boolean bUpdate, nếu bUpdate là true thì khi
danh sách các record có sự thay đổi (bị thêm, xóa hay sửa) biến
RecordEnumeration sẽ tự cập nhật, nếu là false chúng ta phải tự cập nhật
bằng hàm rebuild().
Sau đây là các hàm thông dụng nhất của lớp RecordEnumeration
Lớp javax.microedition.rms.RecordEnumeration
Phương thức Chức năng
Construtor Không có constructor, tạo từ lớp RecordStore
int numRecords() Số lượng records trong tập hợp
byte[] nextRecord() Lấy record kế tiếp, duyệt theo thứ tự tiến
(forward)
int nextRecordId() Lấy RecordID của record kế tiếp
byte[] previousRecord() Lấy record trước đó, duyệt theo thứ tự lùi
(backward)
int previousRecordId() Lấy RecordID của record trước đó
boolean hasNextElement() Kiểm tra còn record để tiếp tục duyệt tiến
(forward) hay không?
bolean hasPrevioussElement() Kiểm tra còn record để tiếp tục duyệt lùi
(backward) hay không?
void keepUpdate(boolean Bật, tắt chế độ tự cập nhật của enum
keepUpdate)
boolean isKeptUpdate() Kiểm tra xem enum có chức năng tự cập nhật
hay không?

116
Java Mobile

void rebuild() Tự cập nhật lại enumeration


void reset() Đưa enumeration về trạng thái ban đầu, lúc vừa
khởi tạo
void destroy() Trả lại hết tài nguyên giữ bởi biến enum này.
Bảng 6.3 Lớp RecordEnumeration

6.3. Sắp xếp bằng RecordComparator


Yêu cầu sắp xếp dữ liệu là một yêu cầu thường được đặt ra cho các ứng dụng
tiện ích. Công việc này trên các máy desktop thường được thực hiện thông qua các
hệ quản trị cơ sở dữ liệu, trên môi trường J2ME chúng ta cũng có một công cụ khá
hiệu quả để sắp xếp dữ liệu trên Record Store, đó là RecordComparator.
RecordComparator là một Java interface, khi có nhu cầu sắp xếp dữ liệu thì ứng
dụng của ta phải cài đặt (implements) interface này.
Sau đây là một ví dụ của lớp có cài đặt interface RecordComparator:
public class Comparator implements RecordComparator {
public int compare(byte[] rec1, byte[] rec2) {
String str1 = new String(rec1), str2 = new String(rec2);
int result = str1.compareTo(str2);
if (result == 0)
return RecordComparator.EQUIVALENT;
else if (result < 0)
return RecordComparator.PRECEDES;
else
return RecordComparator.FOLLOWS;
}
}

Chúng ta cài đặt interface này bằng cách cung cấp hàm int compare(byte[],byte[]).
Hàm này trả về 3 giá trị đặc biệt đã được định nghĩa trước là:

117
Java Mobile

• RecordComparator.EQUIVALENT
• RecordComparator.PRECEDES
• RecordComparator.FOLLOWS
Khi đó, để bắt đầu quá trình sắp xếp và xử lý dữ liệu ta tạo ra một đối tượng
Comparator (lớp có cài đặt RecordComparator) và một RecordEnumeration:

// Tạo đối tượng Comparator để sắp xếp


Comparator comp = new Comparator();
// Tạo đối tượng enum, tham số thứ nhì là comparator
RecordEnumeration re = rs.enumerateRecords(null,comp,false);
// Duyệt danh sách thông qua enum
while (re.hasNextElement()) {
String str = new String(re.nextRecord());
...
}

Lúc này hàm compare trong lớp Comparator sẽ được dùng làm cơ sở để sắp xếp
các record. Hàm này nhận vào hai tham số là hai mảng byte (là 2 record dùng để so
sánh).
int compare (byte[] r1, byte[] r2)
Tùy theo giá trị trả về của hàm mà record r1 sẽ được xếp trước record r2, xếp sau r2
hay 2 records được xem là “bằng nhau”.

Giá trị Ý nghĩa


EQUIVALENT Record r1 và r2 được xem là bằng nhau, thực chất lúc này r1
được xếp trên r2 vì không có sự thay đổi thứ tự
FOLLOWS Record r1 được xem là “lớn hơn” r2 và sẽ xếp sau.
PRECEDES Record r1 được xem là “nhỏ hơn” r2 và sẽ xếp trước.
Bảng 6.4 Các giá trị hằng để sắp xếp record

118
Java Mobile

Lúc này, khi ta dùng hàm enumerateRecords(…) của lớp RecordStore, kết quả
trả về sẽ là một tập hợp (enum) đã được sắp thứ tự và ta có thể thao tác trên tập hợp
này một cách bình thường.
Nguyên lý sort thực chất cũng khá đơn giản: đối với những record gồm nhiều
trường (compound record), khi chúng ta có nhu cầu chỉ search trên một trường bất
kỳ thì trước nhất phải đọc trường đó của 2 record cần so sánh ra 2 biến trung gian.
Sau đó việc so sánh 2 records trên thực chất là việc so sánh 2 biến trung gian. Tùy
theo nhu cầu sort ta sẽ gán giá trị trả về cho hàm compare của lớp Comparator một
cách tương ứng.

6.4. Lọc record với RecordFilter


Ngoài chức năng sắp xếp các record, J2ME còn hỗ trợ chúng ta công cụ lọc các
record. Phần vừa rồi chúng ta đề cập đến việc sắp xếp các record và đưa vào tập
hợp, quá trình này ứng dụng sẽ sắp xếp tất cả các records có trong record store. Nếu
chúng ta chỉ có nhu cầu lấy ra và sắp xếp các record thỏa mãn một yêu cầu nhất
định nào đó (ví dụ trường năm sinh trong record phải nhỏ hơn 1990) thì ta phải
dùng thêm công cụ RecordFilter. Cũng giống như RecordComparator, RecordFilter
là một interface, khi ta có nhu cầu lọc record thì ta phải cài đặt (implements)
interface này qua hàm boolean matches(byte[] candidate).
Hàm matches(byte[] candidate) này nếu trả về giá trị true thì record candidate sẽ
có mặt trong RecordEnumeration, ngược lại nếu trả về giá trị false thì record sẽ bị
loại.
Giả sử ta có bài toán lọc theo năm sinh như sau: Trong một record sẽ có hai
trường, trường HoTen được lưu dưới dạng String UTF8 và trường năm sinh lưu
dưới dạng integer. Ta cần lấy ra danh sách những người sinh trước năm 1990. Bài
toán được giải quyết như sau:

public class YearFilter implements RecordFilter{


private int Year=1990;

119
Java Mobile

public boolean matches(byte[] candidate) {


String HoTen;
Int NamSinh;
ByteArrayInputStream strm=new ByteArrayInputStream(candidate);
DataInputStream dataStrm=new DataInputStream(strm);
Hoten=dataStrm.readUTF();
NamSinh=dataStrm.readInt();
return (NamSinh<Year) ? true:false;
}
}

public class MIDletApp extends MIDlet {



MIDletApp{
YearFilter filter=new YearFilter;
RecordEnumeration enum=rs.enumerateRecords(filter,null,true);
while (enum.hasNextElement()) {
//Xuất danh sách các cá nhân thỏa yêu cầu
}
}

120
Java Mobile

6.5. Nhận thông điệp khi Record Store thay đổi


Đôi khi chúng ta có nhu cầu cần được thông báo mỗi khi các records trong
record store bị thay đổi, xóa hay được thêm vào. Để phục vụ cho nhu cầu này,
J2ME cung cấp cho chúng ta interface RecordListener. Interface này hoạt động
tương tự các interface chúng ta đã đề cập đến trong phần RMS này. Khi lớp ứng
dụng của ta cài đặt interface này, nếu có sự biến đổi nào trên các records của bộ
record store chúng ta sẽ nhận được thông điệp thông qua các hàm recordAdded(),
recordChanged() và recordDeleted().
Phương thức Ý nghĩa
void recordAdded(RecordStore recordStore, int Được gọi khi có một record
recordId) được thêm vào record store
void recordChanged(RecordStore recordStore,int Được gọi khi có một record bị
recordId) thay đổi nội dung.
void recordDeleted(RecordStore recordStore, int Được gọi khi một record bị
recordId) xóa khỏi record store.
Bảng 6.5 Lớp RecordListener

Các hàm sự kiện trên đều có hai tham số:


• RecordStore recordStore: cho biết record store nào bị thay đổi.
• int recordID: cho biết ID của record bị thay đổi

121
Java Mobile

6.6. Xử lý lỗi khi thao tác với Record Store

Hãng Sun đã đặt ra tổng cộng 5 exceptions dành riêng cho việc xử lý RMS. Tất cả
các exception này đều kế thừa từ lớp java.lang.Throwable, sau đây là danh sách các
exception trên và ý nghĩa của chúng:

InvalidRecordIDException:
Được dùng để thông báo người dùng truy xuất đến RecordID không hợp lệ. Ví dụ
như khi hàm RecordStore.getRecord(int ID) được gọi và tham số ID bằng 0 thì
exception này sẽ phát sinh.
Constructor:
public InvalidRecordIDException(String message)
public InvalidRecordIDException()
RecordStoreException:
Một exception dạng “chung chung”, được phát sinh khi có lỗi xảy ra do truy xuất
record store.
Constructor:
public RecordStoreException()
public RecordStoreException(String message)
RecordStoreFullException
Thông báo record store đã đầy: ví dụ khi gọi hàm RecordStore.add
Record(byte[],int,int) để thêm một record, nếu record này đã đạt đến dung lượng tối
đa sẽ phát sinh exception dạng này.
Constructor
public RecordStoreFullException()
public RecordStoreFullException(String message)

122
Java Mobile

RecordStoreNotFoundException
Thông báo tên của record store không tồn tại. Ví dụ khi ta gọi hàm
RecordStore.deleteRecordStore (String) với một tên không tồn tại thì exception này
sẽ phát sinh.
Constuctor:
public RecordStoreNotFoundException()
public RecordStoreNotFoundException(String message)
RecordStoreNotOpenException
Được phát sinh khi ta thực hiện một số công việc truy vấn trên record store như
thêm record, xóa record, đếm số record mà record store chưa được mở trước đó
Consturctor
public RecordStoreNotOpenException()
public RecordStoreNotFoundOpen(String message)

123
Java Mobile

Chương 7: Kết nối mạng với Generic


Connection Framework (GCF)

7.1. Giới thiệu GFC


Trong bộ J2SE và J2EE chúng ta thực hiện các công việc liên quan đến truy xuất
tài nguyên mạng qua hai packages chính là: java.io và java.net. Với kích thước hơn
200 kbytes và bao gồm hơn 100 lớp và interfaces, cách thức truy xuất thông qua hai
gói io và net này vượt quá khả năng của thiết bị J2ME. Ngoài ra, trong bộ J2EE và
J2SE này, nhà phát triển còn chú trọng nhiều đến các phương thức mạng và hệ
thống file system trong khi thiết bị J2ME lại không quan tâm nhiều đến các vấn đề
này. Vì các lý do trên, bộ thư viện Generic Connection Framework (GCF) đã được
phát triển và nhắm đến các thiết bị di động J2ME.
Các nhà phát triển không đưa ra mục tiêu phát triển một bộ thư viện cung cấp
các lớp, phương thức hoàn toàn mới mà họ muốn đưa ra một bộ thư viện con của
các thư viện đã được phát triển khá tốt trên môi trướng J2SE và J2EE. Bộ thư viện
con này sẽ có một số thay đổi nhỏ để thích ứng với các hạn chế trên thiết bị di động
cài đặt MIDP.

7.2. Lược đồ lớp


Mục tiêu chung đươc đề ra là chúng ta cần có một lớp chính: lớp Connector.
Lớp này sẽ có khả năng tạo các loại kết nối khác nhau: http, datagram, file…
Phương thức mở kết nối sẽ có dạng:
Connector.Open("protocol:address;parameters");
Ví dụ:
Connector.Open("http://www.some_web_address.com");
Connector.Open("socket://someaddress:1234");
Connector.Open("file://testdata.txt");

124
Java Mobile

Lúc này GCF cho thấy khả năng linh hoạt của mình. Tùy theo các protocol khác
nhau mà một kết nối loại tương ứng sẽ được mở và trả lại cho người dùng. Lớp
Connector sẽ tìm kiếm các lớp cài đặt cho loại protocol được yêu cầu, việc này
được thực hiện thông qua phương thức Class.forName(). Ví dụ khi có một yêu cầu
mở kết nối HTTP, lớp Connector sẽ thực thi hàm:
Class.forName(“com.sun.midp.io.j2me.http.Protocol”);
Sau khi kiểm tra, nếu lớp này tồn tại thì người dùng sẽ được trả lại một đối
tượng cài đặt (implements) interface Connection và các thao tác truy cập sẽ được
thực hiện thông qua đối tượng này. Lớp Connector và interface Connection được
định nghĩa trong CLDC.
Lược đồ các lớp trong thư viện:

Hình 7.1 Lược đồ các lớp trong thư viện GCF

Thực chất CLDC chỉ cung cấp các định nghĩa cho các interface. Quá trình cài
đặt (implement) các protocols được thực hiện trong Profiles. Ví dụ, trong MIDP 1.0
lớp HTTPConnection sẽ cài đặt (chỉ một phần) bộ giao thức HTTP 1.1. Lớp

125
Java Mobile

HTTPConnection cài đặt interface ContentConnection và có hơn 20 phương thức để


hỗ trợ người dùng tương tác với giao thức HTTP.
Mặc dù DatagramConnection được biểu diển trên lược đồ nhưng MIDP 1.0 chỉ
yêu cầu bắt buộc hỗ trợ giao thức HTTP. Các nhà phát triển có thể hỗ trợ thêm các
giao thức khác nhưng điều này không bắt buộc.
Trong MIDP 2.0, chúng ta được hỗ trợ các phương thức kết nối thông qua TCP
và UDP. Tuy nhiên, ở phần này chúng ta chú trọng đến việc kết nối thông qua
HTTP, đây là yêu cầu bắt buộc với các thiết bị MIDP.

Sau đây là danh sách các lớp,interfaces và hàm chính trong bộ GCF:

Connection (public abstract interface Connection)


public void close()
InputConnection (public abstract interface InputConnection extends Connection)
public InputStream openInputStream()
public DataInputStream openDataInputStream()
OutputConnection (public abstract interface OutputConnection extends Connection)
public OutputStream openOutputStream()
public DataOutputStream openDataOutputStream()
StreamConnection (public abstract interface StreamConnection extends
InputConnection, OutputConnection)
ContentConnection (public abstract interface ContentConnection extends
StreamConnection)
public long getLength()
public String getEncoding()
public String getType()
HttpConnection (public interface HttpConnection extends ContentConnection)
//Hơn 20 phương thức hỗ trợ truy cập HTTP
Connector (public class Connector)

126
Java Mobile

public static Connection open(String name)


public static Connection open(String name, int mode)
public static Connection open(String name, int mode, boolean
timeouts)
public static DataInputStream openDataInputStream(String name)
public static DataOutputStream openDataOutputStream(String name)
public static InputStream openInputStream(String name)
public static OutputStream openOutputStream(String name)

7.3. Kết nối HTTP:


Trong MIDP 1.0, phương thức duy nhất bảo đảm được cài đặt là HTTP. Thông
qua lớp HttpConnection chúng ta có thể liên lạc với web server hoặc một thiết bị có
hỗ trợ HTTP.
HTTP được xem như một giao thức dạng yêu cầu/phản hồi. Máy client sẽ gửi
một yêu cầu đến server (địa chỉ server được định nghĩa theo đặc tả Uniform
Resource Locator (URL)) và một phản hồi sẽ được phát sinh từ phía server gửi trả
cho client. Đây cũng chính là cách thức liên lạc giữa các trình duyệt web và web
server.

7.3.1. Khởi tạo kết nối:


Lớp Connector có 7 phương thức để khởi tạo kết nối với server.
Lớp: javax.microedition.io.Connector
Phương thức Mô tả
static Connection open(String name) Tạo connection dạng READ_WRITE.
static Connection open(String name, Tạo connection với mode được chỉ định rõ
int mode) (được đề cập ở bảng sau).
static Connection open(String name, Tạo connection với mode được chỉ định,
int mode, boolean timeouts) xử lý exception timeouts (được đề cập ở
phần sau)

127
Java Mobile

static InputStream openInputStream Tạo một input stream cho connection


(String name)
static OutputStream Tạo một output stream cho connection
openOutputStream (String name)
static DataInputStream Tạo một data input stream cho connection
openDataInputStream (String name)
static DataOutputStream (String Tạo một data output stream cho connection
name)
Bảng 7.1 Lớp Connector

Có 3 modes được hỗ trợ khi ta tạo mới một connection:


javax.microedition.io.Connector
Mode Ý nghĩa
READ_WRITE Connection hỗ trợ cả đọc lẫn ghi dữ liệu
READ Connection chỉ cho phép đọc dữ liệu xuống
WRITE Connection chỉ hỗ trợ việc ghi dữ liệu.
Bảng 7.2 Mode Kết Nối

Trong 7 phương thức trên có 3 phương thức open() khác nhau: Phương thức đầu
tiên chỉ đòi hỏi địa chỉ của server, phương thức thứ hai cho phép người dùng chọn
kiểu connection có hỗ trợ reading/writing. Phương thức cuối cùng cho phép người
dùng tùy chọn có xử lý timeouts exception hay không. Các phương thức còn lại
dùng để mở các dòng dữ liệu đọc/ghi.

Sau đây là đoạn lệnh dùng để thiết lập một kết nối kiểu ContentConnetion (đây
là interface cài đặt interface Connection và chứa các định nghĩa cho lớp
HttpConnection, xin xem lại lược đồ bên trên):
String url = "http://www.mydomain.com"
ContentConnection connection = (ContentConnection) Connector.open(url);

128
Java Mobile

Chúng ta không thiết lập một đối tượng kiểu Connector mà dùng hàm static
open() để tạo một connection. Kết quả trả về là một đối tượng Connection, ta có thể
“ép kiểu” về dạng Connection chúng ta mong muốn (ở đây là ContentConnection).
Sau đó ta có thể tạo một InputStream từ connection này để phục vụ việc đọc dữ
liệu:

InputStream iStrm = connection.openInputStream();


// ContentConnection hỗ trợ phương thức getLength
int length = (int) connection.getLength();
if (length > 0) {
byte imageData[] = new byte[length];
// Đọc dữ liệu vào mảng
iStrm.read(imageData);
}

Sau khi tạo thành công connection, ta có tạo các dòng dữ liệu đọc/ghi dựa trên
connection này. Interface ContentConnection còn hỗ trợ cả phương thức
getLenght() cho biết chiều dài dữ liệu hiện hành. Cấu trúc và phong cách thiết kế
hướng đối tượng của Java hỗ trợ cho các nhà phát triển ứng dụng rất nhiều.
Thậm chí chúng ta còn có thể lấy ra dòng dữ liệu Input mà không cần tạo đối tượng
connection như sau:

// Tạo một InputStream connection


String url = "http://www.mydomain.com/picture.png"
InputStream iStrm = (InputStream) Connector.openInputStream(url);
try {
byte imageData[] = new byte[2500];
// Đọc dữ liệu vào mảng
int length = iStrm.read(imageData);
}

129
Java Mobile

Tuy nhiên, ở cách tiếp cận vừa nêu chúng ta không tận dụng được phương thức
getLength() của interface ContentConnection. Việc chọn lựa cách tiếp cận nào là
tùy thuộc vào hoàn cảnh và sở thích của người lập trình.

Đến thời điểm này chúng ta chỉ mới khởi tạo kết nối và đọc, ghi dữ liệu mà chưa
tận dụng các tính năng liên quan đến giao thức HTTP. HTTP là một giao thức dạng
yêu cầu / phản hồi: client gửi một yêu cầu (request), server sẽ gửi lại một thông điệp
phản hồi. Tiếp theo chúng ta sẽ nghiên cứu những chức năng hỗ trợ giao thức
HTTP.

7.3.2. Các đặc điểm của kết nối HTTP bằng J2ME:
Các phương thức Yêu Cầu (Request):
Một yêu cầu từ phía client gồm 3 phần: phương thức request, header và phần thân
(body). HttpConnection hỗ trợ ba phương thức request: GET, POST, HEAD.
javax.microediton.io.HttpConnection
Phương thức Mô tả
GET Thông tin yêu cầu được gửi kèm URL
POST Thông tin yêu cầu được gửi theo một stream riêng biệt.
HEAD Gói tin yêu cầu truy vấn thông tin về một tài nguyên.
Bảng 7.3 Các Request Method chính
Cả ba phương thức trên thông báo cho server biết client cần truy vấn một thông
tin. Phương thức GET và POST khác nhau ở cách thông tin truy vấn được gửi lên
server.
Chúng ta có thể chỉ định rõ phương thức sử dụng trong HttpConnection bằng hàm
setRequestMethod():

HttpConnection http = null;


http = (HttpConnection) Connector.open(url);
http.setRequestMethod(HttpConnection.GET);

130
Java Mobile

javax.microediton.io.HttpConnection
Phương thức Mô tả
void setRequestMethod (String method) Đặt phương thức request là Get, Post
hay Head
void setRequestProperty (String key, Đặt một thuộc tính request (thông tin ở
String value) phần header)
String getRequestMethod () Lấy phương thức request đang sử dụng
String getRequestProperty (String key) Lấy giá trị hiện thời của một thuộc tính
request (thuộc phần header)
Bảng 7.4 Các phương thức set/get Request Method

Sử dụng GET, phần thân của yêu cầu được đưa vào chung trong URL. Điều này
được gọi là URL encoding. Ví dụ, chúng ta có một web form gồm 2 trường color và
font. Tên của hai trường này được đặt là userColor và userFont. Khi user chọn giá
trị cho hai trường này, giả sử lần lượt là userColor = blue và userFont = courier và
submit lên trang web http://www.mydomain.com/formscript thì URL thực chất có
dạng như sau:
http://www.mydomain.com/formscript?userColor=blue&userFont=courier
(dấu ? dùng để phân cách vùng địa chỉ trang và phần thông tin yêu cầu gửi lên
server). Sau đó, trang web trên server sẽ dùng các hàm riêng để tách vùng thông tin
yêu cầu và thực hiện xử lý, sau đó sẽ trả kết quả cho client.
Với phương thức POST, thông tin truy vấn không được ghép thêm vào vùng
URL mà được chuyển lên server trong vùng BODY của gói tin HTTP.
Phương thức POST có hai ưu điểm so với phương thức GET:
• Phương thức POST không giới hạn kích thước vùng dữ liệu request gửi lên
server, ngược lại phương thức GET do gửi dữ liệu dạng gắn kèm vào URL
nên không thể gửi kèm dữ liệu quá lớn.
• POST gửi dữ liệu theo một dòng riêng (trong phần BODY) nên không thể
hiện thông tin cho người dùng thấy trong URL.

131
Java Mobile

HEAD là một phương thức gần giống với GET. Client gửi dữ liệu lên server và
đính kèm nó với URL. Tuy nhiên, trong gói tin hồi đáp của server cho gói tin dạng
HEAD này sẽ không có vùng BODY. HEAD được dùng chủ yếu để lấy thông tin về
một tài nguyên nào đó trên server. Ví dụ, chúng ta muốn lấy thông tin về lần cập
nhật mới nhất của một tập tin trên server, do đó, trong gói tin trả lời chúng ta thực
chất không cần nội dung của file trên (gói tin không có vùng BODY).

Ghi chú: Luận văn không có mục tiêu trình bày về giao thức HTTP mà chỉ giới thiệu HTTP như
một phương thức kết nối được J2ME hỗ trợ, do đó phần lý thuyết giới thiệu về HTTP sẽ rất hạn
chế. Nếu người đọc muốn tìm hiểu hơn về HTTP có thể tìm đọc RFC 2616 về HTTP 1.1

Thông tin Header:


Phần thứ hai của một gói tin yêu cầu từ client là phần header. Giao thức HTTP định
nghĩa hơn 40 trường header. Một số trường thông dụng như Accept, Cache-Control,
Content-Type, Expires, If-Modified-Since và User-Agent Header được đặt giá trị
bằng hàm setRequestProperty() đã được đề cập bên trên.
HttpConnection http = null;
http = (HttpConnection) Connector.open(url);
http.setRequestMethod(HttpConnection.GET);
http.setRequestProperty("If-Modified-Since",
"Mon, 16 Jul 2001 22:54:26 GMT");

Phần thân (Body):


Dữ liệu được chuyển từ client lên server thông qua phần body của gói tin
request. Như đã đề cập, GET gộp phần body vào URL còn POST gửi phần body
trong một stream riêng biệt.

Gói tin trả lời của Server:

132
Java Mobile

Khi client đã đóng gói một gói tin gồm phương thức yêu cầu, phần header, phần
body và gửi đến server, server có trách nhiệm phân tích gói tin, xử lý và hồi đáp
client. Phần hồi đáp của server cũng gồm 3 phần: status line, header và phần body.
Status Line:
Phần status line cho biết kết quả của gói tin yêu cầu từ phía client. Trong
HttpConnection, chúng ta có hơn 35 mã status hồi đáp. HTTP chia các mã hồi đáp
này thành 5 mục lớn:
1xx – Thông tin
2xx – Mã báo thành công
3xx – Chuyển hướng (redirection)
4xx – Lỗi từ phía client
5xx – Lỗi tại server
Ví dụ, HTTP_OK (mã 200) thông báo yêu cầu từ phía client đã được xử lý thành
công. Khi gửi gói tin hồi đáp (response), server thường gửi cả version của giao thức
kèm theo status line.
Đây là một số ví dụ về status line:
HTTP/1.1 200 OK
HTTP/1.1 400 Bad Request
HTTP/1.1 500 Internal Server Error

Khi đọc mã status, ta có hai lựa chọn: lấy về mã hay câu thông báo:
http.getResponseCode( );
http.getResponseMessage( );

Header:
Cũng tương tự như client, gói tin trả về của server cũng bao gồm phần header. Phần
header bao gồm nhiều cặp Key – Giá trị có thể được truy xuất thông qua nhiều
cách:

133
Java Mobile

javax.microedition.io.HttpConnection
Phương thức Mô tả
String getHeaderField(int n) Lấy giá trị 1 trường header theo index
String getHeaderField(String name) Lấy giá trị 1 trường header theo tên
long getHeaderFieldDate(String Lấy trường có tên “name”, trả về giá trị
name,long def) kiểu long
int getHeaderFieldInt (String name, int Lấy trường có thên “name”, trả về giá trị
def) kiểu int
String getHeaderFieldKey (int n) Lấy tên trường dựa theo chỉ số của
trường
long getDate( ) Lấy trường date
long getExpiration( ) Lấy trường expires
long getLastModified( ) Lấy trường last-modifed
Bảng 7.5 Các phương thức truy vấn HTTP Header
Xét một ví dụ, giả sử trong vùng header ta có một cặp khóa/giá trị như sau:
content-type=text/plain (“content-type” là một trường được HTTP định nghĩa,
“text-plain” để chỉ giá trị trả về có dạng text đơn thuần). Chúng ta giả sử thêm
trường content-type này là trường đầu tiên (index=0) trong vùng header. Để lấy giá
trị của trường này ta có những cách sau:

http.getHeaderField(0); // "text-plain"
http.getHeaderField("content-type"); // "text-plain"
http.getHeaderFieldKey(0); // "content-type"

Phần thân (Body):


Phần thân là dữ liệu gửi từ server trả về cho client. Chúng ta không có một
phương thức đặc biệt nào để đọc phần body mà cách thông dụng nhất là đọc phần
body này thông qua một stream. Chúng ta xét một ví dụ download một file text từ
server:

134
Java Mobile

Trong ví dụ này, chúng ta sẽ tạo một MIDlet yêu cầu nội dung một file từ phía
server. URL cùa file trên có dạng:
url= “http://localhost/getHeaderInfo.txt”;
Đầu tiên chúng ta cũng sẽ khởi tạo kết nối:
HttpConnection http = null;
…………………………….
//Tạo kết nối
http= (HttpConnection) Connector.open(url);
Ứng dụng Client sẽ trải qua một số bước:
//Gửi yêu cầu lên server:
//1) Xác định phương thức yêu cầu là GET
http.setRequestMethod(HttpConnection.GET);
//2) Gửi các thông tin header (không bắt buộc phải có)
http.setRequestProperty(“User-Agent”, “Profile/MIDP-1.0 Configuration/CLDC-
1.0");
//3) Gửi dữ liệu, vì dùng Get nên không có phần body – data

Sau đó chúng ta phải xử lý phần thông tin trả về của server để lấy ra nội dung file
//Thông tin trả về của server
//1) Lấy status line:
System.out.println("Msg: " + http.getResponseMessage());
System.out.println("Code: " + http.getResponseCode());
// 2) Lấy thông tin header:
if (http.getResponseCode() == HttpConnection.HTTP_OK) {
System.out.println("field 0: " + http.getHeaderField(0));
...
System.out.println("key 0: " + http.getHeaderFieldKey(0));
...
System.out.println("content: " + http.getHeaderField("content-type"));
...
}

135
Java Mobile

// 3) Lấy dữ liệu (nội dung file)


String str;
iStrm = http.openInputStream();
int length = (int) http.getLength();
if (length != -1) {
// Đọc dữ liệu vào mảng nếu có giá trị length
byte serverData[] = new byte[length];
iStrm.read(serverData);
str = new String(serverData);
}
// Nếu không có length, đọc từng byte
else {
ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
// Mỗi lần đọc chỉ đọc một ký tự
int ch;
while ((ch = iStrm.read()) != -1)
bStrm.write(ch);
str = new String(bStrm.toByteArray());
bStrm.close();
}
System.out.println("File Contents: " + str);

Sau khi đọc được nội dung file ta xuất ra màn hình console, nếu là ví dụ trên điện
thoại thật ta có thể dùng các thành phần đồ họa cấp cao để xuất nội dung.

136
Java Mobile

Ghi chú: Ở đây có một vấn đề có thể gây khó hiểu cho người đọc, xin hãy theo dõi đoạn code sau:
http= (HttpConnection) Connector.open(url);
http.setRequestMethod(HttpConnection.GET);
http.setRequestProperty(“User-Agent”, “Profile/MIDP-1.0 Configuration/CLDC-1.0");
System.out.println("Msg: " + http.getResponseMessage());
System.out.println("Code: " + http.getResponseCode());
Ban đầu chúng ta dùng hàm Connector.open(url) để tạo ra một đối tượng kiểu HttpConnection vì
không có phương thức khởi tạo trực tiếp đối tượng HttpConnection. Theo như ý nghĩa của hàm
open(url) thì lúc này một kết nối lên server đã được khởi tạo, nhưng sau đó ta mới đặt các thông số
về phương thức yêu cầu (ở đây là GET) và đặt các giá trị headers. Như vậy điều này có hợp lý hay
không vì kết nối đã được khởi tạo rồi, đúng ra các thông số này phải được đặt trước khi tạo kết nối!
Thật ra với interface HttpConnection, khi ta gọi hàm Connector.open(url) thì kết nối chưa được xác
lập, chỉ khi nào các hàm như getResponseCode( ) hay getResponseMessage( ) được gọi thì kết nối
mới thật sự được thiết lập, do đó ta đặt các thông số sau khi gọi hàm open( ) vẫn hợp lý.

7.3.3. Thông số kết nối:


Khi một kết nối đã được thiết lập, chúng ta được hỗ trợ một số hàm để lấy các thông
tin về kết nối.
javax.microedition.io.HttpConnection
Phương thức Mô tả
String getFile( ) Lấy tên file từ URL
String getHost( ) Lấy host từ URL
int getPort( ) Lấy port từ URL
String getProtocol( ) Lấy giao thức (protocol) từ URL
String getQuery( ) Lấy về chuỗi truy vấn (QueryString), chỉ hỗ trợ trong
phương thức GET.
String getRef( ) Lấy thành phần tham chiếu (reference portion) từ URL
(RFC 2396)
String getURL( ) Lấy về toàn bộ địa chỉ URL
Bảng 7.6 Lấy thông số kết nối

137
Java Mobile

7.4. Kết nối socket Datagram (UDP)

Hình 7.2 Kết nối UDP

Để tạo lập kết nối Datagram ta sử dụng hai lớp chính là DatagramConnection
(Tạo kết nối) và Datagram (Chứa dữ liệu).
Chuỗi kết nối:
{protocol}://[{host}]:[{port}]

Ví dụ:
//tạo một socket UDP server lắng nghe trên port 1234:
String connectionString=”datagram://:1234”;
DatagramConnection= (DatagramConnection) Connector.open(connectionString);

//tạo một socket UDP client kết nối đến socket server vừa tạo:
String connectionString=”datagram://123.456.789.12:1234”;
DatagramConnection= (DatagramConnection) Connector.open(connectionString);

138
Java Mobile

Lớp DatagramConnection: javax.microedition.lcdui.DatagramConnection


Phương thức: Mô tả:
int getMaximumLength() Lấy về kích thước tối đa của một Datagram
int getNominalLength() Lấy về kích thước tối thiểu của một
Datagram
Datagram newDatagram(
Tạo mới 1 datagram
byte[] buf, int size)
Datagram newDatagram (
Tạo mới 1 datagram
byte[] buf, int size, String addr)
Datagram newDatagram ( int size) Tạo mới 1 datagram
Datagram newDatagram ( int size,
Tạo mới 1 datagram
String addr)
void receive (Datagram dgram) Nhận datagram
void send (Datagram dgram) Gửi datagram
Bảng 7.7 Lớp DatagramConnection

Lớp Datagram:
Một datagram tượng trưng cho một UDP packet trong quá trình gửi/nhận
thông qua UDP sockets.
Lớp datagram implements hai interfaces là DataInput và DataOutput nên ta
có thể sử dụng các phương thức đọc/ghi thông thường trên lớp này.
Lớp Datagram: javax.microedition.lcdui.Datagram
Phương thức: Mô tả:
String getAddress() Lấy về địa chỉ IP của gói tin.
byte[] getData() Lấy về nội dung gói tin.
int getLength() Lấy về kích thước gói tin.
int getOffset() Lấy về Offset của buffer của gói tin (internal
buffer).

139
Java Mobile

void reset() Đặt con trỏ đọc/ghi về đầu buffer của gói tin.
void setAddress (Datagram ref) Đặt địa chỉ IP của gói tin theo 1 gói tin khác.
void setAddress (String addr) Đặt trực tiếp địa chỉ IP của gói tin.
void setData (byte[] buffer,
Đưa nội dung vào gói tin.
int offset, int len)
void setLength (int len) Đặt kích thước gói tin.
Bảng 7.8 Lớp Datagram

140
Java Mobile

7.5. Kết nối TCP socket

Hình 7.3 Kết Nối TCP


Để tạo lập kết nối TCP ta phải sử dụng 2 interfaces
StreamConnectionNotifier và StreamConnection.

Tạo lập socket server: sử dụng lớp StreamConnectionNotifier.

String connectionString="socket://:98765";
StreamConnectionNotifier wellKnown = Connector.open(connectionString);
Hoặc
String connectionString="serversocket://:98765";
StreamConnectionNotifier wellKnown = Connector.open(connectionString);

Sau khi đã khởi tạo socket server ta có thể sử dụng hàm StreamConnection
acceptAndOpen() (tương tự như hàm accept() trong lập trình WinSock) để tạo một
socket giao tiếp với client kết nối tới.

141
Java Mobile

Tạo lập socket Client:


String connectionString="socket://server.foo.com:98765";
StreamConnection conn=Connector.open(connectionString);

Interface StreamConnection implements hai interface InputConnection và


Interface OutputConnection do đó ta có thể sử dụng các hàm
openDataInputStream() và openDataOutputStream() để đọc và ghi dữ liệu một các
dễ dàng.
J2ME còn cung cấp lớp SocketConnection kế thừa từ lớp StreamConnection
để phục vụ thêm cho kết nối TCP.

Lớp SocketConnection:
Lớp SocketConnection: javax.microedition.lcdui.SocketConnection
Mode: Mô tả:
static byte DELAY Thời gian delay trước khi gửi gói tin.
static byte KEEPALIVE Thời gian cách nhau của các gói tin KeepAlive
static byte LINGER Thời gian timeout để gửi các gói tin còn đọng lại
khi đã gọi hàm close()
static byte RCVBUF Kích thước Receive Buffer.
static byte SNDBUF Kích thước Send Buffer.
Bảng 7.9 Thuộc tính của SocketConnection

Lớp SocketConnection: javax.microedition.lcdui.SocketConnection


Phương thức: Mô tả:
String getAddress() Lấy địa chỉ IP của máy đang kết nối đến.
String getLocalAddress() Lấy địa chỉ IP máy nội bộ.
int getLocalPort() Lấy port của máy nội bộ.

142
Java Mobile

int getPort() Lấy port của máy đang kết nối đến.
int getSocketOption(byte option) Lấy các tùy chọn của socket.
void setSocketOption(byte option,
Đặt các tùy chọn cho socket.
int value)
Bảng 7.10 Lớp SocketConnection

143
Java Mobile

7.6. Gửi và nhận SMS


Để gửi và nhận tin nhắn SMS trong J2ME ta sử dụng bộ thư viện Wireless
Messaging API - ký mã hiệu JSR 205 (xêm thêm về JSR trong phần phụ lục). SMS
(Short Message Service) là một dịch vụ vô cùng quan trọng trong hệ thống thông tin
di động. Ở Châu Âu, ước tính 40% cước phí dịch vụ di động do SMS mang lại.
Tính năng SMS không được hỗ trợ trong các thư viện gốc của J2ME mà thông
qua Wireless Messaging API (WMA), một đặc điểm rất tiện lợi của WMA là nó cho
phép biến thiết bị di động thành một SMS server: chúng ta có thể viết chương trình
nhận và tự động xử lý tin nhắn (tự động reply hoặc chuyển tiếp đến một máy khác).
Chúng ta có thể khai thác thư viện WMA qua ba interfaces chính được định
nghĩa sẵn:
Interface Mô tả
Message Interface này tượng trưng cho một tin nhắn, hai lớp kế thừa từ
interface này là TextMessage và BinaryMessage.
MessageConnection Interface này tượng trưng cho một kết nối để gửi/nhận
message. Interface này định nghĩa sẵn các hàm rất hữu ích
như newMessage() để tạo một tin nhắn mới sẵn sàng được
gửi đi, receive() để nhận tin nhắn gửi đến.
MessageListener Có chức năng tương tự như CommandListener, MIDlet sẽ
implements interface này để được thông báo khi nào có tin
nhắn gửi đến. Việc thông báo sẽ được thực hiện thông qua
hàm notifyIncomingMessage().
Bảng 7.11 Các interfaces chính của WMA

144
Java Mobile

Hình 7.4 Lược đồ lớp thư viện WMA


Khởi tạo kết nối SMS:
Để khởi tạo kết nối SMS ta cũng sử dụng phương thức Connector.Open(String
URL).
• Nếu URL có dạng sms://+18005555555, lời gọi hàm sẽ tạo một kết nối SMS
gửi tin nhắn đến máy 1-800-555-5555.
• Nếu URL có dạng sms://+18005555555:1234, lời gọi hàm sẽ tạo một kết nối
SMS gửi tin nhắn đến số máy 1-800-555-5555 tại port 1234.
• Nếu URL có dạng sms://:1234, lời gọi hàm sẽ tạo một kết nối SMS server để
lắng nghe các tin nhắn gửi đến tại port 1234. Chúng ta hoàn toàn có thể dùng
một kết nối SMS server để gửi tin nhắn.
Ghi chú: Ở đây chúng ta gặp một khái niêm tương đối lạ lẫm là SMS port. Trong
thư viện WMA, chúng ta có thể thiết lập port cho mỗi tin nhắn chúng ta gửi đi. Nếu

145
Java Mobile

một tin nhắn SMS gửi đến một máy khác mà trên máy này không có port tương ứng
thì tin nhắn sẽ được xem như một "inbox message" và sẽ do chương trình xử lý tin
nhắn mặc định trên thiết bị tiếp nhận. Không có một SMS server nào tạo bởi thư
viện WMA tiếp nhận các tin nhắn loại này, các tin nhắn xử lý bởi WMA thường là
các tin nhắn gửi vào các port được qui định trước.
Gửi tin nhắn:
Để gửi tin nhắn chúng ta sử dụng kết nối MessageConnection:
String addr = "sms://+123456789";
//Hoặcr: String addr = "sms://+123456789:1234";
MessageConnection conn = (MessageConnection) Connector.open(addr);
TextMessage msg = (TextMessage) conn.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setPayloadText( "Hello World" );
conn.send(msg);
Chúng ta cũng có thể gửi tin nhắn từ kết nối SMS server như sau:
MessageConnection sconn =
(MessageConnection) Connector.open("sms://:3333");
TextMessage msg = (TextMessage) sconn.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setAddress("sms://+123456789:1234");
msg.setPayloadText( "Hello World" );
sconn.send(msg);
Việc sử dụng SMS server để gửi tin nhắn có một số lợi điểm sau:
• Chúng ta có thể sử dụng lại kết nối này nhiều lần.
• Tin nhắn gửi đi sẽ có kèm số điện thoại và port của người gửi

Nhận tin nhắn:


Chúng ta có thể nhận tin nhắn theo hai mô hình: blocking (phải tạo thread) và
mô hình non-blocking (mô hình bất đồng bộ).

146
Java Mobile

Với mô hình một chúng ta sẽ phải tạo một thread dành riêng cho SMS server, ví
dụ như sau:
MessageConnection sconn =
(MessageConnection) Connector.open("sms://:3333");
while (true) {
Message msg = sconn.receive();
if (msg instanceof TextMessage) {
TextMessage tmsg = (TextMessage) msg;
String msgText = tmsg.getPayloadText();

// Construct the return message


TextMessage rmsg = (TextMessage) sconn.newMessage(
MessageConnection.TEXT_MESSAGE);
rmsg.setAddress ( tmsg.getAddress() );
rmsg.setPayloadText( "Thanks!" );
sconn.send(rmsg);
} else {
// process the non-text message
// maybe a BinaryMessage?
}
}
Với mô hình bất đồng bộ chúng ta phải implements MessageListener và sử dụng
hàm notifyIncomingMessage() như sau:
// Implements the MessageListener IF
public class WMAasync extends MIDlet
implements CommandListener, MessageListener {

// Init a server connection and assign


// a listener for it.
public void startApp() {
try {
displayBlankForm ();
sconn = (MessageConnection) Connector.open("sms://:"+serverPort);
sconn.setMessageListener(this);
} catch (Exception e) {/* process error*/}
}

// ... ...

// Implement the message handler


// method required in the MessageListener

147
Java Mobile

// interface.
public void notifyIncomingMessage(
MessageConnection c) {
new Thread(new SMSHandler()).start();
return;
}

class SMSHandler implements Runnable {


public void run () {
try {
Message msg = sconn.receive();
if (msg instanceof TextMessage) {
TextMessage tmsg = (TextMessage) msg;
String msgText = tmsg.getPayloadText();

// Construct the return message


TextMessage rmsg = (TextMessage) sconn.newMessage(
MessageConnection.TEXT_MESSAGE);
rmsg.setAddress ( tmsg.getAddress() );
rmsg.setPayloadText( "Message " +
msgText + " is received" );
sconn.send(rmsg);

// Display mesgText

} else {/* not a text mesg */}


} catch (Exception e) {/* handle error */}
}
}
}

148
Java Mobile

Phần 2 : Web Service và Ứng dụng "Đăng Ký Học


Phần"

Chương 8: Giới thiệu Web Service

8.1. Ứng dụng phân tán (Distributed Application)

8.1.1. Giới thiệu


Ứng dụng phân tán (Distributed Application) là một hướng nghiên cứu đang
được chú trọng trong nghành công nghiệp phần mềm. Nhu cầu cần hình thành nên
những hệ thống phân tán xuất phát từ một số lý do:
• Chi phí: Việc đầu tư cho những hệ thống xử lý lớn rất tốn kém và vượt quá khả
năng của nhiều tổ chức; ngoài ra việc tập trung tất cả thông tin tại một nơi là một
nguy cơ tiểm tàng về việc mất dữ liệu nếu xảy ra sự cố. Từ hai yếu tố trên đã
hình thành nhu cầu phân tán dữ liệu để giảm rủi ro và tiết kiệm chi phí.
• Sở hữu thông tin: Thông tin có thể ở nhiều dạng, nhiều nguồn và thuộc sở hữu
của nhiểu tổ chức khác nhau. Việc gom hết tất cả các thông tin quy về một nơi là
bất khả thi, do đó việc phân tán thông tin là nhu cầu nhưng đôi khi cũng là bắt
buộc.
• Độ an toàn: Đối với hầu hết thông tin, yêu cầu đầu tiên là phải truy xuất được dễ
dàng. Tuy nhiên, đối với những dữ liệu quan trọng và nhạy cảm, nhu cầu bảo mật
thông tin lại được đưa lên hàng đầu. Ngày nay, để đáp ứng đồng thời hai nhu cầu
trên, dữ liệu chủ yêu được chia nhỏ thành nhiều phần chứ không được lưu trữ tập
trung tại một nơi.

149
Java Mobile

Từ những nhu cầu trên đã làm xuất hiện một quan niệm thiết kế phần mềm mới và
hình thành nên những hệ thống phần mềm phân tán. Các hệ thống phần mềm phân
tán ra đời đã mang lại nhiều lợi ích:
• Tăng khả năng linh hoạt của chương trình, cho phép chương trình giao tiếp với
nhiều nguồn DL khác nhau
• Tận dụng khả năng tính toán của những hệ thống lớn (Grid computing)
• Tăng khả năng liên kết giữa các hệ thống phần mềm để hình thành những ứng
dụng lớn.

8.1.2. Các vấn đề nảy sinh trong hệ thống ứng dụng phân tán

• Các HĐH khác nhau sẽ hỗ trợ những kiểu dữ liệu khác nhau. Đôi khi, các
kiểu dữ liệu không tương thích 100% với nhau trên các nền tảng HĐH khác
nhau. Khi phát triển các ứng dụng phân tán, chúng ta cần chú ý đến việc hòa
hợp dữ liệu trên các môi trường.
• Các thành phần của một ứng dụng phân tán thường ở nhiều nơi khác nhau
trên mạng do đó khả năng phát sinh lỗi thường cao hơn bình thường. Khi phát
sinh lỗi có thể làm toàn bộ ứng dụng ngưng hoạt động, do đó chúng ta cần
phải chú ý đến việc phát sinh lỗi và mất gói tin trong quá trình hoạt động.
• Nếu server của chúng ta lưu trạng thái của client, khi client bị ngừng đột ngột
chúng ta phải có biện pháp thông báo cho server và thu hồi những tài nguyên
bị chiếm giữ.
• Khi một hàm được gọi từ xa, hàm đã được xử lý nhưng gói tin phản hồi bị
mất trong một số trường hợp chúng ta không thể gửi lại lời gọi hàm một lần
nữa: ví dụ khi ta đặt mua một đơn đặt hàng, đơn đặt hàng đã được ghi nhận
nhưng gói tin phản hồi bị mất, ta không thể đơn thuần gửi lại một đơn đặt
hàng khác.
• Dữ liệu của ứng dụng phân tán thường được gửi qua lại nhiều node trên mạng
do đó bảo mật là một trong những vấn đề hàng đầu cần giải quyết. Chúng ta

150
Java Mobile

phải xem xét những vấn đề về authentication, authorization, Denial of service,


replay attacks…
• Rất nhiều ứng dụng phụ thuộc vào sự đồng bộ thời gian của client và server.
Ví dụ như một thông báo đã đặt hàng thành công không thể phát sinh trước
khi đơn đặt hàng được phát sinh. Do đó, vấn đề về đồng bộ thời gian trên
clients và server cũng phải được quan tâm.

8.1.3. Hạn chế của những mô hình ứng dụng phân tán trước đây
Trước đây đã có nhiều hình thức ứng dụng phân tán được đề ra như: Distributed
Component Object Model (DCOM), Java Remote Method Invocation (RMI),
Common Object Request Broker Architecture (CORBA), tuy nhiên hầu hết các hình
thức này đều tồn tại một số nhược điểm:
Firewalls:
Các ứng dụng này khi hoạt động ở những hệ thống mạng được che chắn bởi
firewall đều phải được sự cho phép của những người quản trị firewall để được ra
ngoài. Đây là một trong những lỗ hổng bảo mật tiềm tàng và khó được chấp nhận
bởi nhiều tổ chức.
Sự phối hợp của các giao thức:
Các mô hình này đều có những đặc điểm và dựa trên những giao thức tầng dưới
khác nhau. Chúng ta có thể xây dựng các chương trình chuyển đổi qua lại giữa các
mô hình này nhưng chắc chắn sẽ dẫn đến việc thất thoát thông tin trong quá trình
chuyển đổi. Các hệ thống ứng dụng phân tán có thể đi theo các “trường phái” khác
nhau dẫn đến việc không thể làm việc chung.

Với những lý do trên, nhu cầu hình thành một chuẩn chung cho các hệ thống
ứng dụng phân tán trở nên một nhu cầu thiết yếu.
Sự ra đời của Web Service, một đặc tả sử dụng hệ thống HTTP đã được chuẩn
hóa làm nền tảng, đã phần nào giải quyết được nhu cầu nói trên.

151
Java Mobile

8.2. Web Service

8.2.1. Định nghĩa


Một Web service được định nghĩa là một tập các phương thức có thể được định
vị thông qua địa chỉ URL, các phương thức này được công bố trên hệ thống mạng
và được dùng như những khối cơ bản để xây dựng một ứng dụng phân tán (Trích
sách: Developing XML Web service using Microsoft Visual Studio .NET). Nói một
cách đơn giản hơn, web service là tập hợp các phương thức có thể được các ứng
dụng khác triệu gọi từ xa (RPC- Remote Procedure Call) để hình thành nên một hệ
ứng dụng phân tán.

8.2.2. Thành phần cơ bản của Web service:


Các thành phần cơ bản nhất của web service bao gồm HTTP, XML và SOAP
(Simple Object Access Protocol). Việc phát triển những kỹ thuật này được điều
hành bởi tổ chức W3C (World Wide Web Consortium). Chúng ta sẽ đề cập đến
những kỹ thuật này ở những phần sau.

8.2.3. Hoạt động của Web service

Hình 8.1 Hoạt động của Web Service

152
Java Mobile

Một ứng dụng web service thường gồm 2 phần: client và server.
Client và server sẽ giao tiếp với nhau theo giao thức HTTP: Ứng dụng client sẽ
gửi những lời gọi hàm đến server thông qua các gói tin HTTP request và kết quả
thực thi hàm sẽ được server hồi đáp thông qua các gói tin HTTP response.
SOAP:
Các thông điệp sẽ được định dạng theo chuẩn giao thức SOAP (Simple Object
Access Protocol). Đây thực chất cũng chỉ là một ngôn ngữ được định nghĩa bên trên
ngôn ngữ XML có sẵn.
WSDL (Web Service Definition Language):
Đây là file XML chứa các định nghĩa về các hàm trong Web service tương ứng.
Các nhà phát triển ứng dụng sẽ phải dựa vào nội dung file này để biết Web service
hỗ trợ những hàm này và nhận những tham số tương ứng, kết quả trả về như thế
nào.
Nếu chúng ta phát triển Web service trong môi trường J2ME thì không nhất thiết
phải hiểu rõ cấu trúc về file WSDL, vì trong bộ công cụ Wireless Toolkit của Sun
đã cung cấp sẵn công cụ Stub Generator. Chức năng của bộ công cụ này là đọc file
WSDL và phát sinh thành những lớp java tương ứng cho nhà phát triển ứng dụng.
UDDI(Universal Description, Discovery, and Integration):
Đây là công cụ giúp cho những nhà phát triển Web Service công bố những
thông tin về web service của mình cho cộng đồng các nhà phát triển ứng dụng.
Người dùng sẽ dựa vào những thông tin này để sử dụng web service trong ứng dụng
riêng của mình tạo thành một hệ ứng dụng phân tán.
Mối quan hệ giữa các thành phần SOAP,WSDL,UDDI có thể được mô tả như sau:
Một ứng dụng web service client cần sử dụng một web service được đặt tại một
nơi nào đó trên hệ thống mạng. Trước tiên, client sẽ truy vấn đến các mẫu tin
UDDI, có thể theo tên, loại hay một thông tin riêng biệt nào đó. Khi đã xác định
được web service cần tìm, client có thể lấy thông tin về địa chỉ của tài liệu WSDL
của web service này dựa trên mẫu tin UDDI. Tài liệu WSDL sẽ mô tả cách thức
liên lạc với web service, định dạng của gói tin truy vấn và phản hồi theo cũng được

153
Java Mobile

mô tả bằng XML schema. Dựa vào những thông tin này client có thể tạo những gói
tin SOAP tương ứng để liên lạc với server.
Ứng dụng web service có thể được cài đặt ở những mức độ cao hơn như những mô
hình sau:

Hình 8.2 Một client truy xuất đến nhiều web services cùng lúc

154
Java Mobile

Hình 8.3 Một web service có thể triệu tập đến các web services khác

8.2.4. Ưu điểm của web service


Web service có nhiều ưu điểm hơn so với những mô hình ứng dụng phân tán ra đời
trước nó. Ưu điểm này được cấu thành bởi chính những thành phần tạo nên web
service.
• Khả năng vượt firewall: Web Service hoạt động trên nền giao thức HTTP nên
cũng sử dụng luôn port 80 dành cho web. Đây là một ưu thế rất lớn của web
service đối với các phương thức gọi hàm từ xa (RPC) khác; với các hình thức cũ
hơn chúng ta thường phải dùng các port tự qui định (lớn hơn 1024) dẫn đến
không thể hoạt động ở một số tổ chức vì quản trị mạng không cho phép vượt qua
firewall. Web service sử dụng port "well-known" 80, đây là port hầu như tất cả
các firewall đều cho phép đi qua nên web service có thể hoạt động ở mọi nơi.
• Hoạt động trên đa môi trường: Web service dựa trên nền công nghệ XML, tài
liệu XML hiện nay được hỗ trợ bởi tất cả các Hệ Điều Hành, kể cả trên môi
trường di động (vì chỉ là những file text đơn thuần). Do đó web service có thể
hoạt động trên mọi môi trường, được hỗ trợ bởi hầu như mọi ngôn ngữ lập trình.
Tuy nhiên chúng ta cũng phải trả giá cho điều này: do truyền dữ liệu dưới dạng

155
Java Mobile

text nên độ trễ của web service sẽ cao và chiếm dụng băng thông cũng nhiều hơn
so với các hình thức chuyển dữ liệu nhị phân.
• Tính linh hoạt, dễ chuyển đổi: Web service chỉ đơn thuần chuyển dữ liệu mà
không kèm những tag định dạng như ngôn ngữ HTML. Đây là ưu điểm của web
service so với các trang web thông thường. Khi cần thêm hay bớt một chức năng
của web service đó đơn thuần là thêm hay bớt một hàm, chúng ta không phải xây
dựng lại giao diện như với trang web. Các client khi nhận được tín hiệu sẽ tùy
vào năng lực của mình mà thể hiện thông tin hợp lý, điều này làm web service
thực sự linh hoạt hơn trang web. Ngoài ra việc không truyền đi các dữ liệu định
dạng làm giảm đi chi phí đáng kể trên đường truyền so với trang web.

156
Java Mobile

8.3. Các thành phần chính của Web Service


Web service dựa vào khá nhiều công nghệ bên dưới như HTTP, XML, SOAP,
… Mỗi công nghệ nêu trên đều có phạm vi ứng dụng khá sâu rộng và đòi hỏi nhiều
thời gian tìm hiểu cũng như trình bày. Luận văn không có tham vọng trình bày cặn
kẽ về tất cả các công nghệ trên mà chỉ xin giới thiệu những nét cơ bản và sơ lược về
các công nghệ chính. Việc trình bày này chỉ nhằm mục đích cung cấp cho người
đọc cái nhìn khái quát hơn về web service, tuy nhiên quá trình phát triển ứng dụng
web service thông thường không đòi hỏi kiến thức sâu về lãnh vực này vì đã có rất
nhiều công cụ hỗ trợ và lập trình viên đã được “che” đi những công việc phức tạp
bên dưới.

8.3.1. SOAP (Simple Object Access Protocol)


SOAP là một giao thức đơn giản nhằm mục đích trao đổi thông tin trong môi
trường ứng dụng phân tán. SOAP dựa trên nền công nghệ XML và bao gồm 2 thành
phần:
• Một “bì thư” (envelope) để quản lý các thông tin mở rộng và mang tính
điều khiển.
• Một chuẩn mã hóa quy định cách thể hiện thông tin trong envelope.
SOAP có thể được sử dụng kết hợp với các giao thức chuẩn khác như
SMTP,HTTP/HTTPS,FTP… Tuy nhiên hiện nay chỉ mới có HTTP/HTTPS được
xem như giao thức chuẩn để trao đổi gói tin SOAP. Việc sử dụng SOAP như một
giao thức trao đổi dữ liệu chuẩn khiến web service có khả năng hoạt động trên nhiều
môi trường lập trình khác nhau như Java, .NET,…
Gói tin SOAP:
Gói tin SOAP là một phương tiện giao tiếp một chiều từ nơi gửi đến nơi nhận.
Gói tin SOAP được gửi bên trong một gói tin HTTP request hoặc gói tin HTTP
response.
Gói tin SOAP gồm 4 phần chính:

157
Java Mobile

• Phần bì thư SOAP envelope: định nghĩa thông điệp chứa những gì, ai nên xử
lý thông điệp, thông điệp này bắt buộc phải xử lý (mandatory) hay mang tính
tùy chọn (optional).
• Luật mã hóa: Quy định cách thức chuyển đổi thông tin, các kiểu dữ liệu trong
ứng dụng.
• Phần SOAP RPC: mô tả những qui luật về cách thức gọi hàm từ xa cũng như
cách thức phản hồi.
• Qui luật mô tả cách thức sử dụng gói tin SOAP với các protocol tầng dưới
(hiện nay là HTTP).
Cấu trúc gói tin SOAP: một gói tin SOAP gồm một Envelope như một node gốc
trong văn bản XML, nút gốc này sẽ chứa node con Body và có thể có hoặc không
chứa node con Header.
SOAP Envelope:
Phần Envelope là node gốc của gói tin SOAP dưới dạng tài liệu XML. Phần
Envelope có thể có hoặc không có phần Header nhưng chắc chắn phải chứa phần
Body.
Đây là một ví dụ về Envelope:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
...
</SOAP-ENV:Envelope>

Trong các gói tin SOAP thông thường, phần Envelope không mang nhiều ý nghĩa.
Nó chỉ đơn thuần báo hiệu sự bắt đầu của một gói tin và định nghĩa các NameSpace
cần thiết sẽ được sử dụng ở các phần sau.
SOAP Header:

158
Java Mobile

Phần SOAP Header sẽ là node con đầu tiên của SOAP Envelope. Phần Header
thường là nơi được dùng để thêm các thông tin bổ sung phục vụ cho mục đích riêng
của chương trình. Các thông tin thường được thêm vào phần Header là
authentication, authorization, quản lý transaction… Phần Header không bắt buộc
phải có trong mọi gói tin SOAP.
SOAP Body:
Nếu trong gói tin SOAP không có node Header thì node Body phải là node con
đầu tiên của SOAP Envelope.
Trong mục Body có thể có nhiều node con, được gọi chung là mẫu tin Body.
Phần Body chứa các thông tin về lời gọi hàm, ví dụ như tên hàm cần gọi, các tham
số đầu vào, giá trị trả về … để phục vụ cho việc gọi hàm từ xa.
Đây là một ví dụ hoàn chỉnh và đơn giản về việc sử dụng SOAP để gọi hàm
GetAccount(int accNumber) với tham số truyền vào accNumber=1234. Gói tin
SOAP được đặt trong gói tin HTTP Request có dạng như sau:

POST /dummy/service1.asmx HTTP/1.1


Host: 192.168.0.80
Content-Type: text/xml; charset=utf-8
Content-Length: 215
SOAPAction: "http://woodgrovebank.com/GetAccount"

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


<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAccount xmlns="http://woodgrovebank.com">
<acctNumber>1234</acctNumber>
</GetAccount>

159
Java Mobile

</soap:Body>
</soap:Envelope>

Phần trên là nội dung gói tin HTTP Request dạng POST, trong gói tin này chứa
lời gọi đến hàm GetAccount(int accNumber) dưới dạng một gói tin SOAP.
Việc hiểu cấu trúc SOAP chủ yếu phục vụ cho việc debug ứng dụng hoặc xây
dựng các ứng dụng cần sự can thiệp ở mức sâu đến các protocol bên dưới. Đối với
các chương trình thông thường hiếm khi chúng ta phải thao tác với gói tin SOAP.
Đây là nội dung gói tin SOAP phản hồi cho lời gọi hàm trên, chỉ ra kết quả lời
gọi hàm là 5250.00

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 247

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


<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAccountResponse xmlns="http://woodgrovebank.com">
<savingsAcct>
<balance>5250.00</balance>
</savingsAcct>
</GetAccountResponse>
</soap:Body>
</soap:Envelope>

SOAP Fault:

160
Java Mobile

Như đã đề cập, một trong những vấn đề đặt ra trong môi trường ứng dụng phân tán
là khả năng xảy ra lỗi cao; do đó khái niệm SOAP Fault được đề ra để vận chuyển
các thông báo lỗi trong quá trình hoạt động.

HTTP/1.0 500 Internal Server Error


Content-Length: 460
Content-Type: text/xml; charset="utf-8"
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Body>
<soap:Fault>
<faultcode>123XYZ</faultcode>
<faultstring>Server Error</faultstring>
<detail>
<bank:faultdetails xmlns:bank="urn:OnlineBank">
<message>Your account is overdrawn</message>
<errorcode>1234</errorcode>
</bank:faultdetails>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Soap Fault có những phần con như faultcode, faultstring, faultactor, faultdetail
để cung cấp những thông tin chi tiết khi có lỗi phát sinh. Trong những môi trường
lập trình cao cấp như Java, .NET, khi soap fault phát sinh thì một ngoại lệ
(Exception) cũng được phát sinh để báo cho lập trình viên có xử lý tương ứng.

161
Java Mobile

8.3.2. WSDL (Web Service Definition Language)


Khi chúng ta đã xây dựng hoàn thành web service cần phải cung cấp tài liệu mô
tả để các nhà phát triển client có thể sử dụng được web service trên. Tài liệu mô tả
web service cần mô tả được vị trí web service, các hàm nó cung cấp, tham số kèm
theo…
Tài liệu WSDL là một tài liệu thỏa mãn các nhu cầu trên. WSDL (Web Service
Definition Language) là một ngôn ngữ dựa trên cú pháp XML dùng để định nghĩa
một web service. Nói cách khác, một file WSDL như một người trung gian đứng
giữa web service và ứng dụng web service client.
Trong tài liệu WSDL, chúng ta sẽ định nghĩa các phương thức được web service
hỗ trợ, các kiểu dữ liệu được xử dụng trong các phương thức cùng các thông điệp
được trao đổi giữa client và server ứng với mỗi phương thức. Chúng ta chỉ phải
định nghĩa các kiểu dữ liệu phức tạp như mảng, các lớp được khai báo thêm trong
chương trình, mảng các lớp … còn các kiểu dữ liệu cơ bản như int, string, float …
đã được hỗ trợ sẵn. Sau đó, chúng ta gộp chung các định nghĩa này kết hợp với các
giao thức mạng bên dưới để hình thành một end-point (tạm dịch là một đầu cuối).

Hình 8.4 Web Service Endpoint

162
Java Mobile

Một endpoint interface (gọi tắt là một enpoint) gồm có nhiều ports, mỗi port quy
định một cách liên lạc với web service khác nhau ứng với mỗi giao thức bên dưới
khác nhau. Sự kết hợp của web service với một giao thức mạng như thế được gọi là
một binding, như trong hình 8.4 chúng ta thấy có 3 binding khác nhau. Port 1 sử
dụng SOAP/HTTP binding, Port 2 sử dụng SOAP/HTTPS binding, Port 3 sử dụng
các dạng binding khác. Như vậy ứng với web service trên, ta có đến 3 phương tiện
khác nhau để triệu gọi các hàm.
Các hình thức binding thông dụng nhất hiện nay vẫn là SOAP/HTTP POST và
SOAP/HTTPS (hỗ trợ bảo mật thông qua SSL).
Việc phát sinh file WSDL sẽ được tự động thực hiện bởi các bộ công cụ (như
Visual Studio .NET) do đó chúng ta không nhất thiết phải hiểu rõ cấu trúc file
WSDL. Tuy nhiên, nếu hiểu cấu trúc file WSDL sẽ cung cấp cho chúng ta thêm
nhiều tùy biến cũng như khả năng sửa lỗi (debug) tốt hơn.
Cấu trúc file WSDL:
Một tài liệu WSDL thực chất chỉ là một danh sách các định nghĩa. Trong một file
WSDL, phần tử gốc được đặt tên là "definitions". Phần tử này chứa năm phần tử
con chính để định nghĩa web service. Thứ tự xuất hiện của các phần tử con này:
• Phần tử "types": định nghĩa các kiểu dữ liệu dùng để trao đổi giữa client và
server (chỉ định nghĩa các kiểu dữ liệu phức tạp như structure, class…).
• Phần tử "message": định nghĩa các thông điệp được trao đổi.
• Phần tử "portType": định nghĩa một tập các chức năng web service hỗ trợ và
thông điệp tương ứng đối với mỗi chức năng đó.
• Phần tử "binding": Sau khi đã định nghĩa các port, ta cần chỉ rõ ràng buộc
giữa các ports này và các giao thức tầng dưới. Phần tử binding sẽ đảm nhiệm
chức năng này (sẽ được đề cập kỹ hơn ở phần sau).
• Phần tử "service": Có tác dụng gom các ports đã định nghĩa thành từng
nhóm.

163
Java Mobile

Để hiểu rõ hơn về file WSDL chúng ta sẽ cùng tìm hiểu một ví dụ chính thức của
hãng Microsoft (ebook Developing XML Web Service Using Microsoft Studio
.NET):
public class Acct
{
public string description;
public string number;
public string type;
public decimal balance;
[XmlAttribute("status")]
/*chỉ rõ status là một attr chứ không phải node con.*/
public string status;
}
public class TheBank
{
[WebMethod]
/*
Phần [WebMethod] báo hiệu đây là hàm được export bởi web service để cho
phép truy cập từ xa. Điều này sẽ được trình bày rõ hơn ở phần xây dựng web
service bằng Visual Studio .NET
*/
public Acct GetAccount(string acctNumber)
{
Acct a = new Acct();
a.description = "Adam's savings acct";
a.balance=10000.0M;
a.number="1234-XX";
a.status="active";
a.type="SV";

164
Java Mobile

return a;
}
}
Đây là một đoạn code khá đơn giản, ta định nghĩa một lớp Acct và cung cấp một
phương thức để lấy về một Account, tham số truyền vào có kiểu string.
Chúng ta sẽ xem xét qua cấu trúc các phần tử vừa nêu đối với web service trên.

8.3.2.1. Phấn tử types:


Các quy tắc định nghĩa trong phần tử types đều tuân theo chuẩn XML
Schema Definition Language (XSD). Tham số acctNumber được định nghĩa như
sau:
...
<types>
...
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="acctNumber" nillable="true"
type="s:string" />
</s:sequence>
</s:complexType>
...
</types>
Phần định nghĩa lớp Acct (kết quả trả về của hàm GetAccount) sẽ phức tạp hơn:
<s:complexType name="Acct">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="description" type="s:string" />
<s:element minOccurs="1" maxOccurs="1"

165
Java Mobile

name="number" type="s:string" />


<s:element minOccurs="1" maxOccurs="1"
name="type" type="s:string" />
<s:element minOccurs="1" maxOccurs="1"
name="balance" type="s:decimal" />
</s:sequence>
<s:attribute name="status" type="s:string" />
</s:complexType>

Dựa vào định nghĩa trên, một đối tượng thuộc lớp Acct có thể được thể hiện như
sau:
<?xml version="1.0" encoding="utf-8"?>
<account status="active">
<description>Adam's savings acct</description>
<number>1234-XX</number>
<type>SV</type>
<balance>10000</balance>
</account>

Sau đó chúng ta phải định nghĩa cấu trúc các thông điệp được trao đổi trong
quá trình gọi hàm và nhận kết quả. Ta tuân theo một quy tắc: cấu trúc gói tin request
(lời gọi hàm) sẽ có tên trùng với tên hàm, cấu trúc gói tin response sẽ có tên là tên
hàm cộng với Response ở cuối.

<s:element name="GetAccount">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="acctNumber" nillable="true"

166
Java Mobile

type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetAccountResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
name="account" type="s0:Acct" />
</s:sequence>
</s:complexType>
</s:element>
Trên đây là toàn bộ nội dung phần types.

8.3.2.2. Phần tử message:


Bên cạnh việc định nghĩa các kiểu dữ liệu được truyền giữa client và server
ta cần phải định nghĩa các thông điệp được truyền đi và hồi đáp. Bởi và các thông
điệp không phụ thuộc vào các giao thức tầng dưới nên các thông điệp có thể được
định nghĩa dưới dạng HTTP-GET/POST, SOAP hay bất kỳ một protocol nào hỗ trợ
Web Service.
Chúng ta có thể đặt tên bất kỳ cho thông điệp vì web service không đưa ra
một ràng buộc cũng như quy tắc đặt tên nào cả. Các phần tử message có thể chứa
nhiều phần tử con "part" (cũng có khi không chứa phần tử con nào). Một phần tử
"part" tượng trưng cho một tham số được truyền trong hàm. Một phần tử part phải
có một tên và kiểu dữ liệu tương ứng đã được định nghĩa.
Đối với ví dụ trên thì phần tử message có dạng như sau:
<message name="GetAccountIn">
<part name="parameters" element="s0:GetAccount" />
</message>

167
Java Mobile

<message name="GetAccountOut">
<part name="parameters" element="s0:GetAccountResponse" />
</message>
Ở đây ta gập lại cấu trúc GetAccout và GetAccountResponse đã định nghĩa ở
phần types. Theo như định nghĩa trên, thông điệp đầu vào GetAccountIn nhận một
tham số có kiểu GetAccount và thông điệp đầu ra GetAccountOut trả về một kết
quả có kiểu GetAccountResponse; cả hai kiểu này đã được định nghĩa ở phần tử
types trước đó. Các message được định nghĩa này sẽ được dùng ở phần sau.

8.3.2.3. Phần tử portType:


Ta có thể nói một cách đơn giản như sau: phần tử “types” định nghĩa các
kiểu dữ liệu, phần tử “message” định nghĩa tất cả các thông điệp (hay cũng có thể
gọi là gói tin) vào/ra nhưng lại chưa thể hiện được “thông điệp nào là của phương
thức nào”, vai trò này do portType đảm nhận.

<portType name="BankService">
<operation name="GetAccount">
<input message="s0:GetAccountIn" />
<output message="s0:GetAccountOut" />
</operation>
</portType>

Chúng ta có thể nhận thấy, các từ khóa input và output được dùng để chỉ rõ gói
tin request và gói tin response.

Phần định nghĩa portType trên cũng khá đơn giản, đối với hàm GetAccount ( ) sẽ có
hai thông điệp:
• Thông điệp input: Lời gọi hàm từ client gửi lên server, có tên
GetAccountIn. Nếu đọc ngược lên phần tử message, ta sẽ thấy thông điệp

168
Java Mobile

GetAccountIn sẽ có kiểu GetAccount, và kiểu dữ liệu GetAccount được định


nghĩa trong phần tử types.
• Thông điệp output: Kết quả trả về được gửi từ server đến client, có tên
GetAccountOut. Tương tự, phần tử message đã cho chúng ta biết thông điệp
GetAccountOut sẽ có kiểu GetAccountResponse và kiểu này đã được định
nghĩa trong phần types.

8.3.2.4. Phần tử binding

Các phần tử chúng ta đã xem xét qua có trách nhiệm định nghĩa web service
một cách trừu tượng: chúng cho biết các phương thức được web service hỗ trợ, các
thông tin kèm theo như tham số truyền vào, kết quả trả về của mỗi phương thức.
Tuy nhiên, với những thông tin trên chúng ta chưa xác định được sẽ phải dùng công
cụ nào để truy xuất đến web service này: ta sẽ dùng SOAP kết hợp với HTTP hay
SOAP/HTTPS hay công cụ nào khác? Phần tử binding sẽ định nghĩa cách thức truy
cập web service thông qua các protocols bên dưới.

Mỗi phần tử binding sẽ mô tả cách thức liên kết một portType vào một
protocol nhất định. Nếu web service của chúng ta hỗ trợ nhiêu protocol thì phải tạo
cho mỗi protocol một phần tử binding.

<binding name="BankService" type="s0:BankService">


<soap:binding transport = "http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="GetAccount">
<soap:operation soapAction =
“http://woodgrovebank.com/GetAccount” style="document" />
<input>
<soap:body use="literal" />
</input>

169
Java Mobile

<output>
<soap:body use="literal" />
</output>
</operation>
</binding>

Đoạn ví dụ trên cho biết web service sử dụng SOAP là protocol trao đổi
thông tin và gói tin soap sẽ được vận chuyển bằng HTTP, chúng ta có thể sử dụng
nhiều công cụ khác để truy xuất đến các hàm của web service nhưng SOAP hiện
nay là thông dụng nhất. Đoạn định nghĩa trên còn chỉ rõ “document/encoding style”
được sử dụng là dạng document/literal (còn có một dạng khác khá phổ biến là
rpc/encoded; hiện tại j2me chỉ hỗ trợ web service dạng document/literal).

8.3.2.5. Phần tử service:


Phần cuối cùng của file WSDL chứa định nghĩa các thông số vật lý cụ thể
dùng để truy xuất đến web service.

<service name="BankService">
<port name="BankService" binding="s0:BankService">
<soap:address location =
"http://www.woodgrovebank.com/Bank/BankService.asmx"/>
</port>
</service>

Giá trị location trong phần tử port chỉ rõ vị trí đặt web service. Phần tử
“binding” cho biết cách thức ánh xạ các phương thức trong phần tử “portType”
thành các gói tin SOAP (hoặc gói tin của các protocols khác) nhưng không cho biết
làm thế nào để tạo được một đối tượng portType. Đấy là nhiệm vụ của phần tử port,
phần tử port sẽ ánh xạ một phần tử portType sang một địa chỉ URI cụ thể. Node

170
Java Mobile

service sẽ gom nhóm các port liên quan đến nhau. Nếu web service có thể được truy
xuất đến bởi nhiều protocol thì sẽ có nhiều phần tử port được định nghĩa.

Trên đây là toàn bộ nội dung của một file WSDL, có khá nhiều điểm phức
tạp. Tuy nhiên, với vai trò là người sử dụng web service cũng như người xây dựng
web service đơn thuần chúng ta không cần nắm rõ cấu trúc file này vì đã có các
công cụ hỗ trợ. Cả J2ME và Visual .NET đều hỗ trợ công cụ đọc file WSDL để phát
sinh các lớp tương ứng phục vụ cho việc truy xuất hàm từ xa, mọi công việc phức
tạp bên dưới đã được giấu đi với nhà phát triển ứng dụng.

171
Java Mobile

Chương 9: Ứng dụng đăng ký học phần

9.1 Đặc tả chương trình:

9.1.1 Tổng quan:


Chương trình hỗ trợ các chức năng đăng ký học phần, xem thời khoá biểu,
xem điểm thi… chạy trên môi trường điện thoại di động. Sau khi cài đặt chương
trình lên điện thoại và đăng ký dịch vụ truy cập Internet từ điện thoại, người dùng
có thể sử dụng hầu hết các tiện ích tương tự hệ thống SMS mà không cần có máy
tính kết nối Internet như hiện nay. Ngoài J2ME, chương trình còn sử dụng công
nghệ WebService trong kết nối mạng. Vấn đề bảo mật trong chương trình tương đối
không cần thiết, chỉ sử dụng trong quá trình gửi password khi đăng nhập nhằm
tránh việc đánh cắp password.

Chương trình được thực hiện với mục tiêu mô phỏng lập trình trên thiết bị di
động bằng J2ME nên chỉ sử dụng cơ sở dữ liệu tự xây dựng. Việc ứng dụng thực tế
trên cơ sở dữ liệu chính của hệ thống SMS là hướng mở rộng trong tương lai của
chương trình.

9.1.2 Các chức năng chính:


Khi người dùng khởi động ứng dụng client, chương trình yêu cầu người dùng
đăng nhập với account, password của hệ thống SMS.
Nếu đăng nhập không hợp lệ người dùng phải nhập lại account/password để
đăng nhập lại. Nếu đăng nhập hợp lệ, người dùng có thể truy cập hệ thống và sử
dụng các chức năng sau của chương trình.

9.1.2.1 Xem thời khoá biểu:


Người dùng nhập tên và số thứ tự lớp (vd:Lớp TH2001 STT:1) để xem
thời khoá biểu của học kỳ hiện tại của lớp tương ứng.

172
Java Mobile

9.1.2.2 Đăng ký học phần:


Trong thời gian được đăng ký, người dùng có thể đăng ký các học phần
lý thuyết cũng như học phần thực hành mà trường mở trong học kỳ này.

9.1.2.3 Xem phiếu đăng ký:


Xem lại các học phần lý thuyết và thực hành mà người dùng đã thực hiện
đăng ký.

9.1.2.4 Xem điểm thi:


Xem kết quả học tập của sinh viên .

9.1.2.5 Xem thông báo:


Xem thông báo của giáo vụ khoa.

173
Java Mobile

9.2 Kiến trúc chương trình:

9.2.1 Mô hình kết nối:

HTTP request/ response


Gateway

Internet .NET
GPRS

Web Server

Store Procedures

J2ME / SQL Server


JSR172

Client DB Server

Hình 9.1 Kiến trúc chương trình ứng dụng

Ứng dụng MIDlet chạy trên điện thoại di động đóng vai trò 1 client. Client
này sau khi đăng ký sử dụng dịch vụ internet cho điện thoại sẽ có khả năng kết nối
đến server.
Client được viết bằng J2ME đóng gói thành DKHP.jar và DKHP.jad. Server
là chương trình viết bằng .NET chạy trên HTTP server, không có giao diện. Server
sẽ trao đổi thông tin với Database server thông qua các Store procedure. Cơ sở dữ
liệu xây dựng trên SQL Server.
Mô hình hoạt động:

174
Java Mobile

• Điện thoại sẽ chủ động kết nối và gửi gói tin đến web server. Gói
tin sẽ được gửi dưới dạng sóng GPRS đến trạm điện thoại, trách
nhiệm của nhà cung cấp điện thoại sẽ phải chuyển tín hiệu từ dạng
sóng GPRS sang dạng tín hiệu truyền trong đường truyền hữu
tuyến internet.
• Lúc này nhà cung cấp dịch vụ di động sẽ hoạt động như một
gateway, làm trung gian liên lạc cho thiết bị di động và web server.
• Gói tin được điện thoại di động gửi đến web server là những gói tin
HTTP request và ngược lại web server sẽ hồi đáp bằng những gói
tin HTTP response. Các gói tin HTTP request và HTTP response
này sẽ chứa bên trong các thông điệp SOAP request và SOAP
response tương ứng. Các gói tin SOAP chính là trung tâm của kỹ
thuật web service, các thông điệp SOAP này sẽ chứa các lời gọi
hàm, tham số truyền đi, các tham số trả về… tạo thành mô hình
truy xuất hàm từ xa RPC (Remote Procedure Call).
• Khi web server nhận được yêu cầu xử lý từ điện thoại (thể hiện qua
các lời gọi hàm) sẽ truy xuất và giao tiếp với SQL Server qua các
store procedure để thực hiện các xử lý nghiệp vụ của chương trình.
Thông tin sau khi được sử lý sẽ được gửi trả cho client thông qua
các HTTP response.
• Các gói tin HTTP response này sẽ đến nhà cung cấp dịch vụ di
động, chuyển thành dạng tín hiệu GPRS và về đến client.
Trên đây là mô hình khái quát hoạt động của ứng dụng trong bối cảnh mạng
điện thoại di động. Yêu cầu duy nhất của thiết bị phần cứng là điện thoại phải hỗ trợ
GPRS và thư viện JSR 172. Thư viện JSR 172 có chức năng tạo các thông điệp
SOAP và phân tích nội dung các thông điệp này, nếu không có thư viện này chúng
ta không thể tạo các lời gọi hàm cũng như lấy các kết quả trả về từ hồi đáp của
server.

175
Java Mobile

9.2.2 Mô hình bảo mật (mã hoá password):


Sử dụng thuật toán DES, dùng khoá đối xứng để mã hoá password trong chương
trình.

Same Private Key

Encrypted
Session
Key

Encrypted Data

Same Same
Session Session
Key Key

Hình 9.2 Mô hình mã hoá password

176
Java Mobile

9.3 Phân tích - thiết kế:

9.3.1 Mô hình use case:

9.3.1.1 Lược đồ chính:

Hình 9.3 Lược đồ use case

9.3.1.2 Danh sách các use case:


STT Use case Ý nghĩa
1 Dang nhap Đăng nhập hệ thống
2 Dang ky ly thuyet Đăng ký các học phần lý thuyết

177
Java Mobile

3 Dang ky thuc hanh Đăng ký các học phần thực hành


4 Xem phieu dang ky Xem phiếu đăng ký học phần
5 Xem ket qua hoc tap Xem kết quả học tập của sinh viên
6 Xem thoi khoa bieu Xem thời khoá biểu của lớp học
7 Xem thong bao Xem thông báo của giáo vụ khoa
Bảng 9.1 Danh sách các Use Case

9.3.2 Đặc tả một số use case chính:

9.3.2.1 Đăng nhập:


Mô tả: Hỗ trợ người dùng đăng nhập vào hệ thống.
Tác nhân kích hoạt: người dùng.
Luồng sự kiện chính:
o Chương trình client yêu cầu người dùng nhập account (MSSV),
password.
o Người dùng nhập thông tin theo yêu cầu.
o Client gửi yêu cầu đến server.
o Server phát sinh một số ngẫu nhiên (8 bytes), sau đó mã hoá bằng mật
mã (khoá đối xứng mà server và client đã chọn từ trước) bằng thuật
toán DES thành session key và gửi về cho client.
o Client dùng khoá bí mật giải mã session key này để tạo lại số ngẫu
nhiên tương ứng mà server đã tạo. Sau đó, client dùng số ngẫu nhiên
vừa tìm được để mã hoá password gửi kèm account đến server.
o Server nhận hai giá trị này từ client, truy cập cơ sở dữ liệu để lấy
password của account tương ứng. Sau đó, dùng session key mã hoá
password trong cơ sở dữ liệu và so sánh kết quả với password đã được
mã hoá nhận từ client. Nếu hợp lệ, trả về client giá trị “true”, nếu
không, trả về “false”.
o Client nhận kết quả từ server.
Điều kiện sau: tuỳ theo kết quả trả về từ server,

178
Java Mobile

o nếu là “false”, thông báo đăng nhập không hợp lệ, người dùng phải
đăng nhập lại để sử dụng chương trình.
o nếu là “true”, người dùng đăng nhập hợp lệ, hiển thị menu chức năng
chương trình cho người dùng sử dụng.

9.3.2.2 Đăng ký lý thuyết:


Mô tả: Cho phép người dùng đăng ký các học phần lý thuyết có mở trong
học kỳ này.
Tác nhân kích hoạt: ngừơi dùng
Luồng sự kiện chính:
o Người dùng chọn chức năng đăng ký lý thuyết.
o Client gửi yêu cầu đến cho server.
o Server lấy danh sách tất cả các học phần có mở trong học kỳ này, có
đánh dấu các học phần người dùng đã đăng ký trước đó, trả về cho
client.
o Client hiển thị danh sách lên cho người dùng, người dùng chọn các
môn muốn đăng ký hoặc hiệu chỉnh lại đăng ký cũ.
o Người dùng nhấn nút đăng ký, client lấy danh sách các môn mới được
đăng ký và các môn vừa được người dùng gỡ bỏ gửi cho server.
o Server truy cập cơ sở dữ liệu, xoá các đăng ký thực hành đã đăng ký
trong học kỳ này. Sau đó xoá các đăng ký lý thuyết cũ đã được gỡ bỏ
và ghi các đăng ký lý thuyết mới.
Luồng sự kiện phụ: Sau khi hết use case đăng ký lý thuyết, use case xem
phiếu đăng ký lý thuyết sẽ được gọi.
Điều kiện trước: Người dùng phải đăng nhập thành công vào hệ thống.

179
Java Mobile

9.3.2.3 Đăng ký thực hành:


Mô tả: Cho phép người dùng đăng ký các học phần thực hành trong học kỳ
này
Tác nhân kích hoạt: Người dùng.
Luồng sự kiện chính:
o Người dùng chọn chức năng đăng ký thực hành.
o Client gửi yêu cầu lên server.
o Server lấy từ cơ sở dữ liệu tất cả các học phần thực hành có mở tương
ứng với các học phần lý thuyết mà người dùng đã đăng ký. Các học
phần thực hành đã được người dùng đăng ký trước được đánh dấu
riêng
o Client nhận thông tin từ server, hiển thị danh sách các học phần thực
hành để người dùng đăng ký.
o Sau khi người dùng nhấn nút đăng ký, client sẽ lấy danh sách các lớp
người dùng mới đăng ký và danh sách các lớp người dùng bỏ đăng ký
gửi lên server.
o Server truy cập cơ sở dữ liệu, thực hiện đăng ký và huỷ đăng ký theo
yêu cầu của client.
Luồng sự kiện phụ: Sau khi hết use case đăng ký lý thuyết, use case xem
phiếu đăng ký lý thuyết sẽ được gọi.
Điều kiện trước: Người dùng phải đăng nhập thành công vào hệ thống.

9.3.2.4 Xem phiếu đăng ký:


Mô tả: Cho phép người dùng xem lại danh sách các học phần lý thuyết hay
thực hành mà người dùng đã đăng ký trong học kỳ này.
Tác nhân kích hoạt: người dùng, hệ thống.
Luồng sự kiện chính:

180
Java Mobile

o Người dùng chọn một trong hai chức năng xem phiếu đăng ký học
phần lý thuyết hay phiếu đăng ký học phần thực hành.
o Client gửi yêu cầu lên server.
o Server truy cập cơ sở dữ liệu, lấy danh sách các học phần lý thuyết
hay thực hành theo yêu cầu client mà người dùng đã đăng ký thành
công, trả về cho client.
o Client hiển thị kết quả cho người dùng.
Điều kiện trước: Người dùng phải đăng nhập thành công vào hệ thống.

9.3.2.5 Xem kết quả học tập:


Mô tả: Cho phép người dùng xem kết quả các học phần người dùng có học
và đã có điểm trong một học kỳ cụ thể.
Tác nhân kích hoạt: Người dùng.
Luồng sự kiện chính:
o Người dùng chọn chức năng xem kết quả học tập.
o Client yêu cầu người dùng chọn học kỳ, năm học muốn xem điểm thi.
o Người dùng nhập thông tin yêu cầu, nhấn nút xem điểm. Client gửi
yêu cầu đến server.
o Server truy cập cơ sở dữ liệu, lấy danh sách điểm thi các môn học
thoả yêu cầu (các học phần trong học kỳ yêu cầu và đã có điểm thi)
gửi cho client.
o Client hiển thị kết quả cho người dùng.
Điều kiện trước: Người dùng phải đăng nhập thành công vào hệ thống.

9.3.2.6 Xem thời khoá biểu:


Mô tả: Cho phép người dùng xem thời khoá biểu các học phần của lớp trong
học kỳ hiện tại.
Tác nhân kích hoạt: Người dùng.

181
Java Mobile

Luồng sự kiện chính:


o Người dùng chọn chức năng xem thời khoá biểu.
o Client yêu cầu người dùng nhập thông tin lớp học muốn xem thời
khoá biểu (tên lớp, số thứ tự lớp).
o Người dùng nhập thông tin theo yêu cầu và nhấn nút xem thời khoá
biểu lý thuyết hoặc thời khoá biểu thực hành.
o Client gửi yêu cầu lên server.
o Server truy cập cơ sở dữ liệu, lấy danh sách thông tin các học phần lý
thuyết hoặc học phần thực hành có mở trong học kỳ này theo yêu cầu,
gửi trả về cho client.
o Client hiển thị kết quả trả về cho người dùng.

9.3.2.7 Xem thông báo:


Mô tả: Hỗ trợ người dùng xem các thông báo của giáo vụ khoa.
Tác nhân kích hoạt: Người dùng.
Luồng sự kiện chính:
o Người dùng chọn chức năng xem thông báo.
o Client gửi yêu cầu lên server.
o Server truy cập cơ sở dữ liệu, lấy tiêu đề của 10 thông báo gần đây
nhất, sắp xếp theo thời gian giảm dần, gửi về cho client.
o Client hiển thị các tiêu đề thông báo này cho người dùng.
Luồng sự kiện phụ:
o Nếu người dùng chọn một trong các tiêu đề và nhấn nút xem thông
báo. Client sẽ gửi yêu cầu đến server.
o Server truy cập cơ sở dữ liệu để lấy nội dung thông báo, trả về cho
client. Client hiển thị nội dung này lên màn hình cho người dùng.

182
Java Mobile

9.4 Thiết kế mô hình dữ liệu:

9.4.1 Mô hình thực thể kết hợp:

Hình 9.4 Mô hình thực thể kết hợp ER

9.4.2 Các bảng dữ liệu:


ChuyenNganh: MaChuyenNganh, TenChuyenNganh
SV: MaSV, TenSV, NgaySinh, DiaChi, ChuyenNganh, password
MonHoc: MaMH, TenMonHoc, SoTCLT, SoTCTH

183
Java Mobile

GV: MaGV, TenGV, DiaChi


Lop: MaLop, TenLop, STT
Lop_MonLT: MaLopLT, MaLop, STT, MaMH, HK, NamHoc, SiSo, SiSoMax,
MaGV, Phong, Thu, Tiet
Lop_MonTH: MaLopTH, MaLopLT, STT, SiSo, SiSoMax, Phong, Thu, Tiet
PhanCongTH: MaGV, MaLopTH
DangKyLT: MaSV, MaLopLT, DiemLT, DiemTH, DiemTC
DangKyTH: MaSV, MaLopTH
ThongBao: MaThongBao, NgayTB, TieuDe, NoiDung

9.4.3 Chi tiết các bảng dữ liệu:

9.4.3.1 ChuyenNganh:
Các chuyên ngành của khoa
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaChuyenNganh nvarchar(4) Mã chuyên ngành Khóa chính
TenChuyenNganh nvarchar(100) Tên chuyên ngành
Bảng 9.2 Table ChuyenNganh

9.4.3.2 SV:
Lưu trữ thông tin của sinh viên
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaSV nvarchar(10) Mã số sinh viên Khóa chính
TenSV nvarchar(60) Tên sinh viên
NgaySinh datetime Ngày sinh của sinh viên
DiaChi nvarchar(100) Địa chỉ của sinh viên
ChuyenNganh nvarchar(4) Mã chuyên ngành Khoá ngoại
password nvarchar(25) Mật mã account của sinh viên
Bảng 9.3 Table SV

184
Java Mobile

9.4.3.3 MonHoc:
Lưu trữ thông tin môn học
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaMH nvarchar(5) Mã môn học Khoá chính
TenMH nvarchar(30) Tên môn học
SoTCLT int Số tín chỉ lý thuyết
SoTCTH int Số tín chỉ thực hành
Bảng 9.4 Table MonHoc

9.4.3.4 GV:
Lưu trữ thông tin giáo viên
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaGV int Mã giáo viên Khoá chính
TenGV nvarchar(60) Tên giáo viên
DiaChi nvarchar(100) Địa chỉ liên lạc của giáo viên
Bảng 9.5 Table GV

9.4.3.5 Lop:
Lưu thông tin lớp
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaLop nvarchar(12) Mã lớp Khoá chính
TenLop nvarchar(10) Tên lớp (niên khoá tương ứng)
STT int Số thứ tự lớp (cùng niên khoá)
Bảng 9.6 Table Lop

9.4.3.6 Lop_MonLT:
Lưu thông tin các học phần lý thuyết được mở trong mỗi học kỳ
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaLopLT int Mã học phần Khoá chính

185
Java Mobile

MaLop nvarchar(12) Mã lớp tương ứng Khoá ngoại


STT int STT lớp (nếu mở nhiều lớp nhỏ
như các lớp Anh văn)
MaMH nvarchar(5) Mã môn học Khoá ngoại
HK int Học kỳ (1 hay 2)
NamHoc nvarchar(9) Năm học (vd: 2004-2005)
SiSo int Sĩ số đăng ký hiện tại
SiSoMax int Sĩ số dự kiến
MaGV int Mã giáo viên phụ trách Khoá ngoại
Phong nvarchar(10) Phòng học
Thu nvarchar(5) Lịch học vào các ngày trong
tuần
Tiết nvarchar(5) Tiết học trong ngày
Bảng 9.7 Table Lop_MonLT

9.4.3.7 Lop_MonTH:
Lưu thông tin các lớp thực hành tương ứng của các lớp lý thuyết
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaLopTH int Mã lớp thực hành Khoá chính
MaLopLT int Mã lớp lý thuyết tương ứng Khoá ngoại
STT int Số thứ tự lớp thực hành(một lớp
lý thuyết có thể có nhiều lớp
thực hành)
SiSo int Sĩ số đăng ký hiện tại
SiSoMax int Sĩ số dự kiến
MaGV int Mã giáo viên hướng dẫn thực Khoá ngoại
hành
Phong nvarchar(10) Phòng học
Thu nvarchar(5) Lịch học vào các ngày trong

186
Java Mobile

tuần
Tiết nvarchar(5) Tiết học trong ngày
Bảng 9.8 Table Lop_MonTH

9.4.3.8 PhanCongTH:
Phân công giáo viên hướng dẫn thực hành cho từng lớp
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaGV int Mã giáo viên hướng dẫn
Khoá chính
MaLopTH int Mã lớp thực hành
Bảng 9.9 Table PhanCongTH

9.4.3.9 DangKyLT:
Thông tin đăng ký học phần lý thuyết
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaSV nvarchar(10) Mã số sinh viên
Khoá chính
MaLopLT int Mã lớp lý thuyết đăng ký
DiemLT float Điểm thi lý thuyết
DiemTH float Điểm thi thực hành
DiemTC float Điểm tổng cộng
Bảng 9.10 Table DangKyLT

9.4.3.10 DangKyTH:
Thông tin đăng ký học phần thực hành
Tên field Kiểu dữ liệu Ý nghĩa Ghi chú
MaSV nvarchar(10) Mã số sinh viên
Khoá chính
MaLopTH int Mã lớp thực hành đăng ký
Bảng 9.11 Table DangKyTH

9.4.3.11 ThongBao:
Các thông báo của văn phòng khoa

187
Java Mobile

Tên field Kiểu dữ liệu Ý nghĩa Ghi chú


MaThongBao int Mã thông báo (tự động) Khoá chính
NgayTB datetime Ngày ra thông báo
TieuDe nvarchar(100) Tiêu đề của thông báo
NoiDung nvarchar(2000) Nội dung thông báo
Bảng 9.12 Table ThongBao
9.4.4 Ràng buộc dữ liệu:

9.4.4.1 Ràng buộc miền giá trị:


Điểm lý thuyết, điểm thực hành, điểm tổng cộng trong khoảng 0 đến 10.

Ngày sinh của sinh viên phải nhỏ hơn ngày hiện tại.
Năm học có dạng xxxx-yyyy với yyyy=xxxx+1 . Vd: 2004-2005.
Mã môn học có dạng xxyyy với xx là dạng ký tự, yyy là các ký số.
Học kỳ có giá trị 1 hoặc 2.
Sĩ số các lớp lý thuyết, thực hành là số không âm.
Sĩ số tối đa các lớp lý thuyết, thực hành là số dương.

9.4.4.2 Ràng buộc liên thuộc tính:


Điểm thực hành không lớn hơn điểm tổng cộng.
Điểm lý thuyết không lớn hơn điểm tổng cộng.
Các lớp lý thuyết, lớp thực hành có sĩ số không lớn hơn sĩ số max.
Trong cùng một học kỳ, một năm học, các học phần lý thuyết của cùng một môn
học phải có số thứ tự liên tục từ 1.
Trong cùng một lớp lý thuyết, các lớp thực hành phải có số thứ tự liên tục từ 1.

9.4.4.3 Ràng buộc liên quan hệ, liên bộ:


Sĩ số hiện tại của các lớp lý thuyết, lớp thực hành bằng tổng số sinh viên đã đăng ký
học lớp đó.

188
Java Mobile

9.4.4.4 Ràng buộc chu trình:


Sinh viên chỉ được phép đăng ký các học phần thực hành của các học phần lý thuyết
đã đăng ký.

Lop_MonLT

MaLopLT MaLopTH

DangKyLT DangKyTH

MaSV

: Các học phần thực hành SV đã đăng ký

: Các học phần thực hành có mở ứng với các học phần lý
thuyết SV đã đăng ký

Hình 9.5 Ràng buộc chu trình

189
Java Mobile

9.4.5 Mô hình dữ liệu:

Hình 9.6 Mô hình cơ sở dữ liệu


9.4.6 Các chức năng store procedures:
• sp_XEM_DIEM: Lấy điểm thi của sinh viên trong một học kỳ cho
trước hay tất cả các học kỳ.
• sp_XEM_TKB_LT: Lấy thông tin thời khoá biểu lý thuyết của một
lớp khi biết tên lớp và số thứ tự lớp.
• sp_XEM_TKB_TH: Lấy thông tin thời khoá biểu thực hành của một
lớp khi biết tên lớp và số thứ tự lớp.

190
Java Mobile

• sp_DelAllTH: Xoá tất cả đăng ký thực hành của một sinh viên tại
một học kỳ cho trước. (Khi sinh viên hiệu chỉnh đăng ký lý thuyết thì
tất cả các học phần thực hành cũ đã đăng ký sẽ bị xoá trước)
• sp_DelRegisterLT: Xoá đăng ký một học phần lý thuyết.

• sp_getLopLT: Lấy thông tin tất cả các học phần lý thuyết có mở


trong một học kỳ cho trước, có đánh dấu các học phần đã được sinh
viên đăng ký. Dùng để hiển thị danh sách các học phần lý thuyết để
sinh viên đăng ký.

• sp_getLopTH: Lấy thông tin các học phần thực hành có mở tương
ứng với các học phần lý thuyết mà sinh viên đã đăng ký.
• sp_getRegLT: Lấy thông tin đăng ký học phần lý thuyết của sinh
viên trong một học kỳ cho trứơc.
• sp_getRegTH: Lấy thông tin đăng ký học phần thực hành của sinh
viên trong học kỳ cho trước.
• sp_RegisterLT: Thực hiện đăng ký một học phần lý thuyết. (Chỉ cho
phép đăng ký khi sĩ số đăng ký còn nhỏ hơn sĩ số tối đa của học phần
đó)
• sp_RegisterTH: Thực hiện đăng ký một học phần thực hành. (Chỉ
cho phép đăng ký khi sĩ số đăng ký còn nhỏ hơn sĩ số tối đa)
• sp_getNewsTitle: Lấy tiêu đề 10 thông báo gần đây nhất
• sp_getNewsContent: Lấy nội dung một thông báo cụ thể

9.4.7 Thiết kế lớp:


Chương trình phía client chỉ giữ nhiệm vụ nhận yêu cầu từ phía người dùng,
chuyển đến server. Chương trình phía server làm nhiệm vụ xử lý chính và tương tác
với cơ sở dữ liệu.

191
Java Mobile

Hình 9.7 Mô hình Lớp

9.5 Cài đặt - thử nghiệm:


9.5.1 Yêu cầu phần cứng:
• Client: điện thoại hỗ trợ kết nối GPRS (để kết nối mạng), gói JSR172 để hỗ
trợ gửi nhận các gói tin SOAP, gói JSR177 hỗ trợ mã hoá. Có thể sử dụng
chương trình giả lập của điện thoại tương ứng.
• Server: server hỗ trợ kết nối web (có địa chỉ cố định để client kết nối đến).
Cơ sở dữ liệu có thể đặt trực tiếp tại web server hay tại database server riêng
biệt.

192
Java Mobile

9.5.2 Yêu cầu phần mềm:


Client:
• Máy ảo Java j2sdk 1.4.2_05.
• J2ME Wireless Toolkit 2.3.
• Ngoài ra có thể dùng JBuider10 để hỗ trợ soạn thảo chương trình Java,
cũng như các chương trình giả lập điện thoại khác.

Server:
• Dot Net FrameWork.
• Database server phải cài sql server 2000.

9.5.3 Giao diện chương trình:


Server: không cần giao diện.
Client:

193
Java Mobile

Hình 9.8 Sơ đồ các màn hình

194
Java Mobile

9.5.3.1 Màn hình welcome:

Hình 9.9 Màn hình welcome

195
Java Mobile

9.5.3.2 Màn hình đăng nhập:

Hình 9.10 Màn hình đăng nhập


Khi đăng nhập, trước khi bắt đầu kết nối, chương trình hiển thị nhắc nhở
“bạn có thực sự muốn kết nối mạng hay không ?” vì khi kết nối, người dùng phải trả
chi phí cho nhà cung cấp dịch vụ. Nếu đồng ý, nhấn nút OK, chương trình sẽ thực
hiện kết nối và cho biết kết quả đăng nhập, nếu không, người dùng thoát khỏi ứng
dụng.

196
Java Mobile

Hình 9.11 Confirm

197
Java Mobile

9.5.3.3 Menu chức năng:

Hình 9.12 Menu chức năng

198
Java Mobile

9.5.3.4 Màn hình đăng ký lý thuyết:

Hình 9.13 Màn hình đăng ký học phần lý thuyết

199
Java Mobile

9.5.3.5 Màn hình đăng ký học phần thực hành:

Hình 9.14 Màn hình đăng ký học phần thực hành

200
Java Mobile

9.5.3.6 Màn hình xem thời khoá biểu:

Hình 9.15 Màn hình xem thời khoá biểu

201
Java Mobile

9.5.3.7 Màn hình xem kết quả học tập:

Hình 9.16 Màn hình xem kết quả học tập

202
Java Mobile

9.5.3.8 Màn hình xem phiếu đăng ký học phần:

Hình 9.17 Màn hình xem phiếu đăng ký

203
Java Mobile

9.5.3.9 Màn hình xem thông báo:

Hình 9.18 Màn hình xem thời khoá biểu

204
Java Mobile

Chương 10: Tổng kết

10.1 Kết luận:


Sau hơn 5 tháng thực hiện, luận văn đã hoàn thành và đạt được một số kết
quả nhất định. Chúng tôi đã cố gắng trình bày những kiến thức nền tảng trong J2ME
và xây dựng thành công ứng dụng “Đăng ký học phần bằng điện thoại di động”.
Luận văn giới thiệu các kiến thức về lập trình trên điện thoại di động dùng
J2ME, gồm:
• Giới thiệu về CLDC, MIDP.
• Các thành phần của ứng dụng MIDlet.
• Các thành phần giao diện trong MIDlet.
• Lưu trữ dữ liệu với RMS.
• Kết nối mạng với GCF.
• Nhắn tin SMS với WMA.
• …
Từ kết quả này, chúng tôi đã tiến hành xây dựng ứng dụng “Đăng ký học
phần bằng điện thoại di động”, với các kết quả đạt được:
• Ứng dụng hoàn chỉnh, với tương đối đầy đủ các chức năng tương tự
hệ thống đăng ký học phần SMS dành cho sinh viên trên web, có thể
áp dụng trong thực tế.
• Vận dụng tốt các kỹ thuật lập trình bằng J2ME.
• Sử dụng thuật toán DES để mã hoá password, sử dụng khoá bí mật 64
bits.
• Tìm hiểu và ứng dụng công nghệ Web service trong trao đổi dữ liệu
giữa server và client.
Tuy nhiên, vì được thực hiện trong thời gian giới hạn, nên luận văn vẫn còn
một số hạn chế:

205
Java Mobile

• Trong quá trình tìm hiểu công nghệ J2ME, có một số thuật ngữ tiếng
Anh không thể được chuyển ngữ một cách chính xác. Số lượng kiến
thức trong lãnh vực J2ME rất lớn và liên tục được cập nhật nên luận
văn chắc chắn còn nhiều thiếu sót.
• Ứng dụng chỉ được thử nghiệm bằng chương trình giả lập, chưa có
điều kiện chạy trên thiết bị thật.
• Ứng dụng sử dụng cơ sở dữ liệu tự xây dựng nên chưa hoàn toàn
chính xác với thực tế.
Các yêu cầu bắt buộc phải có để thử nghiệm được ứng dụng ở môi trường thực
tế:
• Phải có điện thoại di động hỗ trợ công nghệ JSR 172, ngoài ra để
phục vụ cho nhu cầu mã hoá dữ liệu, điện thoại cần hỗ trợ JSR 177.
• Điện thoại phải truy cập được GPRS và nhà cung cấp phải hỗ trợ dịch
vụ này.
• Phải có một server IIS và một địa chỉ IP thực (có thể đã thông qua
NAT). Do ta truy xuất thông qua nhà cung cấp dịch vụ viễn thông nên
không thể dùng các địa chỉ Private IP (10.0.0.0,172.29.0.0,…) cho
server.
Một số lý do khiến ứng dụng khó áp dụng rộng rãi ở Việt Nam tại thời điểm
hiện tại:
• Hiện tại số lượng điện thoại hỗ trợ bộ thư viện JSR-172 chưa nhiều vì
công nghệ này khá mới. Hiện nay chỉ một số điện thoại ra đời gần đây
là hỗ trợ công nghệ này, nhưng các điện thoại này hầu hết chưa có
mặt tại VN. (Nokia N90, N91; Motorola A860…)
• Công nghệ kết nối mạng được sử dụng là GPRS, hiện tại theo chúng
tôi được biết công nghệ này chỉ được hỗ trợ ở hai thành phố lớn là Hà
Nội và TP.Hồ Chí Minh. Giá cước của loại hình dịch vụ này hiện nay
còn khá đắt, khoảng 50/1Kbyte.

206
Java Mobile

10.2 Hướng phát triển:


Mục tiêu ban đầu của chúng tôi đề ra khi xây dựng ứng dụng là giúp cho sinh
viên của trường Tự Nhiên có thể đăng ký học phần qua điện thoại, tuy nhiên vì các
lý do khách quan về thiết bị phần cứng nên mong muốn của chúng tôi chưa đạt
được. Nhóm sẽ tiếp tục nghiên cứu và quan tâm đến các tin tức cập nhật về công
nghệ, đến khi điều kiện Việt Nam cho phép chúng tôi sẽ thử nghiệm ứng dụng của
mình trong môi trường thực tế.
Hiện tại ứng dụng của chúng tôi đang sử dụng Cơ Sở Dữ Liệu tự xây dựng
nên chưa có sự liên thông với dữ liệu của khoa CNTT. Việc này rõ ràng không
thuận tiện, gây dư thừa và có khả năng xảy ra đụng đột giữa hai hệ thống.Về sau,
nếu được phép chúng tôi sẽ tích hợp ứng dụng với dữ liệu của khoa theo mô hình
sau:

Hình 10.1 Hướng phát triển thực tế


Lúc này Web Service của chúng tôi sẽ đóng vai trò trung gian giữa ứng dụng
J2ME và ứng dụng Đăng Ký Học Phần của Khoa. Yêu cầu duy nhất đối với hệ
thống của khoa CNTT là cung cấp cho chúng tôi những chức năng chính dưới dạng
những hàm được export của một Web Service. Web Service của chúng tôi lúc này
không cần hỗ trợ thao tác với cơ sở dữ liệu mà đóng vai trò biến đổi những dữ liệu
gửi đến từ chương trình trên thiết bị di động để phù hợp với dữ liệu input của hệ

207
Java Mobile

thống của khoa CNTT và ngược lại. Lúc này việc coding trên điện thoại di động và
ứng dụng của Khoa hầu như không có thay đổi vì mọi thay đổi sẽ diễn ra tại web
service trung gian của chúng tôi. Có một điểm cần nói thêm là ứng dụng của khoa
không nhất thiết phải là một web service mà có thể chỉ là một ứng dụng TCP giao
tiếp thông qua socket đơn thuần. Lúc này chúng tôi sẽ giao tiếp với ứng dụng J2ME
qua giao thức web service và giao tiếp với ứng dụng của khoa theo mô hình lập
trình socket quen thuộc vẫn được.
Việc nghiên cứu công nghệ Web Service trong môi trường J2ME sẽ giúp
chúng tôi có thể xây dựng nhiều hệ thống thương mại trực tuyến khác trong tương
lai chứ không đơn thuần gói gọn trong ứng dụng đã trình bày. Công nghệ J2ME và
công nghệ Web Service đều là những công nghệ có tiềm năng to lớn, đặc biệt Web
Service là một công nghệ mới và được chuẩn hoá nên hứa hẹn sẽ vượt qua những
rào cản của các mô hình trước đây. Các ứng dụng thương mại dựa trên Web Service
sẽ có thể hoạt động tốt trong môi trường firewall và không bị rào cản do sự khác
nhau về dữ liệu, cấu trúc của các hệ thống khác nhau. Các nhà phát triển đánh giá
lãnh vực thương mại điện tử trên môi trường thiết bị di động sẽ phát triển rất nhanh
chóng, là ngành công nghiệp sẽ đem lại nhiều tỉ đô la doanh thu. Sự ra đời của Web
Service đã khiến việc xây dựng những ứng dụng thương mại tiến thêm một bước
quan trọng. Một yếu tố quan trọng trong các ứng dụng thương mại điện tử là quá
trình chi trả trực tuyến, chúng ta sẽ thực hiện giao dịch qua một bên trung gian được
gọi là "payment gateway", người đọc có thể tìm hiểu thêm về khái niệm này trên
www.google.com hay www.secpay.com .
Việt Nam là một nước có tỉ lệ người sử dụng điện thoại di động khá cao tuy
nhiên lãnh vực thương mại điện tử lại chưa phát triển. Thói quen giao dịch trực
tuyến chưa được hình thành trong đại đa số người dân. Tuy nhiên, với sự phát triển
nhanh chóng của ngành phần mềm cho thiết bị di động và web service, chúng tôi hy
vọng tương lai sẽ có thêm nhiều ứng dụng phục vụ cho đời sống như mua vé tàu
hoả, máy bay, đặt chỗ khách sạn, xem chỉ số chứng khoán, dự báo thời tiết… qua

208
Java Mobile

môi trường di động. Chúng tôi mong muốn được góp sức cho sự phát triển của lãnh
vực thương mại điện tử qua môi trường di động tại Việt Nam.

209
Java Mobile

Tài liệu tham khảo

Books:
1. Bruce Eckel, Thinking in Java 3rd, Prentice Hall, New Jersey, 1998
2. David Chappell - Tyler Jewell, Java Web Services, O'Reilley, 2002
3. Dreamtech Software Team, Cracking the Code™ , Hungry Minds, 2002
4. James White-David Hemphill, Java in small things, Manning, 2002
5. John W. Muchow, Core J2ME™ Technology & MIDP, Prentice Hall, 2001
6. Kim Topey, J2ME™ in a Nutshell, O’Reilley, 2002
7. Kim Topey,Java Web Service in A Nutshell, O'Reilley, 2003
8. Michael Juntao Yuan, Enterprise J2ME™: Developing Mobile Java
Application, Prentice Hall PTR, 2003
9. MSDN Training, Developing XML Web Services using Microsoft Visual
C#, Microsoft, 2001
10. Roger Riggs, Programming Wireless Devices with the Java™ 2 Platform
Micro Edition, Addision Wesley, 2003
11. Vartan Piroumian, Wireless J2ME™ Platform Programming, Prentice Hall
PTR, 2002
Web Sites:
1. http://java.sun.com: Trang chủ Sun Java
2. http://javavietnam.org: Diễn đàn Java Việt Nam
3. http://jcp.org: Trang chủ tổ chức Java Community Process
4. http://msdn.microsoft.com: Trang tài liệu MSDN online
5. http://www.forum.nokia.com: Forum của Hãng Nokia, nơi có nhiều tài liệu
cho nhà phát triển.

210
Java Mobile

Phụ Lục A: Hướng dẫn sử dụng công cụ Sun


Wireless ToolKit 2.3

Wireless ToolKit là bộ công cụ giả lập thiết bị di động. Wireless ToolKit cung
cấp các chức năng thuận lợi cho nhà phát triển J2ME như biên dịch các file mã
nguồn, tự phát sinh file JAD và file JAR, giả lập các thiết bị di động với các chức
năng phong phú…

Hình A.1 Công cụ Sun WirelessToolkit 2.3

Để vào màn hình ứng dụng chính của Wireless ToolKit ta sử dụng chức năng
KToolBar. Để tạo một chương trình ứng dụng mới, ta chọn chức năng New Project

211
Java Mobile

Hình A.2 Màn hình chính của công cụ

Sau đó chương trình sẽ yêu cầu chúng ta nhập tên Project và tên của lớp ứng dụng
MIDLet (bao gồm cả tên Package).

Hình A.3 Tạo project mới

Lúc này Wireless ToolKit sẽ tạo một thư mục có tên theo Project Name ta vừa nhập
(J2ME Project) trong thư mục apps của thư mục gốc cài đặt wireless toolkit. Giả sử
ta cài đặt wireless toolkit vào thư mục C:\WTK thì chương trình sẽ tạo thư mục
C:\WTK\apps\J2ME Project\ sau những bước vừa làm như trên.

Sau đó Wireless ToolKit sẽ cung cấp một màn hình tùy chọn

212
Java Mobile

Hình A.4 Các options cho project

Chúng ta sẽ chọn các thư viện mở rộng cần Wireless ToolKit hỗ trợ đối với Project
vừa tạo. Ứng với ứng dụng "Đăng Ký Học Phần" trong luận văn, chúng ta sẽ chọn
Cofiguration sử dụng là CLDC 1.1, check chọn các thư viện JSR 172 (Web Service)
và JSR 177 (hỗ trợ mật mã hóa dữ liệu).

(Ta có thể chọn mục Project/Setting để trở lại màn hình này bất kỳ lúc nào).
Sau đó ta chọn Tab MIDlets

213
Java Mobile

Hình A.5 Chỉnh sửa nội dung file Jad và Jar

Đây là những thuộc tính cực kỳ quan trọng đối với ứng dụng và sẽ được đóng gói
trong file JAD cũng như file manifest của file JAR. (Ý nghĩa các thuộc tính đã được
trình bày rất kỹ ở phần 2.2.4 MIDlet Suite trong báo cáo luận văn).
Trong gói ứng dụng của ta, có thể có nhiều MIDlet và mỗi MIDlet phải được khai
báo chính xác các thuộc tính trong phần này. Đặc biệt phải chú ý đến thuộc tính
Class, ta phải khai báo đúng tên lớp của MIDlet nếu không sẽ phát sinh lỗi trong
quá trình biên dịch.

214
Java Mobile

Sau đó ta có thể dùng các chương trình quản lý file thông dụng để chép các file mã
nguồn của ứng dụng vào thư mục C:\WTK\apps\J2ME Project\ vừa được tạo ra.
Nếu các file mã nguồn nằm trong các package thì ta phải tạo các thư mục con ứng
với các package và đưa các file mã nguồn vào đúng chính xác các thư mục con
tương ứng. Giả sử như trên ta phải tạo thư mục MyPackage trong thư mục
C:\WTK\apps\J2ME Project\ và chép các tập tin mã nguồn vào thư mục MyPackage
vừa tạo đó. Điều này khá quen thuộc với những người dùng đã từng sử dụng ngôn
ngữ Java trước đây.
Ta cần lưu ý, công cụ Wireless Toolkit không phải là bộ công cụ hỗ trợ biên soạn
mã nguồn mà chỉ có chức năng biên dịch, thực thi và đóng gói ứng dụng. Để hỗ trợ
việc soạn thảo mã nguồn chúng ta có thể sử dụng Jbuilder hoặc các chương trình
tương đương.
Biên dịch chương trình

Hình A.6 Biên dich project

Ta dùng tính năng Build để biên dịch các file mã nguồn, nếu không có lỗi
phát sinh ta có thể sử dụng tính năng Run để thực thi chương trình.
Cấu trúc thư mục Project:
Với mỗi Project được tạo ra đều có những thư mục con như sau:
Bin: Chứa file JAD và file JAR sau khi đã được đóng gói.

215
Java Mobile

Classes: Chứa file mã nguồn được biên dịch thành dạng .class
Lib: Chứa các thư viện cộng thêm của Project.
Res: Chứa các file resource như file hình dạng .png của project.
Src: Chứa các file mã nguồn chưa biên dịch dạng .java
Tmpclasses và Tmplib: Các thư mục tạm của wireless toolkit, chúng ta thường
không dùng đến.
Tạo file JAD và file JAR:

Hình A.7 Đóng gói ứng dụng

Ta chọn chức năng Create Package có sẵn trong tab project để phát sinh các file
JAR và file JAD để có thể đưa vào thiết bị thật để sử dụng.

216
Java Mobile

Phụ Lục B: Xây dựng và Sử dụng Web Service


Xây dựng Web Service bằng Microsoft Studio .NET:
Việc xây dựng một web service trong môi trương Visual Studio .Net rất dễ dàng,
chúng ta chỉ cần tạo mới một project ASP.NET (có thể bằng ngôn ngữ C# hoặc
VB.NET)

Hình B.1 Tạo project Web Service


Sau đó ta khai báo một lớp mới để chứa service, lớp này kế thừa từ lớp
System.Web.Services.WebService.
Trong lớp vừa tạo của chúng ta, những hàm nào có nhu cầu export để gọi từ xa
chúng ta khai báo thêm cụm từ [Web Method], lúc này Studio sẽ giúp chúng ta biên
dịch mọi thứ để hình thành một Web Service tương ứng.

217
Java Mobile

Hình B.2 Khai báo lớp và hàm


Trong ví dụ trên chúng ta đã xây dựng lớp Service1 và trong lớp này hàm
HelloWorld() được khai báo là hàm được phép gọi từ xa qua cụm từ “[Web
Method]”, phần còn lại là trách nhiệm của Visual Studio.
Với những đồ án cần export nhiều hàm vào service, trước mỗi hàm cần cho phép
truy cập từ xa ta sẽ thêm định nghĩa WebMethod vào trước mỗi hàm. Ngoài ra
.NET còn cho phép ta định nghĩa nhiều thuộc tính (properties) để tăng thêm tùy
biến cho các hàm service. Thuộc tính quan trọng nhất cần chú ý là EnableSession,
khi khai báo EnableSession=true, trong hàm sẽ cho phép ta sử dụng đối tượng
Session để lưu và truy vấn các biến session.

218
Java Mobile

Hình B.3 Export nhiều hàm cùng lúc


Thực thi Web Service.

Hình B.4 Màn hình thực thi Web Service của IE

Khi chúng ta đưa project này vào IIS và Run ta sẽ nhận được trang tóm tắt các
thông tin về web service, trang này sẽ gồm các hàm được export trong service của
chúng ta và mục Service Description sẽ cung cấp file WSDL cho Web service
tương ứng.
Khi ta click vào phần Service Description, IIS sẽ cung cấp nội dung file WSDL.
File WSDL này sẽ được dùng để xây dựng các lớp giúp truy xuất Web Service vừa
xây dựng (sẽ được trình bày ở phần truy xuất web service bằng J2ME).

219
Java Mobile

Hình B.5 File WSDL


Ta sẽ dùng chức năng Save As… của Web Browser để lưu nội dung file này lại
với phần mở rộng là .wsdl. Nội dung file này rất quan trọng và sẽ được dùng ở phần
sau để truy xuất web service.

Dùng J2ME truy xuất Web Service:


Để truy xuất được web service, chúng ta phải dùng chức năng stub generator của bộ
công cụ wireless toolkit 2.3

220
Java Mobile

Hình B.6 Công cụ Stub Generator


Khi chọn chức năng stub generator, màn hình chức năng sẽ xuất hiện

Hình B.7 Các options của công cụ Stub Generator


Ta chọn đường dẫn đến file WSDL có được, phần Output Package ta sẽ nhập
tên Package cho các lớp được tự động phát sinh.
Các lớp phát sinh này sẽ được đặt ở thư mục output path, ở đây cũng chính là
thư mục source của project. Trong các lớp phát sinh, lớp quan trọng nhất là lớp
<PackageName>Soap_Stub.java (trong trường hợp này là lớp
DKHPServiceSoap_Stub.java). Lớp này có chứa tất cả các hàm mà web service
cung cấp (tương ứng 1-1), để gọi hàm của web service ta chỉ cần tạo một đối tượng
của lớp này và dùng hàm do đối tượng đó cung cấp.

221
Java Mobile

Phụ Lục C: Giới thiệu các thư viện JSR


Như đã đề cập, Java là ngôn ngữ phát triển rất nhanh chóng. Sự phát triển
của ngôn ngữ Java, đặc biệt là J2ME, là nhờ công sức đóng góp của cộng đồng các
nhà phát triển phần mềm. Java Community Process (JCP – http://www.jcp.org/) là
một chương trình do hãng Sun đề ra nhằm tập hợp ý kiến của các nhà phát triển
khắp nơi để đóng góp cho ngôn ngữ Java. Tổ chức này liên tục đề ra những yêu cầu,
những đặc tả mới cho ngôn ngữ Java, trong đó có J2ME, dưới dạng các Java
Specification Requests (JSR – xxx với xxx là ký số của đặc tả). Các đặc tả này ra
đời rất nhanh chóng và dần trở thành yêu cầu bắt buộc đối với những nhà sản xuất
nếu muốn cạnh tranh với các đối thủ; việc ra đời của các đặc tả này đã tăng thêm
sức mạnh cho ngôn ngữ Java nói chung và dòng ngôn ngữ J2ME nói riêng vốn ban
đầu chỉ nhắm đến các thiết bị nhỏ, ít chức năng.
Trong số các đặc tả cho dòng ngôn ngữ J2ME thì một số đặc tả sau là quan
trọng nhất:
- Connected Limited Device Configuration (CLDC); JSR 30, JSR 139
- Mobile Information Device Profile (MIDP); JSR 37, JSR 118
- Java Technology for the Wireless Industry, (JTWI); JSR 185
- Wireless Messaging API (WMA); JSR 120, JSR 205
- Mobile Media API (MMAPI); JSR 135
- Location API for J2ME; JSR 179
- Security and Trust Services API for J2ME, (SATSA); JSR-177
- Mobile 3D Graphics; JSR-184
- J2ME Web Services APIs, (WSA); JSR 172
- Bluetooth API (JSR-82, Motorola, Java Partner Site)
- J2ME Content Handler API, (CHAPI); JSR 211
Để tìm hiểu về JSR bạn có thể vào trang web
http://www.jcp.org/en/jsr/detail?id=xxx với xxx là mã hiệu của JSR (172,177,…)

222

You might also like