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

Android 主執行緒網路操作崩潰:Handler.post() 不等於子執行緒

     編輯:程式設計綜合問答

錯誤現象

在 Button 點擊事件中建立 Socket 連線,雖然包裝在 Runnable 並呼叫 handler.post(runnable),仍拋出 NetworkOnMainThreadException。

核心誤區

Handler handler = new Handler();
handler.post(runnable); // ❌ 仍在主執行緒 (UI Thread) 執行!

Handler.post() 只是將 Runnable 放入主執行緒的訊息佇列,待主執行緒空閒時執行。本質上仍在主執行緒,無法解決網路操作限制。

正確做法:真正的子執行緒

方案一:new Thread()(最基礎)

new Thread(runnable).start(); // ✅ 開啟新執行緒執行

方案二:ExecutorService / ThreadPool(推薦生產環境)

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(runnable); // 可復用執行緒、管理生命週期

方案三:Kotlin Coroutines / RxJava(現代框架)

// Kotlin
lifecycleScope.launch(Dispatchers.IO) {
    val socket = Socket("172.16.5.30", 8000)
    // ... 網路操作 ...
    withContext(Dispatchers.Main) {
        // 更新 UI
    }
}

UI 更新必須回主執行緒

在子執行緒中不可直接操作 View(如 editText.setText())。需切回主執行緒:

runOnUiThread(() -> editText.setText(msg));
// 或
handler.post(() -> editText.setText(msg));
// 或 Kotlin
withContext(Dispatchers.Main) { editText.setText(msg) }

完整修正範例

button.setOnClickListener(v -> {
    new Thread(() -> {
        try (Socket socket = new Socket("172.16.5.30", 8000);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
            
            String message = editText.getText().toString() + "\r\n";
            out.println(message);
            String response = in.readLine();
            
            runOnUiThread(() -> {
                if (response != null) editText.setText(response);
                else editText.setText("data error");
            });
        } catch (IOException e) {
            e.printStackTrace();
            runOnUiThread(() -> editText.setText("connection failed"));
        }
    }).start();
});

補充:Android 9+ 明文流量限制

若目標伺服器非 HTTPS,需在 AndroidManifest.xml <application> 加入 android:usesCleartextTraffic="true",或配置 network_security_config.xml。

總結

  • handler.post() ≠ 子執行緒,只是排程在主執行緒稍後執行。
  • 網路操作必須在 new Thread()、ExecutorService、Coroutine(Dispatchers.IO) 等真正背景執行緒執行。
  • 子執行緒完成後,務必用 runOnUiThread() 或 Handler(Looper.getMainLooper()) 更新 UI。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved