Activity Lifecycle (Java)

Activities move through well-defined lifecycle callbacks as they appear, gain focus, lose focus, become hidden, and are destroyed. Understanding these transitions helps you place code in the right callback, persist UI state, and avoid memory leaks or crashes during configuration changes and process death.

High-Level Flow

Created

onCreate()

Visible

onStart()

Interactive

onResume()

Paused

onPause()

Stopped

onStop()

Destroyed

onDestroy()

onCreateonStartonResume(Running)onPauseonStoponDestroy Visible Interactive Not visible

Callback Responsibilities

CallbackWhenDoAvoid
onCreate(Bundle) First time created setContentView, DI, inflate/bind views, restore savedInstanceState Long-running tasks (move to background thread)
onStart() Becoming visible Register UI-related receivers, start lightweight UI updates Heavy work, starting sensors if not needed
onResume() Gains focus (interactive) Start camera, location updates, animations, listeners Blocking I/O, disk DB operations on main thread
onPause() Partially obscured Commit small UI state, pause animations/sensors Lengthy saves; it should be fast
onStop() No longer visible Release resources, unregister receivers, stop expensive work Holding onto context-bound references
onDestroy() Finishing / system destroying Final cleanup; beware it may not always be called Relying on it for critical persistence
// Skeleton with logs (Java)
public class LifecycleActivity extends AppCompatActivity {
    private static final String TAG = "LifecycleActivity";
    private static final String KEY_COUNT = "count";
    private int clickCount = 0;

    @Override protected void onCreate(Bundle s) {
        super.onCreate(s);
        setContentView(R.layout.activity_lifecycle);
        Log.d(TAG, "onCreate");
        if (s != null) {
            clickCount = s.getInt(KEY_COUNT, 0); // restore small UI state
        }
    }
    @Override protected void onStart(){super.onStart(); Log.d(TAG,"onStart");}
    @Override protected void onResume(){super.onResume(); Log.d(TAG,"onResume");}
    @Override protected void onPause(){ Log.d(TAG,"onPause"); super.onPause(); }
    @Override protected void onStop(){ Log.d(TAG,"onStop"); super.onStop(); }
    @Override protected void onDestroy(){ Log.d(TAG,"onDestroy"); super.onDestroy(); }

    @Override protected void onSaveInstanceState(Bundle out) {
        super.onSaveInstanceState(out);
        out.putInt(KEY_COUNT, clickCount); // small, serializable state
    }
}

State, Configuration Changes & Process Death

Android can destroy and recreate your Activity during configuration changes (rotation, locale, night mode…) or when the process is killed in the background. Use multiple layers of state protection:

  • UI instant stateonSaveInstanceState / savedInstanceState
  • Screen dataViewModel (survives config changes; not process death)
  • Long-term → DB / SharedPreferences / file
// ViewModel for screen-level state
public class CounterViewModel extends ViewModel {
    public MutableLiveData<Integer> counter = new MutableLiveData<>(0);
}

// In Activity
CounterViewModel vm;
@Override protected void onCreate(Bundle s) {
  super.onCreate(s);
  setContentView(R.layout.activity_main);
  vm = new ViewModelProvider(this).get(CounterViewModel.class);
  vm.counter.observe(this, value -> ((TextView)findViewById(R.id.tv)).setText(String.valueOf(value)));
}
Tip: Treat onSaveInstanceState as your “instant restore” for small UI values (scroll positions, selections). Use DB for large objects.

Lifecycle-Aware Components

Classes that implement DefaultLifecycleObserver or use LifecycleOwner can start/stop work when the Activity goes to the foreground/background automatically.

// Lifecycle-aware helper
public class Tracker implements DefaultLifecycleObserver {
  @Override public void onResume(@NonNull LifecycleOwner owner){ start(); }
  @Override public void onPause(@NonNull LifecycleOwner owner){ stop(); }
  private void start(){ // start sensors/network polling }
  private void stop(){ // stop sensors/network polling }
}

// In Activity
Tracker tracker = new Tracker();
getLifecycle().addObserver(tracker);

Foreground vs Background Work

Put This In…

UI binding → onCreate/onStart
Sensors/Camera → onResume
Pause/commit small state → onPause
Stop heavy tasks → onStop

Avoid Doing In…

onCreate: long DB/network on main
onPause: slow writes
onDestroy: critical persistence

Configuration Changes (Options)

  • Default (recommended): let system recreate; rely on ViewModel + savedInstanceState + persistent store.
  • Handle yourself: declare configChanges (advanced, use sparingly).
<!-- AndroidManifest.xml (advanced) -->
<activity android:name=".CameraActivity"
          android:configChanges="orientation|keyboardHidden|screenSize"/>

Long-Running Work

Use background threads, coroutines (Kotlin) or ExecutorService/HandlerThread in Java. Tie start/stop to lifecycle.

private ExecutorService io = Executors.newSingleThreadExecutor();

@Override protected void onResume(){
  super.onResume();
  io.submit(() -> {
    // network/db work
    runOnUiThread(() -> { // update UI safely });
  });
}

@Override protected void onStop(){
  super.onStop();
  // optionally cancel/interrupt ongoing tasks
}

Common Pitfalls

  • Leaking Context: Passing Activity to static singletons or long-lived objects.
  • Heavy work on main thread: Causes ANRs; move to background threads.
  • Forgetting to unregister: Receivers/sensors kept after onStop().
  • Relying on onDestroy: Not guaranteed; persist important state earlier.
  • Not handling process death: Use savedInstanceState + persistent storage.

Hands-On Checklist

  • Add logs to each lifecycle method and rotate the device—observe order.
  • Save a counter in onSaveInstanceState; restore it on recreate.
  • Start camera preview in onResume, stop it in onPause.
  • Move list data to a ViewModel and verify it survives rotation.

Quick Reference (Cheat Sheet)

Visible & interactive └─ onCreate() → onStart() → onResume() Backgrounded (partially covered) └─ onPause() Not visible └─ onStop() Process may reclaim resources → onDestroy() (if finishing)