runOnUiThread()方法和@UiThreadTest注释之间的区别

时间:2013-10-17 12:57:30

标签: android unit-testing junit

作为标题,任何人都可以解释runOnUiThread()方法和@UiThreadTest注释之间的区别吗?我一直在阅读使用两者的Android测试教程(http://developer.android.com/tools/testing/activity_test.html)。它声明:

  

与测试中的应用程序视图交互的测试应用程序中的代码必须在主应用程序的线程(也称为UI线程)中运行。为此,请使用Activity.runOnUiThread()方法

  

@UiThreadTest注释告诉Android构建此方法,以便它在UI线程上运行。这允许该方法更改被测试应用程序中微调器窗口小部件的状态。

对于runOnUi()方法,有问题的代码是

public void testASpinnerUI()
{
    mActivity.runOnUiThread(
            new Runnable()
            {
                @Override
                public void run()
                {
                    mSpinner.requestFocus();
                    mSpinner.setSelection(INITIAL_POSITION);
                }// end of run
            } // end of runnable
        ); //end of runOnUiThread

    this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
    for (int i = 0; i < TEST_POSITION; i++)
    {
        this.sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
    }
    this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);

    mPos = mSpinner.getSelectedItemPosition();
    mSelection = (String) mSpinner.getItemAtPosition(mPos);

    TextView resultView = (TextView) mActivity.findViewById(com.android.example.spinner.R.id.SpinnerResult);

    String resultText = (String) resultView.getText();
    assertEquals(resultText, mSelection);
}

和@UiThreadTest注释:

@UiThreadTest
public void testStatePause()
{
    Instrumentation mInstr = this.getInstrumentation();
    mActivity.setSpinnerPosition(TEST_STATE_PAUSE_POSITION);
    mActivity.setSpinnerSelection(TEST_STATE_PAUSE_SELECTION);

    mInstr.callActivityOnPause(mActivity);

    mActivity.setSpinnerPosition(0);
    mActivity.setSpinnerSelection("");

    mInstr.callActivityOnResume(mActivity);

    int currentPosition = mActivity.getSpinnerPosition();
    String currentSelection = mActivity.getSpinnerSelection();

    assertEquals(TEST_STATE_PAUSE_POSITION, currentPosition);
    assertEquals(TEST_STATE_PAUSE_SELECTION, currentSelection);     
}

它们似乎是可互换的,因为我可以从注释测试中删除注释并将其内容包含在runOnUiThread()方法中并传递。同样,我可以从其他测试中删除runOnUiThread()方法并添加@UiThreadTest注释并传递。

那有什么区别?

此外,本教程还包括另一项测试:

public void testStateDestroy()
{
    mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);
    mActivity.setSpinnerSelection(TEST_STATE_DESTROY_SELECTION);

    mActivity.finish();
    mActivity = getActivity();

    int currentPosition = mActivity.getSpinnerPosition();
    String currentSelection = mActivity.getSpinnerSelection();

    assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);
    assertEquals(TEST_STATE_DESTROY_SELECTION, currentSelection);
}

此测试还与活动交互但不需要@UiThreadTest注释或runOnUiThread()方法。这是为什么?

1 个答案:

答案 0 :(得分:6)

区别在于语义和副作用。

首先,@UiThreadTest的存在会导致创建活动,如果它尚未by calling getActivity()

然后,在InstrumentatinTestCase中,它使用getInstrumentation().runOnMainSync()来运行完整测试。

getInstrumentation().runOnMainSync()Activity.runOnUiThread()之间的区别在于前者等待完成调用(在运行完整测试时需要,或者,你知道,在测试中调用内容),而后者不会吨。

除此之外,他们发布到不同的Handler s(runOnMainSync使用ActivityThread中的那个,而Activity实例有自己的实例)但这是无关紧要的,因为他们将被安排在同一MessageQueue