在大约20%的情况下会忽略Looper.loop

时间:2018-06-20 12:56:51

标签: java android multithreading

我有一个在后台运行的工作线程。在此工作线程上,我有一个名为syncWithUiThreadAndWait的方法。这是简化的代码:

function formatNumber(num) {
    var check = Math.round(num * 100) / 100;
    var rounded = Math.round(check);
    if (rounded == check) {
        return String(rounded);
    }
    return num.toFixed(2);
}

function formatNumberViaToFixed(num) {
    return num.toFixed(2).replace(/\.00$/, "");
}

function test(num) {
    var formatted = formatNumber(num);
    var viaToFixed = formatNumberViaToFixed(num);
    if (formatted == viaToFixed) {
        console.log(num, "=>", formatted);
    } else {
        console.log(num, "=>", formatted, "ERROR: Should be", viaToFixed);
    }
}
test(1.01);
test(1.43);
test(23.7);
test(1.200123);
test(1.000043);
test(1.007);
test(1.0007);

所以我的问题是:为什么有时这段代码正确运行,有时线程循环无法启动,并且收到“ WHY”异常?

编辑: 我决定添加一些说明,以使其更易于理解。 我想做的是与UI线程同步的线程。

  1. 首先,准备任务“ .as-console-wrapper { max-height: 100% !important; }”,一旦我“阻止”后台线程继续执行,该任务就会运行。
  2. 之后,我用 private void syncWithUiThreadAndWait(final Runnable codeToSync) { if (looper == null) throw new RuntimeException("Thread is not ready (Looper=null)"); if (looper != Looper.myLooper()) throw new RuntimeException("Called from wrong thread"); final boolean[] wasRun = {false}; new Handler(looper).post(new Runnable() { // I use 'new Handler(looper).post' instead of direct call to make sure that this code will // run 100% after Looper.loop() is called, because in some cases it can be called before Looper.loop @Override public void run() { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { synchronized (MyWorkerThread.this) { // Synchronization to establishes a happens-before relationship wasRun[0] = true; looper.quit(); } } }); } }); Looper.loop(); synchronized (MyWorkerThread.this) { // Synchronization to establishes a happens-before relationship if (!wasRun[0]) throw new RuntimeException("WHY!!!"); } } “阻塞”了我的后台线程
  3. 我准备的任务将在循环循环后运行,并将触发UI线程的代码。
  4. 最后,在将要在UI线程new Handler (looper) .post (...);上运行的代码的末尾,被调用来取消阻塞后台线程。

1 个答案:

答案 0 :(得分:0)

所以即使我仍然不知道为什么会这样。因此,如果有人可以解释,我会将其标记为正确答案。

但是我发现了使用Thread.sleep()而不是Looper.loop()的解决方法。威奇为我工作,可能更有效率:

private void syncWithUiThreadAndWait(final Runnable codeToSync) {
    synchronized (this) {
        if (thread == null)
            throw new RuntimeException("Thread not ready");
        if (Thread.currentThread() != thread)
            throw new RuntimeException("Called from wrong thread");
    }
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            codeToSync.run();
            setPaused(false);
        }
    });
    setPaused(true);
    final long sleepStart = System.currentTimeMillis();
    while (isPaused()) {
        try {
            Thread.sleep(200);
        } catch (InterruptedException ignored) { }
        if (sleepStart + TIMEOUT_IN_MILLISEC <= System.currentTimeMillis())
            throw new RuntimeException("Timeout waiting for network response");
    }
}

private synchronized boolean isPaused() {
    return paused;
}

private synchronized void setPaused(boolean newValue) {
    paused = newValue;
}