浓缩咖啡和postDelayed

13

我有一个使用postDelayed调用的活动:

public class SplashActivity extends Activity {
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(...);
        handler.postDelayed(new Runnable() { 
            public void run() { finish(); }
        }, 3000L);
    }
 }

这个在应用启动时运行,我需要在我的登录界面和此之间进行导航。然而,UIController的loopMainThreadUntilIdle似乎没有考虑处理程序中的基础消息队列。因此,在队列中仍然存在消息时,此操作将立即完成。

onView(withId(R.id.splash_screen)).perform(new ViewAction() {
    @Override
    public Matcher<View> getConstraints() {
        return isAssignableFrom(View.class);
    }

    @Override
    public String getDescription() {
        return "";
    }

    @Override
    public void perform(final UiController uiController, final View view) {
        uiController.loopMainThreadUntilIdle();
    }
});

我一直无法想出如何阻塞,直到队列被排空。Android本身防止我尝试许多事情(比如扩展Handler并重写postDelayed方法等)。

有人有关于如何处理postDelayed的建议吗?

我宁愿避免使用uiController.loopMainThreadForAtLeast,因为它似乎很hacky(就像Thread.sleep一样)。

2个回答

16
当 Espresso 等待时,它实际上考虑了 MessageQueue,但与您想象的不同。要处于空闲状态,队列必须为空或者有任务需要在 15 毫秒后运行。
您可以自己查看代码,特别是 UiControllerImpl.java 中的 loopUntil() 方法和 QueueInterrogator.java 文件。在后者中,您还将找到 Espresso 如何检查 MessageQueue(方法 determineQueueState())的逻辑。
那么,如何解决您的问题?有许多种方法:
1. 使用 AsyncTask 而不是 Handler,在后台线程上休眠并在 onPostExecute() 中执行操作。这样做可以解决问题,因为 Espresso 会等待 AsyncTask 完成,但可能不喜欢另一个线程的开销。
2. 在测试代码中休眠,但您已经不喜欢这种方法。
3. 编写自定义的 IdlingResource:这是一种通用机制,用于让 Espresso 知道何时空闲,以便运行操作和断言。对于此方法,您可以:
- 使用 Espresso 提供的 CountingIdlingResource 类。 - 当您发布可运行文件时调用 increment(),在可运行文件内部的逻辑运行后调用 decrement()。 - 在测试设置中注册您的 IdlingResource,并在拆卸中注销它。

参见: 文档和示例另一个示例


1
我在考虑是否应该将消息推送到队列的抽象化,并注入一些其他实现,作为IdlingResource。我将在我的代码中有一个默认实现,它会延迟到处理程序,并在测试代码中有一个是IdlingResource并增加/减少。 - Matt

0
据我所知,Espresso中没有等待活动完成的方法。您可以实现自己的waitForCondition版本,类似于Robotium。这样,您只需要等待所需的时间,并且可以检测到活动未完成的问题。
您可以基本上每隔x毫秒轮询条件,例如:
while (!conditionIsMet() && currentTime < timeOut){
    sleep(100);
}

boolean conditionIsMet() {
    return "espresso check for if your splash view exists";
}

问题在于Android没有提供一种真正查看消息队列是否有任何排队内容的方法。这必须是在启动时被拦截和替换的东西(我认为这就是Robotium所做的)。 - Matt
waitForCondition类只是作为您自己编写的条件轮询。至于robotium检查队列,我不太相信,因为我也看到了像你遇到的robotium问题。 - JohanShogun
对于这种用例,您应该能够等待操作完成,而不是查看消息队列(从测试角度来看,这确实更有趣)。 - JohanShogun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接