Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 59 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
59
Dung lượng
0,97 MB
Nội dung
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 openRecordStore(String recordStoreName, boolean createIfNeccessary) Mở một record store, tùy chọn tạo mới nếu record store chưa tồn tại. void closeRecordStore() Đóng record store static void deleteRecordStore(String rcdStoreName) Xóa record store static String[] listRecordStore() Liệt kê các record stores trong MIDlet Suite int addRecord(byte[] data, int offset, int numBytes) Thêm một record void setRecord(int recordID,byte[] newData,int offset, int numBytes) Thay đổi nội dung một record. 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[] buffer, int offset) Lấy nội dung record từ vị trí offset đưa 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 (RecordFilter filter, RecordComparator comparator, boolean keepUpdate) Bổ sung chức năng duyệt các record dưới dạng một tập hợp. (sẽ được đề cập sau) void addRecordListener(RecordListener listener) Thêm một bộ lắng nghe trên Record Store (sẽ được đề cập sau) void removeRecordListener (RecordListener listener) Gỡ bỏ bộ nghe (sẽ được đề cập sau) 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 keepUpdate) Bật, tắt chế độ tự cập nhật của enum boolean isKeptUpdate() Kiểm tra xem enum có chức năng tự cập nhật hay không? 116 [...]... 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");... RecordStoreNotFoundOpen(String message) 1 23 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... 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... 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... 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... 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... 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... 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... 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... //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/CLDC1.0"); / /3) Gửi dữ liệu, vì dùng Get nên không có phần body – data . 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. 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. 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ể