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

J2ME 進度條與線程模型進階:可取消任務的低耦合實現

     編輯:J2ME

前言:為什麼需要重寫進度條框架?

舊模型中,後台任務 BackgroundTask 輪詢前台 ProgressGaugeUI 的 isStopped() 標誌來決定是否退出。缺陷顯而易見:

  • 阻塞不可中斷:任務陷入 Thread.sleep()、網絡 I/O、RMS 讀寫時,無法檢查標誌,用戶點「取消」無響應,體感死鎖。
  • 輪詢頻率難把控:太頻繁浪費 CPU,太稀疏延遲響應;代碼散落業務邏輯中,污染可讀性。
  • 單向耦合:後台依賴前台接口,難以複用於無 UI 場景(如後台同步)。

本文引入 回調 + 接口隔離,實現「前台強制中斷後台、雙向解耦」。

一、 核心接口設計

// 1. 可取消契約:後台實現,前台調用
public interface Cancelable {
    /** 非阻塞、幂等、立即返回;內部通常 interrupt() 或 close() 資源 */
    void cancel();
}

// 2. 進度觀察者:前台實現,後台推送進度
public interface ProgressObserver {
    void reset();
    void setMax();
    void show(Display display);
    void exit();
    void updateProgress(Object param); // 進度值或提示文本
    boolean isStoppable(); void setStoppable(boolean b);
    boolean isStopped(); void setStopped(boolean b);
    void setTitle(String t); void setPrompt(String p);
    /** 關鍵:注入可取消對象,建立回調鏈 */
    void setCancelableObject(Cancelable co);
}

二、 前台實現:ProgressGaugeUI

  • 基於 Form + Gauge(INDEFINITE/INCREMENTAL) + Command.STOP。
  • commandAction() 捕獲用戶點擊「取消」 → setStopped(true) → cancelableObject.cancel() 回調後台。
  • 單例模式 getInstance() 保證全進程唯一進度條,節省內存。

三、 後台抽象類:BackgroundTask

public abstract class BackgroundTask extends Thread implements Cancelable {
    protected ProgressObserver poUI;
    protected Displayable preScreen; // 任務前界面
    protected Alert alertScreen;     // 取消/異常提示
    protected boolean needAlert;

    public BackgroundTask(ProgressObserver poUI, Displayable pre, Display display) { ... }

    public final void run() {
        boolean taskComplete = false;
        try {
            taskComplete = runTask(); // 子類實現具體業務
        } catch (Exception e) { showErrorAlert(e); }
        finally {
            // 任務結束統一處理
            if (!taskComplete && poUI.isStoppable() && poUI.isStopped()) {
                display.setCurrent(needAlert ? alertScreen : preScreen, preScreen);
            }
            poUI.exit();
        }
    }

    /** 子類必須實現:返回 true=成功跳轉、false=失敗/取消 */
    protected abstract boolean runTask();

    /** 取消回調:默認 interrupt(),子類可覆寫 close 流/連接 */
    public void cancel() { this.interrupt(); }

    /** 靜態啟動器:一鍵綁定 UI、註冊回調、啟動線程 */
    public static void runWithProgressGauge(BackgroundTask task, String title,
                                            String prompt, boolean stoppable, Display display) { ... }
}

四、 實戰:可中斷的 6 秒模擬任務

BackgroundTask bkTask = new BackgroundTask(poUI, currentScreen, display) {
    public boolean runTask() {
        poUI.updateProgress("Sleep 3s...");
        try { Thread.sleep(3000); } catch (InterruptedException e) { return false; } // 捕獲中斷,快速退出

        poUI.updateProgress("Sleep another 3s...");
        try { Thread.sleep(3000); } catch (InterruptedException e) { return false; }

        poUI.setMax();
        display.setCurrent(new Form("Complete")); // 成功跳轉
        return true;
    }

    @Override public void cancel() {
        // 針對性中斷:關閉 HttpConnection、InputStream 等
        this.interrupt(); 
    }
};
BackgroundTask.runWithProgressGauge(bkTask, "Long Task", "Working...", true, display);

五、 關鍵點總結

痛點舊模型新模型
阻塞操作可取消性依賴輪詢,不可靠interrupt() / close() 強制拋異常,catch 即退出
耦合度後台依賴前台具體類雙方依賴接口 Cancelable/ProgressObserver
代碼侵入性業務邏輯混雜 if (poUI.isStopped())僅在阻塞點 catch (InterruptedException),業務碼純淨
複用性綁定特定 UI任意實現 ProgressObserver 的 Canvas/Form/自定義組件均可

六、 最佳實踐清單

  1. 所有阻塞調用必須聲明拋出 InterruptedException,或自行檢查 Thread.interrupted()。
  2. 資源關閉要在 cancel() 中完成:conn.close()、is.close()、recordStore.close(),觸發底層 I/O 異常打斷阻塞。
  3. UI 線程與後台線程嚴格分離:updateProgress() 必須線程安全(JXL 內部已同步),避免直接在後台操作 LCDUI 組件。
  4. 幂等取消:cancel() 多次調用無副作用,ProgressObserver.setStopped(true) 守衛重複回調。

七、 總結

通過 Cancelable 接口反向注入,將「用戶意圖」即時傳遞給「執行引擎」,徹底解決了 J2ME 單線程阻塞模型下的取消難題。此模式不僅適用於進度條,同樣可推廣至下載管理器、數據同步、圖片加載等所有長耗時異步場景,是 J2ME 併發編程的基石範式。

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