2016-05-31 6 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.

Первый тест пройдет, потому что весь метод выполняется синхронно. Поскольку вы уже находитесь в потоке пользовательского интерфейса, при вызове activity.runOnUiThread(...)Runnable будет выполнен немедленно. Так как latch тогда 0 latch.await(20, TimeUnit.SECONDS) немедленно возвращается, и утверждение верно.

Во втором примере вы начинаете новый поток и вызываете activity.runOnUiThread(...) изнутри. Поскольку вы не находитесь в потоке пользовательского интерфейса, Runnable отправляется в Handler в потоке пользовательского интерфейса, который будет выполняться в будущем асинхронно. На этом этапе вы переходите к вызову latch.await(20, TimeUnit.SECONDS); из потока пользовательского интерфейса, что означает, что Runnable не может работать за это время, так как вы блокируете поток пользовательского интерфейса.

Через 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()); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^