Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between runOnUiThread() method and @UiThreadTest annotation

As the title, can anyone explain the difference between the runOnUiThread() method and the @UiThreadTest annotation? I've been reading through the Android testing tutorial (http://developer.android.com/tools/testing/activity_test.html) which uses both. It states:

Code in a test application that interacts with a View of the application under test must run in the main application's thread, also known as the UI thread. To do this, you use the Activity.runOnUiThread() method

and:

The @UiThreadTest annotation tells Android to build this method so that it runs on the UI thread. This allows the method to change the state of the spinner widget in the application under test.

For the runOnUi() method, the code in question is

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);
}

and for the @UiThreadTest annotation:

@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);     
}

They appear to be interchangeable, in the sense that I can remove the annotation from the annotated test and include its contents in a runOnUiThread() method and it passes. Similarly, I can remove the runOnUiThread() method from the other test and add the @UiThreadTest annotation and it passes.

So what's the difference?

Additionally, the tutorial includes another test:

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);
}

This test also interacts with the activity but requires neither the @UiThreadTest annotation or a runOnUiThread() method. Why is this?

like image 753
barry Avatar asked Oct 17 '13 12:10

barry


People also ask

What is runOnUiThread?

Sometimes Main thread performs some heavy operations. if user wants to add some extra operations on UI, it will get load and provides ANR. Using runOnUiThread going to do back ground operations on worker thread and update the result on main thread. This example demonstrate about How do we use runOnUiThread in Android.

Which helper method helps to run a portion of a test in UI thread?

runOnUiThread. Helper method for running part of a method on the UI thread.


1 Answers

The difference is in semantics and side effects.

First, the presence of @UiThreadTest causes the activity to be created if it hasn't been already by calling getActivity().

Then, in InstrumentatinTestCase, it uses getInstrumentation().runOnMainSync() to run the full test.

The difference between getInstrumentation().runOnMainSync() and Activity.runOnUiThread() is that the former waits for the call to finish (needed when running a full test or, you know, calling things inside a test) while the latter doesn't.

Other than that, they post to different Handlers (runOnMainSync uses the one from ActivityThread, while the Activity instance has its own) but that's irrelevant, since they're getting scheduled on the same MessageQueue.

like image 142
Delyan Avatar answered Nov 09 '22 04:11

Delyan