线程上的robolectric runOnUiThread不起作用

问题描述 投票:4回答:1

runOnUiThread()在线程中执行时似乎不起作用。有人知道一个变通方法吗?

注意:我在这里提交了一张票 - https://github.com/robolectric/robolectric/issues/2479

import android.app.Activity;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.junit.Assert.assertTrue;

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class RunOnUiThreadTest {

    /**
     * Works
     * @throws Exception
     */
    @Test
    public void inside_the_main_thread() throws Exception {
        final Activity activity = Robolectric.setupActivity(Activity.class);
        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicBoolean didRun = new AtomicBoolean(false);

        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                didRun.set(true);
                latch.countDown();
            }
        });

        latch.await(20, TimeUnit.SECONDS);
        assertTrue(didRun.get());
    }

    /**
     * Fails
     * @throws Exception
     */
    @Test
    public void inside_a_new_thread() throws Exception {
        final Activity activity = Robolectric.setupActivity(Activity.class);
        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicBoolean didRun = new AtomicBoolean(false);

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        didRun.set(true);
                        latch.countDown();
                    }
                });
            }
        });
        thread.start();

        latch.await(20, TimeUnit.SECONDS);
        assertTrue(didRun.get());
    }

}
android unit-testing testing robolectric
1个回答
2
投票

由于第二个测试阻止了运行目标Runnable所需的UI线程,因此测试的结果可能与预期的一样。

第一个测试将通过,因为整个方法是同步执行的。由于您已经在UI线程上,当调用activity.runOnUiThread(...)时,Runnable将立即执行。因为latch是0,所以latch.await(20, TimeUnit.SECONDS)立即返回并且断言为真。

在第二个示例中,您将启动一个新线程并从其中调用activity.runOnUiThread(...)。由于您不在UI线程上,因此将Runnable发布到UI线程上的Handler,以便将来异步执行。此时,您将继续从UI线程调用latch.await(20, TimeUnit.SECONDS);,这意味着在此期间Runnable无法运行,因为您阻止了UI线程。

20秒后,线程恢复,但Runnable从未有机会运行,因此断言失败,因为didRun()从未设置为true。

下面是一个更新的测试,允许使用Runnable发布的runOnUiThread()运行。

@Test
public void inside_a_new_thread() throws Exception {
    final Activity activity = Robolectric.setupActivity(Activity.class);
    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicBoolean didRun = new AtomicBoolean(false);

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    didRun.set(true);
                    latch.countDown();
                }
            });
        }
    });
    thread.start();

    // sleep current thread to give the new thread a chance to run and post the runnable
    Thread.sleep(1000);

    // This method will cause the runnable to be executed
    Robolectric.flushForegroundThreadScheduler();

    // Should immediately return since the runnable has been executed
    latch.await(20, TimeUnit.SECONDS);
    assertTrue(didRun.get());
}
© www.soinside.com 2019 - 2024. All rights reserved.