Android Handler的runWithScissors手段

Handler的runWithScissors方法是隐藏API,用于执行同步任务(即让另一个线程执行一个任务,当前线程先阻塞,等待该执行完,之后当前线程再继续执行)。源码如下:

BlockingRunnable代码如下:

ok 源码就这些。 当前线程 wait(阻塞),等待handler所关联的线程执行完任务后唤醒当前线程。可以用于执行同步任务。timeOut为超时时间。

隐藏API不方便直接调用。把这段代码复制出来测试下, 测试代码如下:

package com.example.myapplication;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
public class Test {
    MyHandler handler;
    public void testRunWithScissors() {
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                Log.d("zx", "thread1 start , threadID:" + Thread.currentThread().getId());
                Looper.prepare();
                handler = new MyHandler(Looper.myLooper());
                Looper.loop();
            }
        };
        thread1.start();
        Thread thread2 = new Thread() {
            @Override
            public void run() {
                Log.d("zx", "thread2 start , threadID:" + Thread.currentThread().getId());
                // 线程2等待线程1执行一个任务, 执行完该任务后,线程2再做其他事。
                boolean res = handler.runWithScissors2(new Runnable() {
                    @Override
                    public void run() {
                        // 线程1中会执行这个任务
                        Log.d("zx", "current Thread, threadID:" + Thread.currentThread().getId()
                                + ", task start ...");
                        for (int i = 0; i < 5; i++) {
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            Log.i("zx", "i = " + i);
                        }
                        Log.i("zx", "task finish");
                    }
                }, 1000);
                Log.d("zx", "task finish, result: " + res + ", thread2 continue ...");
            }
        };
        try {
            Thread.sleep(10); // 防止线程1还没跑起来handler为空
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.start();
    }
    public static class MyHandler extends Handler {
        public MyHandler(Looper looper) {
            super(looper);
        }
        // 同步执行任务。 意思是,阻塞当前线程,等待另一个线程执行完该任务后,当前线程再继续执行. timeout为超时时间。 返回值表示任务执行是否成功
        public final boolean runWithScissors2(Runnable r, long timeout) { // 不能和隐藏api的方法同名,所以换了方法名。
            if (r == null) {
                throw new IllegalArgumentException("runnable must not be null");
            }
            if (timeout < 0) {
                throw new IllegalArgumentException("timeout must be non-negative");
            }
            if (Looper.myLooper() == getLooper()) { // 特殊情况,没有切换线程,就在当前线程执行。
                r.run();
                return true;
            }
            BlockingRunnable br = new BlockingRunnable(r);
            return br.postAndWait(this, timeout);
        }
        private static final class BlockingRunnable implements Runnable {
            private final Runnable mTask;
            private boolean mDone;
            public BlockingRunnable(Runnable task) {
                mTask = task;
            }
            @Override
            public void run() {
                try {
                    mTask.run();
                } finally {
                    synchronized (this) {
                        mDone = true;
                        notifyAll();
                    }
                }
            }
            public boolean postAndWait(Handler handler, long timeout) {
                if (!handler.post(this)) {
                    return false;
                }
                synchronized (this) {
                    if (timeout > 0) {
                        final long expirationTime = SystemClock.uptimeMillis() + timeout;
                        while (!mDone) {
                            long delay = expirationTime - SystemClock.uptimeMillis();
                            if (delay <= 0) {
                                return false; // timeout 超时了
                            }
                            try {
                                wait(delay);
                            } catch (InterruptedException ex) {
                            }
                        }
                    } else {
                        while (!mDone) {
                            try {
                                wait();
                            } catch (InterruptedException ex) {
                            }
                        }
                    }
                }
                return true;
            }
        }
    }
}

然后在activity里直接测试:

打印:

ok. 结果符合预期。

posted @ 2025-10-23 19:35  wzzkaifa  阅读(2)  评论(0)    收藏  举报