2016-05-31 63 views
3

runOnUiThread()在线程内执行时似乎不起作用。任何人都知道解决方法?robolectric 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()); 
    } 

} 

回答

1

结果的测试很可能因为第二试块这是需要运行目标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。

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

@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()); 
}