Chloe
Chloe

Reputation: 26264

Test app lifecycle, destruction and creation

I need to test my apps lifecycle and its destruction and re-creation, because when the keyboard slides in/out (or is rotated), the app is destroyed and re-created. I also need to test for memory leaks when it does this.

I saw in the tutorial http://developer.android.com/tools/testing/activity_test.html#StateManagementTests

Terminate the activity and restart it:
mActivity.finish();
mActivity = this.getActivity();

However this is very simplified. My logging seems to indicate that calling finish() spawns a background thread with a different thread id which then calls onPause(), finish(), onStop(), and onDestroy(). I even tried getInstrumentation().waitForIdleSync(); to try to wait for that background thread to complete, but I still get race conditions when I test for expected values.

Not only that, but when it re-creates the Activity (when the 1st race condition doesn't occur or I comment out the assert), with getActivity(), then it just returns the exact same object that I just finished! I can tell because I log this in my onXXX...() methods.

This differs from the orientation rotation / keyboard sliding app lifecycle, which always creates a new Activity object.

So how can I test this destruction / reincarnation scenario?

Upvotes: 1

Views: 289

Answers (2)

Chloe
Chloe

Reputation: 26264

Ok I found it! It involves LOTs of waitForIdleSync() since it is multi-threaded to begin with, and setActivity(null). I could only get within +- 30% of the same memory. I would like to give credit to Peter Carpenter too, because his idea sped up my app and I would never have thought of that!

public void testMemoryLeaks() {
    Log.e(TAG, "------------ testMemoryLeaks()");
    getInstrumentation().waitForIdleSync();
    System.gc();
    Main mActivity = getActivity();
    Log.d(TAG, "-- Extractor.stop() "+mActivity.getExtractor());
    mActivity.getExtractor().stop();
    getInstrumentation().waitForIdleSync();
    System.gc();
    long mem = Runtime.getRuntime().freeMemory();
    Log.d(TAG, "-- freeMemory: " + mem);
    Log.d(TAG, "-- mActivity.finish()");
    mActivity.finish();
    getInstrumentation().waitForIdleSync();
    Log.d(TAG, "-- setActivity()");
    setActivity(null);
    getInstrumentation().waitForIdleSync();
    System.gc();
    Log.d(TAG, "-- getActivity()");
    mActivity = getActivity();
    assertTrue(mActivity != null);
    Log.d(TAG, "-- Extractor.stop() "+mActivity.getExtractor());
    mActivity.getExtractor().stop();
    getInstrumentation().waitForIdleSync();
    System.gc();
    long memAfter = Runtime.getRuntime().freeMemory();
    Log.d(TAG, "-- freeMemory: " + memAfter);
    assertTrue("Memory leak", mem > memAfter * .70 && mem < memAfter * 1.30);
    mActivity.finish();
    getInstrumentation().waitForIdleSync();
    Log.d(TAG, "-- end testMemoryLeaks()");
}

Upvotes: 0

Peter
Peter

Reputation: 679

The only way I know of to replicate the orientation change is to actually do it. (Keypad #7 key) Perhaps what you're really after is to prevent the app from being killed on orientation change.... ;) You can do this by overriding the onConfigurationChanged() function in your activity. see: http://developer.android.com/guide/topics/resources/runtime-changes.html

Upvotes: 1

Related Questions