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

Android AsyncTask 取消執行:呼叫 cancel(true) 並配合 isCancelled 檢查

     編輯:程式設計綜合問答

場景

在 AsyncTask 執行耗時網路連線時,使用者點擊取消按鈕需中斷連線並停止後續邏輯。

核心 API

  • asyncTask.cancel(true):true 表示嘗試中斷執行緒(呼叫 Thread.interrupt())。
  • isCancelled():在 doInBackground 中定期檢查,若為 true 應提前返回。
  • onCancelled():取消完成後在 UI 執行緒回呼,替代 onPostExecute。

完整實作範例


private ConnectTask connectTask;

public void startConnect(View view) {
    connectTask = new ConnectTask();
    connectTask.execute(urlString);
}

public void cancelConnect(View view) {
    if (connectTask != null && connectTask.getStatus() == AsyncTask.Status.RUNNING) {
        connectTask.cancel(true); // 請求取消
    }
}

private class ConnectTask extends AsyncTask {
    private HttpURLConnection connection;

    @Override
    protected void onPreExecute() {
        // UI 提示「連線中...」
    }

    @Override
    protected String doInBackground(String... params) {
        try {
            URL url = new URL(params[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(10_000);
            connection.setReadTimeout(30_000);

            // 關鍵:連線前檢查取消
            if (isCancelled()) return null;

            connection.connect();

            // 關鍵:讀取資料流中定期檢查
            try (InputStream in = connection.getInputStream();
                 ByteArrayOutputStream out = new ByteArrayOutputStream()) {

                byte[] buffer = new byte[8192];
                int len;
                while ((len = in.read(buffer)) != -1) {
                    if (isCancelled()) return null; // 支援中途取消
                    out.write(buffer, 0, len);
                }
                return out.toString("UTF-8");
            }
        } catch (IOException e) {
            if (!isCancelled()) Log.e("ConnectTask", "IO Error", e);
            return null;
        } finally {
            if (connection != null) connection.disconnect();
        }
    }

    @Override
    protected void onPostExecute(String result) {
        if (result != null) {
            // 顯示結果
        }
    }

    @Override
    protected void onCancelled() {
        // UI 提示「已取消」
    }
}

關鍵注意事項

  1. isCancelled() **必須在耗時迴圈/阻塞點前檢查**,否則取消請求無法即時響應。
  2. cancel(true) 僅發送中斷信號,**無法強制停止原生 I/O 阻塞**(如 connection.connect()、in.read())。若需強制中斷網路,須在 onCancelled 或 finally 中呼叫 connection.disconnect() 關閉 Socket。
  3. Android 8.0+ AsyncTask 已棄用,新專案請改用 Coroutines + Retrofit/OkHttp、RxJava 或 ExecutorService + Future,取消語意更清晰(job.cancel()、disposable.dispose()、future.cancel(true))。

現代替代:Kotlin Coroutine


private var connectJob: Job? = null

fun startConnect() {
    connectJob = lifecycleScope.launch(Dispatchers.IO) {
        try {
            val result = downloadUrl(urlString) // 可掛起函式,支援協程取消
            withContext(Dispatchers.Main) { showResult(result) }
        } catch (e: CancellationException) {
            showCancelled() // 協程取消自動拋出
            throw e
        } catch (e: Exception) {
            showError(e)
        }
    }
}

fun cancelConnect() {
    connectJob?.cancel() // 一行搞定,包含子協程、網路呼叫皆可響應
}

掌握 cancel() + isCancelled() + disconnect() 三部曲,即可在 AsyncTask 時代優雅處理取消;長期請遷移至協程體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved