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

Android UI 卡頓排查:Service 同樣跑在主執行緒,耗時操作需再開 Thread

     編輯:程式設計綜合問答

現象

  • Button 點擊 → new Thread(sendable).start() → sendRemote() → startService(intent)。
  • 雖已另開 Thread,UI 仍明顯卡頓。

根因

startService() 呼叫後,Service 的 onCreate()/onStartCommand() 依然在主執行緒 (UI Thread) 執行。若 Service 內直接進行網路發送、加密、大量序列化等耗時工作,會阻塞主執行緒導致 UI 卡頓。

修正方案

方案一:Service 內再開 Thread/HandlerThread/IntentService

public class SendService extends Service {
    private HandlerThread workerThread;
    private Handler workerHandler;

    @Override public void onCreate() {
        super.onCreate();
        workerThread = new HandlerThread("SendWorker");
        workerThread.start();
        workerHandler = new Handler(workerThread.getLooper());
    }

    @Override public int onStartCommand(Intent intent, int flags, int startId) {
        workerHandler.post(() -> doSend(intent));
        return START_NOT_STICKY;
    }

    private void doSend(Intent intent) {
        String data = intent.getStringExtra("data");
        // 耗時網路操作...
        // 完成後可用 EventBus/廣播/ResultReceiver 通知 UI
    }

    @Override public void onDestroy() {
        workerThread.quitSafely();
        super.onDestroy();
    }
}

方案二:改用 IntentService (API 30 棄用) 或 JobIntentService / WorkManager

// WorkManager (現代推薦,支援約束、重試、系統優化)
OneTimeWorkRequest sendWork = new OneTimeWorkRequest.Builder(SendWorker.class)
    .setInputData(new Data.Builder().putString("data", data).build())
    .build();
WorkManager.getInstance(context).enqueue(sendWork);

// SendWorker extends CoroutineWorker (Kotlin) 或 ListenableWorker (Java)

方案三:若必須同步等待回應,用 ResultReceiver / CompletableFuture 跨程序回調

// Activity
ResultReceiver receiver = new ResultReceiver(new Handler()) {
    @Override protected void onReceiveResult(int code, Bundle data) {
        // UI 執行緒收到結果
    }
};
intent.putExtra("receiver", receiver);
startService(intent);

// Service
ResultReceiver receiver = intent.getParcelableExtra("receiver");
receiver.send(RESULT_OK, resultBundle);

核心觀念釐清

元件預設執行緒耗時操作處理
Activity/Fragment/ViewMain (UI)必須移至背景執行緒
ServiceMain (UI)必須移至背景執行緒
IntentServiceWorker Thread自動在背景,但已棄用
WorkManagerBackground Executor自動最佳調度,首選
BroadcastReceiverMain (UI)goAsync() 取得 10 秒背景時間

「另開 Thread 呼叫 startService」≠「耗時工作離開主執行緒」。Service 內部同樣需遵守「不阻塞主執行緒」原則。

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