Skip to content

Commit

Permalink
Add ActivityController.close that transitions Activity to destroyed s…
Browse files Browse the repository at this point in the history
…tate

Update ActivityController to implement AutoCloseable, and add a 'close'
method that is lifecycle-aware and transitions the underlying Activity
to the destroyed state, freeing all resources and making the Activity
eligible for gc.

This is a convenient way to ensure that ActivityControllers can be freed
without having to manage the underlying Activity lifecycles.

It also enables ActivityController to be managed using
try-with-resources.

PiperOrigin-RevId: 410291892
  • Loading branch information
hoisie committed Nov 17, 2021
1 parent 662a2fe commit 1a350f7
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 1 deletion.
Expand Up @@ -379,6 +379,77 @@ public void windowFocusChanged() {
assertThat(controller.get().hasWindowFocus()).isTrue();
}

@Test
public void close_transitionsActivityStateToDestroyed() {
Robolectric.buildActivity(MyActivity.class).close();
assertThat(transcript).isEmpty();
transcript.clear();

Robolectric.buildActivity(MyActivity.class).create().close();
assertThat(transcript)
.containsExactly("onCreate", "finishedOnCreate", "onDestroy", "finishedOnDestroy");
transcript.clear();

Robolectric.buildActivity(MyActivity.class).create().start().close();
assertThat(transcript)
.containsExactly(
"onCreate",
"finishedOnCreate",
"onStart",
"finishedOnStart",
"onStop",
"finishedOnStop",
"onDestroy",
"finishedOnDestroy");
transcript.clear();

Robolectric.buildActivity(MyActivity.class).setup().close();
assertThat(transcript)
.containsExactly(
"onCreate",
"finishedOnCreate",
"onStart",
"finishedOnStart",
"onPostCreate",
"finishedOnPostCreate",
"onResume",
"finishedOnResume",
"onPostResume",
"finishedOnPostResume",
"onPause",
"finishedOnPause",
"onStop",
"finishedOnStop",
"onDestroy",
"finishedOnDestroy");
}

@Test
public void close_tryWithResources_getsDestroyed() {
try (ActivityController<MyActivity> ignored =
Robolectric.buildActivity(MyActivity.class).setup()) {
// no-op
}
assertThat(transcript)
.containsExactly(
"onCreate",
"finishedOnCreate",
"onStart",
"finishedOnStart",
"onPostCreate",
"finishedOnPostCreate",
"onResume",
"finishedOnResume",
"onPostResume",
"finishedOnPostResume",
"onPause",
"finishedOnPause",
"onStop",
"finishedOnStop",
"onDestroy",
"finishedOnDestroy");
}

public static class MyActivity extends Activity {
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Expand Down
Expand Up @@ -44,7 +44,18 @@
*/
@SuppressWarnings("NewApi")
public class ActivityController<T extends Activity>
extends ComponentController<ActivityController<T>, T> {
extends ComponentController<ActivityController<T>, T> implements AutoCloseable {

enum LifecycleState {
INITIAL,
CREATED,
RESTARTED,
STARTED,
RESUMED,
PAUSED,
STOPPED,
DESTROYED
}

enum LifecycleState {
INITIAL,
Expand Down Expand Up @@ -541,6 +552,38 @@ private Instrumentation getInstrumentation() {
return _component_.getInstrumentation();
}

/**
* Transitions the underlying Activity to the 'destroyed' state by progressing through the
* appropriate lifecycle events. It frees up any resources and makes the Activity eligible for GC.
*/
@Override
public void close() {

LifecycleState originalState = currentState;

switch (originalState) {
case INITIAL:
case DESTROYED:
return;
case RESUMED:
pause();
// fall through
case PAUSED:
// fall through
case RESTARTED:
// fall through
case STARTED:
stop();
// fall through
case STOPPED:
// fall through
case CREATED:
break;
}

destroy();
}

/** Accessor interface for android.app.Activity.NonConfigurationInstances's internals. */
@ForType(className = "android.app.Activity$NonConfigurationInstances")
interface _NonConfigurationInstances_ {
Expand Down

0 comments on commit 1a350f7

Please sign in to comment.