11

如题,谁能解释一下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() 方法。为什么是这样?

4

1 回答 1

10

区别在于语义和副作用。

首先,@UiThreadTest如果尚未通过调用getActivity().

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

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

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

于 2013-10-17T13:24:22.317 回答