runOnUiThread使用技巧

时间:2013-02-12 10:23:50

标签: android testing robotium

我有一个正在使用Robotium进行测试的课程,在onPause()方法中我只清除EditText(我不需要在onPause()之后保留数据)

所以我参加了一个考试的课程:

@Override
protected void onPause() {
    super.onPause();
    mEdtPassword.setText("");
}

和测试方法:

public void testOnPauseOnStart() {
        Activity mActivity = getActivity();
        solo.typeText(0, CORRECT_PASSWORD);

        getInstrumentation().callActivityOnPause(mActivity);
    }

但后来我收到了一个错误:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4746)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:854)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:4077)
at android.view.View.invalidate(View.java:10322)
at android.widget.TextView.invalidateRegion(TextView.java:4395)
at android.widget.TextView.invalidateCursor(TextView.java:4338)
at android.widget.TextView.spanChange(TextView.java:7186)
at android.widget.TextView$ChangeWatcher.onSpanAdded(TextView.java:8821)
at android.text.SpannableStringBuilder.sendSpanAdded(SpannableStringBuilder.java:979)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:688)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:588)
at android.text.Selection.setSelection(Selection.java:76)
at android.text.Selection.setSelection(Selection.java:87)
at android.text.method.ArrowKeyMovementMethod.initialize(ArrowKeyMovementMethod.java:302)
at android.widget.TextView.setText(TextView.java:3555)
at android.widget.TextView.setText(TextView.java:3425)
at android.widget.EditText.setText(EditText.java:80)
at android.widget.TextView.setText(TextView.java:3400)
at <package>.ui.CheckPasswordActivity.onPause(CheckPasswordActivity.java:182)

如果我使用solo.setActivityOrientation(Solo.LANDSCAPE),我不会收到此错误。

然后,如果我用mEdtPassword.setText("")包裹runOnUiThread(),一切都很好。

所以问题是:

  1. 为什么我使用solo.setActivityOrientation()时没有这个例外,但是当我使用getInstrumentation().callActivityOnPause(mActivity)时我会这样做,我认为两者都在做同样的事情。

  2. 我是否应该将mEdtPassword.setText("")中的onPause()之类的内容与其他地方的runOnUiThread包装在一起,或者我只是需要它用于测试目的?

  3. 这是否意味着如果我想要测试我的UI我需要编写更多代码(比如在UI线程上运行普通操作)以便可以运行它们?

  4. 非常感谢您的澄清。

2 个答案:

答案 0 :(得分:0)

这就是我所知道的对你有用的东西:

  

1)为什么我使用时没有此异常   solo.setActivityOrientation()但是当我使用时我会这样做   getInstrumentation()。callActivityOnPause(mActivity),我假设两者   正在做同样的事情。

根据callActivityOnPause()

的javadoc
  

执行调用活动的onPause()方法。默认   实现只是调用该方法。

所以它会在其线程上调用onPause()而不是UI线程。现在,由于您要在Activity onPause()中设置值并编辑文本,因此会出错。因此,EditText上设置值的错误原因。由于您没有在setActivityOrientation()中执行任何UI操作,因此不会抛出任何错误。

  

2)我应该在onPause()中包含mEdtPassword.setText(“”)这样的内容   runOnUiThread在其他地方出于其他原因或我只是需要它   用于测试目的?

     

3)这是否意味着如果我想要我的UI测试我需要写更多   代码(比如在UI线程上运行普通操作)来实现它   可以运行它们吗?

我会一起回答第二点和第三点。您无需更改活动以使其可测试。如果您现在正在测试的活动方法正在执行与UI相关的任务,那么您可以将UiThreadTest注释添加到测试方法中。您还可以阅读此link了解更多信息..

我的知识只来自阅读我自己没有测试过的java文档。所以,请试一试,让我知道它是如何工作的。

答案 1 :(得分:0)

Praful大部分是正确的,但我相信你无法在使用@UiThreadTest注释的测试中使用乐器方法。这意味着你最好的选择实际上是在一个可以发布到主线程的runnable中包装instrumentation方法。例如:

public void callActivityOnPause(final Activity activity){
    getInstrumentation().runOnMainSync(new Runnable() {
            public void run() {
                activity.onpause();
            }
        });
}

我没有尝试过这段代码,所以它可能是错的,只是在火车上消磨时间!