2016-05-31 5 views
3

스레드 내에서 실행될 때 runOnUiThread()가 작동하지 않는 것 같습니다. 누구나 해결 방법을 알고 있습니까?스레드에서 runonUi 스레드가 작동하지 않음

참고 : 여기 티켓을 제출 - 두 번째 테스트 블록 대상 Runnable을 실행하는 데 필요한 UI 스레드 때문에 예상대로 시험에 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

결과는 가능성이있다.

전체 메서드가 동 기적으로 실행되기 때문에 첫 번째 테스트가 통과합니다. 이미 UI 스레드에 있기 때문에 activity.runOnUiThread(...)을 호출하면 Runnable이 즉시 실행됩니다. latch이 0 일 때 latch.await(20, TimeUnit.SECONDS)이 즉시 반환되고 assert가 true이므로 true입니다.

두 번째 예에서는 새 스레드를 시작하고 그 안에 activity.runOnUiThread(...)을 호출합니다. UI 스레드가 아니기 때문에 Runnable은 향후 비동기 적으로 실행될 UI 스레드의 Handler에 게시됩니다. 이 시점에서 UI 스레드에서 으로 전화를 걸므로 UI ​​스레드를 차단하고 있기 때문에이 시간 동안 Runnable을 실행할 수 없습니다.

스레드가 다시 시작되지만 Runnable은 실행할 기회가 전혀 없으므로 didRun()이 절대로 true로 설정되지 않았기 때문에 어설 션이 실패합니다.

다음은 을 사용하여 게시 된 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()); 
} 
관련 문제