首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 通用聯網框架(GCF)實戰:HttpConnection 完整流程與多執行緒架構設計

     編輯:J2ME

GCF 架構核心:Connector.open()

J2ME 通用聯網框架 (Generic Connection Framework, GCF) 以 javax.microedition.io.Connector 為唯一入口,透過協議字串動態建立連線:


// HTTP 連線
HttpConnection http = (HttpConnection) Connector.open("https://example.com/api");

// Socket 連線 (MIDP 2.0 選配)
SocketConnection socket = (SocketConnection) Connector.open("socket://host:port");

// Datagram (UDP) 連線 (MIDP 2.0 選配)
DatagramConnection dgram = (DatagramConnection) Connector.open("datagram://:port");

HTTP POST 標準實作範本 (取自 MIDP API 文檔)

void postViaHttpConnection(String url) throws IOException {
    HttpConnection conn = null;
    InputStream is = null;
    OutputStream os = null;
    try {
        conn = (HttpConnection) Connector.open(url);
        
        // 1. 設定請求屬性
        conn.setRequestMethod(HttpConnection.POST);
        conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.1");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Accept", "text/plain");
        
        // 2. 發送請求體
        os = conn.openOutputStream();
        String payload = "action=login&user=test&pass=1234";
        os.write(payload.getBytes("UTF-8")); // 明確指定編碼
        os.flush();
        
        // 3. 取得回應碼 (觸發實際連線與請求發送)
        int rc = conn.getResponseCode();
        if (rc != HttpConnection.HTTP_OK) {
            throw new IOException("HTTP Error: " + rc);
        }
        
        // 4. 處理回應
        is = conn.openInputStream();
        String type = conn.getType(); // Content-Type
        int len = (int) conn.getLength();
        
        if (len > 0) {
            byte[] data = new byte[len];
            int read = 0, actual;
            while (read < len && (actual = is.read(data, read, len - read)) != -1) {
                read += actual;
            }
            processResponse(data);
        } else {
            // Chunked 或未知長度:流式讀取
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int n;
            while ((n = is.read(buf)) != -1) baos.write(buf, 0, n);
            processResponse(baos.toByteArray());
        }
    } catch (ClassCastException e) {
        throw new IllegalArgumentException("Non-HTTP URL");
    } finally {
        // 5. 關閉資源 (逆序關閉)
        if (is != null) try { is.close(); } catch (IOException ignored) {}
        if (os != null) try { os.close(); } catch (IOException ignored) {}
        if (conn != null) try { conn.close(); } catch (IOException ignored) {}
    }
}

關鍵架構原則:網絡操作必須在背景執行緒

鐵律:任何網絡 I/O (openConnection, read, write) 絕不可在事件分發執行緒 (EDT) 執行,否則 UI 凍結、甚至被 AMS 強制終止。

標準多執行緒模式

public class NetworkTask implements Runnable {
    private final String url;
    private final byte[] payload;
    private final NetworkListener listener;
    private final Display display;
    private final Displayable waitScreen; // 等待動畫畫面

    public NetworkTask(String url, byte[] payload, NetworkListener listener, 
                       Display display, Displayable waitScreen) {
        this.url = url;
        this.payload = payload;
        this.listener = listener;
        this.display = display;
        this.waitScreen = waitScreen;
    }

    public void run() {
        // 1. 顯示等待畫面 (需在 EDT 執行)
        display.callSerially(() -> display.setCurrent(waitScreen));
        
        try {
            byte[] response = doPost(url, payload);
            // 2. 回調結果 (在 EDT 執行)
            display.callSerially(() -> listener.onSuccess(response));
        } catch (IOException e) {
            display.callSerially(() -> listener.onError(e));
        } finally {
            // 3. 恢復原畫面 (可選)
            // display.callSerially(() -> display.setCurrent(previousScreen));
        }
    }

    private byte[] doPost(String url, byte[] payload) throws IOException {
        // 上述 HttpConnection 實作...
        return responseBytes;
    }
}

interface NetworkListener {
    void onSuccess(byte[] data);
    void onError(IOException e);
}

啟動方式

// 在命令處理或遊戲邏輯中
new Thread(new NetworkTask(url, payload, listener, display, waitCanvas)).start();

資料序列化協定設計

客戶端與伺服器必須嚴格對應讀寫順序與類型:

// 客戶端發送
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("login");      // String
dos.writeInt(userId);       // int
dos.writeBoolean(true);     // boolean
dos.writeLong(timestamp);   // long
dos.flush();

// 伺服器接收 (順序、類型完全一致)
DataInputStream dis = new DataInputStream(is);
String action = dis.readUTF();
int userId = dis.readInt();
boolean flag = dis.readBoolean();
long ts = dis.readLong();

WAP 閘道透明轉發機制

手機 → WAP 閘道 (運營商) → Internet Web Server。閘道處理協議轉換 (WSP↔HTTP)、壓縮、快取。開發者無需關心閘道,但需注意:

  • 閘道可能壓縮/修改 Header,Content-Length 不可靠。
  • 閘道超時通常較短 (10-30s),長連線需心跳維持。
  • 部分閘道封鎖非標準 Port,HTTP/HTTPS 最安全。

錯誤處理與重試策略

MVC 架構整合建議

  • Model:資料實體、RMS 快取、網絡 DTO。
  • View:Canvas/Form 畫面、等待動畫、錯誤提示。
  • Controller:CommandListener、網絡任務調度、狀態機流轉。
  • 導航控制器持有 Display 參考,統一管理畫面切換與回退棧。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
錯誤類型處理策略
連線超時 / 拒絕指數退避重試 (1s, 2s, 4s...),最多 3 次,記錄離線隊列
HTTP 4xx客戶端錯誤 (參數/認證),提示用戶修正,不重試
HTTP 5xx伺服器錯誤,延遲重試,可切換備用 IP
IO 錯誤 (斷網)偵測網絡狀態變化 (JSR 172/205),恢復後自動重發隊列