2

In both the Testing Fundamentals and the Activity Testing section entitled "Adding state management tests" in the Android developer documentation, it suggests testing activity restarts using:

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

Having tried this with the addition of a sleep between the two statements above, I can see that the Activity is not redrawn on the screen when the mActivity = this.getActivity() is executed. My test appears to work, but I am intrigued as to why the Activity isn't redrawn on the screen as this doesn't seem to be mentioned in the API documentation.

I'd be grateful for any insight into this anyone can give. At the point the finish() method is called, the Activity disappears from the screen, but doesn't reappear when the this.getActivity() is called. I've also tried putting an mActivity.setVisible(true) after the getActivity(), but that doesn't help.

My code snippet is now:

...
mActivity.finish();
Thread.sleep(5000);
mActivity = this.getActivity();
Thread.sleep(5000);
...

I've searched extensively, but can't find any explanation of why the Activity doesn't reappear when getActivity() is called.

I've tested this on Android 2.3.5, 2.3.3 and 2.2.2 all with the same result.

HexAndBugs
  • 5,549
  • 2
  • 27
  • 36
  • 1
    Thank you for asking this question, because my UIThread code would not run when the UI thread was not on screen! – Noumenon Jul 30 '13 at 14:58

1 Answers1

8

It seems that class ActivityInstrumentationTestCase2 needs an additional finish method in which some cleanup must be done. In meanwhile you can work around this problem by cleaning up yourself after finishing the activity. So change your code as follows:

mActivity.finish();
setActivity(null);
mActivity = this.getActivity();

This can be explained as follows. Method getActivity in class ActivityInstrumentationTestCase2 calls setActivity(a)

public T getActivity() {
    Activity a = super.getActivity();
    if (a == null) {
        // set initial touch mode
        getInstrumentation().setInTouchMode(mInitialTouchMode);
        final String targetPackage = 
            getInstrumentation().getTargetContext().getPackageName();
        // inject custom intent, if provided
        if (mActivityIntent == null) {
            a = launchActivity(targetPackage, mActivityClass, null);
        } else {
            a = launchActivityWithIntent(targetPackage, 
                                         mActivityClass, 
                                         mActivityIntent);
        }
        setActivity(a);
    }
    return (T) a;
}

Method setActivity sets internal variable mActivityIntent.

public void setActivityIntent(Intent i) {
    mActivityIntent = i;
}

All calls after this first call will now use the new value mActivityIntent instead of a null-value. As a result

a = launchActivityWithIntent(targetPackage, mActivityClass, mActivityIntent);

will be called. Probably your app can not be started with this intent.

Note that method rearDown does a proper cleanup:

protected void tearDown() throws Exception {
    // Finish the Activity off (unless was never launched anyway)
    Activity a = super.getActivity();
    if (a != null) {
        a.finish();
        setActivity(null);
    }
}
Kjartan
  • 18,591
  • 15
  • 71
  • 96
Padi
  • 291
  • 3
  • 4
  • This answer fixed my problem where my UI thread code was mysteriously not running after `activity.finish()`, which defeated the whole purpose of testing onDestroy. Thank you. – Noumenon Jul 30 '13 at 15:03
  • From the docs :Terminate the activity and restart it: **mActivity.finish();** **mActivity = this.getActivity();** They should really update the documentation ... – Decoy Sep 23 '14 at 14:39
  • Thanks a lot for finding this. – Decoy Sep 23 '14 at 14:40