import android.os.Handler; import android.os.Looper; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; /** * UI线程执行代码工具类 *

* 提供在工作线程同步执行主线程任务的能力,调用线程会阻塞直到任务完成。 * 适用于需要在工作线程中获取主线程操作结果的场景。 *

*/ public final class UiThreadSync { private static final Handler MAIN = new Handler(Looper.getMainLooper()); private static final long DEFAULT_TIMEOUT_MS = 5000; // 默认超时时间5秒 private UiThreadSync() { // 工具类,防止实例化 } /** * 在工作线程同步执行主线程任务 *

* 如果调用线程已经是主线程,则直接执行任务;否则会将任务投递到主线程并等待执行完成。 * 注意:任务中不应包含需要消息队列的其他异步操作,以免导致死锁。 *

* * @param r 要执行的任务 * @throws RuntimeException 如果任务执行抛出异常、等待时被中断或超时 */ public static void runCode(Runnable r) { runCode(r, DEFAULT_TIMEOUT_MS); } /** * 在工作线程同步执行主线程任务(带超时控制) *

* 如果调用线程已经是主线程,则直接执行任务;否则会将任务投递到主线程并等待执行完成。 *

* * @param r 要执行的任务 * @param timeoutMs 超时时间(毫秒),0表示无限等待 * @throws RuntimeException 如果任务执行抛出异常、等待时被中断或超时 * @throws IllegalArgumentException 如果timeoutMs为负数 */ public static void runCode(Runnable r, long timeoutMs) { if (r == null) { throw new NullPointerException("Runnable cannot be null"); } if (timeoutMs < 0) { throw new IllegalArgumentException("Timeout cannot be negative: " + timeoutMs); } // 如果已经在主线程,直接执行(不抛异常) if (Looper.myLooper() == Looper.getMainLooper()) { r.run(); return; } final CountDownLatch latch = new CountDownLatch(1); final AtomicReference error = new AtomicReference<>(); // 提交任务到主线程 MAIN.post(() -> { try { r.run(); } catch (Throwable t) { error.set(t); } finally { latch.countDown(); } }); try { boolean completed; if (timeoutMs > 0) { completed = latch.await(timeoutMs, TimeUnit.MILLISECONDS); if (!completed) { // 超时:清理未执行的任务 MAIN.removeCallbacksAndMessages(null); throw new RuntimeException("Timeout waiting for UI thread after " + timeoutMs + "ms"); } } else { latch.await(); // 无限等待 completed = true; } if (completed) { Throwable t = error.get(); if (t != null) { rethrowThrowable(t); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 中断:清理未执行的任务 MAIN.removeCallbacksAndMessages(null); throw new RuntimeException("Thread interrupted while waiting for UI thread", e); } } /** * 重新抛出异常,保持原始异常类型 */ private static void rethrowThrowable(Throwable t) { if (t instanceof RuntimeException) { throw (RuntimeException) t; } else if (t instanceof Error) { throw (Error) t; } else { throw new RuntimeException("Exception in UI thread", t); } } /** * 检查当前是否在主线程 */ public static boolean isMainThread() { return Looper.myLooper() == Looper.getMainLooper(); } }