J2ME 網路存取核心為 javax.microedition.io 套件定義的 **Generic Connection Framework (GCF)**,採用工廠模式統一建立連線:
Connection conn = Connector.open("https://example.com/api");
協定由 URL Scheme 決定:http:, https:, socket:, datagram:, ssl:, comm: 等。
Connection (介面)
├─ StreamConnection // 雙向串流 (InputStream + OutputStream)
│ ├─ ContentConnection // 含長度/型別/編碼資訊 (getLength, getType, getEncoding)
│ └─ HttpConnection // HTTP 專用 (GET/POST/HEAD, 標頭操作, 狀態碼)
├─ DatagramConnection // UDP 資料包
└─ ... (其他)
StreamConnection, DatagramConnectionHttpConnection (含 ContentConnection)
HttpConnection conn = null;
InputStream is = null;
try {
conn = (HttpConnection) Connector.open("https://example.com/data.txt");
conn.setRequestMethod(HttpConnection.GET);
int rc = conn.getResponseCode();
if (rc == HttpConnection.HTTP_OK) {
is = conn.openInputStream();
// 讀取資料...
} else {
// 處理錯誤碼
}
} finally {
if (is != null) try { is.close(); } catch (Exception ignore) {}
if (conn != null) try { conn.close(); } catch (Exception ignore) {}
}
HttpConnection conn = (HttpConnection) Connector.open(url);
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setRequestProperty("Content-Length", String.valueOf(body.length()));
OutputStream os = conn.openOutputStream();
os.write(body.getBytes("UTF-8"));
os.flush();
// 讀取回應...
ContentConnection cconn = (ContentConnection) Connector.open(url);
long len = cconn.getLength(); // -1 表示未知 (Chunked 或動態生成)
if (len > 0 && len < MAX_BUFFER) {
byte[] buf = new byte[(int) len];
DataInputStream dis = cconn.openDataInputStream();
dis.readFully(buf);
// 處理完整資料
}
// 請求標頭
conn.setRequestProperty("User-Agent", "MyMIDlet/1.0");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Cookie", cookieManager.getCookieHeader(url));
// 回應標頭
String contentType = conn.getHeaderField("Content-Type");
String setCookie = conn.getHeaderField("Set-Cookie");
Date expires = new Date(conn.getHeaderFieldDate("Expires", 0));
先前範例使用 dbAddress.addAddress() 手動填入測試資料。
// AddressDB 建構子中
StreamConnection conn = null;
InputStream in = null;
try {
conn = (StreamConnection) Connector.open("https://server/addressbook.txt");
in = conn.openInputStream();
byte[] buf = new byte[256]; // StreamConnection 無 getLength,需固定緩衝區
int count = in.read(buf);
String content = new String(buf, 0, count).trim();
// 解析:每行 "姓名,電話"
StringTokenizer st = new StringTokenizer(content, "\n");
while (st.hasMoreTokens()) {
String line = st.nextToken();
int comma = line.indexOf(',');
if (comma > 0) {
String name = line.substring(0, comma);
String phone = line.substring(comma + 1);
addAddress(name, phone); // 原有 RMS 寫入方法
}
}
} catch (IOException e) {
// 錯誤處理...
} finally {
// 關閉資源...
}
ContentConnection cconn = (ContentConnection) Connector.open(url);
long len = cconn.getLength();
if (len > 0) {
byte[] buf = new byte[(int) len];
DataInputStream dis = cconn.openDataInputStream();
dis.readFully(buf);
// 解析...
}
注意:J2ME 缺少 java.util.StringTokenizer,需自行實作或使用第三方實作 (如 kxml 附屬工具類)。
| 面向 | 建議 |
|---|---|
| 執行緒 | 所有網路操作**必須在背景執行緒**進行,避免阻塞 UI 執行緒導致裝置當機 |
| 逾時設定 | J2ME 無標準 API 設定逾時,需自行實作監視執行緒或使用廠商擴充 API |
| 例外處理 | 區分 ConnectionNotFoundException (網路/URL錯誤)、IOException (傳輸錯誤)、SecurityException (權限不足) |
| 資料壓縮 | 伺服端啟用 GZIP,客戶端支援 Accept-Encoding: gzip (需手動解壓) |
| 安全性 | 生產環境強制 HTTPS,驗證伺服器憑證 (MIDP 2.0 支援 HTTPS) |
| 離線支援 | 失敗時回退本地 RMS 快取,提供離線唯讀模式 |