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

bar*_*rry 9 junit android unit-testing

作为标题,任何人都可以解释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);
}
Run Code Online (Sandbox Code Playgroud)

并为@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);     
}
Run Code Online (Sandbox Code Playgroud)

它们似乎是可互换的,因为我可以从注释测试中删除注释并将其内容包含在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);
}
Run Code Online (Sandbox Code Playgroud)

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

Del*_*yan 8

区别在于语义和副作用.

首先,@UiThreadTest如果尚未通过调用getActivity(),则存在会导致创建活动.

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

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

除此之外,他们发布到不同的Handlers(runOnMainSync使用一个ActivityThread,虽然Activity实例有自己的),但这是无关紧要的,因为他们已经安排在同一个MessageQueue.