| 維度 | JSR 172 (標準) | kSOAP (第三方) |
|---|---|---|
| 標準化 | JCP 標準規範 | 開源庫,非標準 |
| 工具支持 | WTK 內建 Stub Generator | 手動編寫 SOAP 請求/解析響應 |
| .NET 兼容性 | 優秀 (WSDL 標準互操作) | 需手動處理命名空間、數組、DataSet 等 .NET 特有類型 |
| 代碼體積 | 生成 Stub 較大 | 核心庫較小 (~30KB) |
| 維護性 | WSDL 變更重新生成即可 | 手動維護映射代碼 |
結論:優先使用 **JSR 172**,僅在設備不支持 JSR 172 (極舊機型) 或 JAR 體積極其敏感時考慮 kSOAP。
kXML-min.zip、ksoap-midp.zip (Stub 運行時依賴)
[WebService(Namespace = "https://tempuri.org/")]
public class MyServices : WebService {
[WebMethod(Description = "User Login")]
public bool Login(string sLoginUserID, string sLoginPwd) {
if (string.IsNullOrEmpty(sLoginUserID)) return false;
string connStr = "Server=.;Database=TestDB;Uid=sa;Pwd=123;";
using (SqlConnection conn = new SqlConnection(connStr)) {
string sql = "SELECT Pwd FROM Users WHERE UserID = @UserID";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@UserID", sLoginUserID);
conn.Open();
object result = cmd.ExecuteScalar();
if (result == null) return false;
return result.ToString() == sLoginPwd;
}
}
}
部署至 IIS,驗證 https://server/MyServices.asmx?wsdl 可訪問。
https://192.168.10.101/Service/MyServices.asmx?wsdl (必須帶 ?wsdl)src 目錄helloworld.ws (對應 src/helloworld/ws/)MyServices_Stub.java、MyServices_Soap_Stub.java 等文件
package helloworld;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import helloworld.ws.*; // 生成的 Stub 包
public class LoginMIDlet extends MIDlet implements CommandListener {
private Display display;
private Form loginForm;
private TextField txtUser, txtPwd;
private Command cmdLogin, cmdExit;
private MyServices_Soap_Stub service; // 核心:生成的 SOAP Stub
protected void startApp() throws MIDletStateChangeException {
display = Display.getDisplay(this);
loginForm = new Form("Login");
txtUser = new TextField("UserID:", "", 20, TextField.ANY);
txtPwd = new TextField("Password:", "", 20, TextField.PASSWORD);
cmdLogin = new Command("Login", Command.OK, 1);
cmdExit = new Command("Exit", Command.EXIT, 1);
loginForm.append(txtUser);
loginForm.append(txtPwd);
loginForm.addCommand(cmdLogin);
loginForm.addCommand(cmdExit);
loginForm.setCommandListener(this);
display.setCurrent(loginForm);
// 初始化 Service Stub
service = new MyServices_Soap_Stub();
service._setProperty(MyServices_Soap_Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
}
public void commandAction(Command c, Displayable d) {
if (c == cmdLogin) {
doLogin();
} else if (c == cmdExit) {
destroyApp(false);
notifyDestroyed();
}
}
private void doLogin() {
final String user = txtUser.getString();
final String pwd = txtPwd.getString();
if (user.length() == 0 || pwd.length() == 0) {
showAlert("Error", "Please input user/pwd");
return;
}
// 必須在新線程中調用,避免阻塞 UI 線程導致系統假死
new Thread() {
public void run() {
try {
boolean result = service.login(user, pwd); // 同步調用
if (result) {
// 登入成功,切換到主界面 (需在 UI 線程操作)
display.callSerially(new Runnable() {
public void run() {
display.setCurrent(mainForm); // 假設有主界面
}
});
} else {
showAlert("Login Failed", "Invalid user or password");
}
} catch (Exception e) {
e.printStackTrace();
showAlert("Connection Error", "Check network/proxy settings");
}
}
}.start();
}
private void showAlert(final String title, final String msg) {
display.callSerially(new Runnable() {
public void run() {
Alert a = new Alert(title, msg, null, AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
display.setCurrent(a, loginForm);
}
});
}
protected void pauseApp() {}
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {}
}
| 技術點 | 說明 |
|---|---|
_setProperty(SESSION_MAINTAIN_PROPERTY, Boolean.TRUE) | 啟用 HTTP Session 保持,支持 .NET 服務端 Session 狀態 |
新線程調用 service.login() | 網絡調用阻塞,必須離開 UI 線程,否則屏幕凍結、甚至系統看門狗重啟 |
display.callSerially(Runnable) | 網絡線程完成後,安全地在 UI 線程更新界面 (MIDP 2.0 標準) |
| 異常處理 | 捕獲 RemoteException、IOException、XMLParserException 等,友好提示用戶 |