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

Android 線程中更新 UI 卡頓優化:Handler sendMessageDelayed 頻率設置錯誤導致主線程阻塞

     編輯:程式設計綜合問答

現象:使用 Handler 定時更新 SeekBar,但 UI 其他元素凍結、響應極慢。

問題代碼

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        int pos = setProgress(); // 更新 SeekBar
        if (!mDragging && mBoundService.isPlaying()) {
            // 錯誤:100 - (pos % 1000) 極大概率為負數或極小值
            msg = obtainMessage(SHOW_PROGRESS);
            sendMessageDelayed(msg, 100 - (pos % 1000)); // 這裡!
        }
    }
};

根因:延遲計算錯誤導致高頻甚至立即重入

  • pos % 1000 範圍 0~999。
  • 100 - (pos % 1000) 範圍 -899 ~ 100。
  • 負數延遲視為 0,**導致消息泛洪、主線程循環處理 Message、UI 線程餓死**。

修正:目標約 1 秒更新一次

// 正確:1000 - (pos % 1000) → 下一個整秒邊界
sendMessageDelayed(msg, 1000 - (pos % 1000));

若 pos 為毫秒進度,則 pos % 1000 為當前秒內毫秒數,1000 - ... 為距離下一秒的毫秒數,實現「每秒整點更新」。

進階優化:移除冗余消息

// 發送前移除舊消息,避免重複排隊
mHandler.removeMessages(SHOW_PROGRESS);
mHandler.sendMessageDelayed(msg, 1000 - (pos % 1000));

現代替代:LiveData + 協程 / RxJava

// Kotlin 協程
lifecycleScope.launch {
    while (isPlaying) {
        val pos = boundService.currentPosition
        val delay = 1000 - (pos % 1000)
        delay(delay)
        _seekProgress.postValue(pos) // LiveData 觸發 UI 更新
    }
}

總結

一個減法符號錯誤(100 vs 1000)導致主線程消息風暴。**定時更新 UI 必須確保延遲 ≥ 16ms (理想 ≥ 200ms)**,並清理舊消息。

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