public final class

ActivityLifecycleMonitorImpl

extends java.lang.Object

implements ActivityLifecycleMonitor

 java.lang.Object

↳androidx.test.internal.runner.lifecycle.ActivityLifecycleMonitorImpl

Gradle dependencies

compile group: 'androidx.test', name: 'monitor', version: '1.6.0-alpha03'

  • groupId: androidx.test
  • artifactId: monitor
  • version: 1.6.0-alpha03

Artifact androidx.test:monitor:1.6.0-alpha03 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.test:monitor com.android.support.test:monitor

Overview

The lifecycle monitor implementation.

Summary

Constructors
publicActivityLifecycleMonitorImpl()

publicActivityLifecycleMonitorImpl(boolean declawThreadCheck)

Methods
public voidaddLifecycleCallback(ActivityLifecycleCallback callback)

public java.util.Collection<Activity>getActivitiesInStage(Stage stage)

public StagegetLifecycleStageOf(Activity activity)

public voidremoveLifecycleCallback(ActivityLifecycleCallback callback)

public voidsignalLifecycleChange(Stage stage, Activity activity)

Called by the runner after a particular onXXX lifecycle method has been called on a given activity.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ActivityLifecycleMonitorImpl()

public ActivityLifecycleMonitorImpl(boolean declawThreadCheck)

Methods

public void addLifecycleCallback(ActivityLifecycleCallback callback)

public void removeLifecycleCallback(ActivityLifecycleCallback callback)

public Stage getLifecycleStageOf(Activity activity)

public java.util.Collection<Activity> getActivitiesInStage(Stage stage)

public void signalLifecycleChange(Stage stage, Activity activity)

Called by the runner after a particular onXXX lifecycle method has been called on a given activity.

Source

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.test.internal.runner.lifecycle;

import static androidx.test.internal.util.Checks.checkNotNull;

import android.app.Activity;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.RestrictTo;
import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
import androidx.test.runner.lifecycle.ActivityLifecycleMonitor;
import androidx.test.runner.lifecycle.Stage;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * The lifecycle monitor implementation.
 *
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // used by robolectric
public final class ActivityLifecycleMonitorImpl implements ActivityLifecycleMonitor {
  private static final String TAG = "LifecycleMonitor";
  private final boolean declawThreadCheck;

  public ActivityLifecycleMonitorImpl() {
    this(false);
  }

  // For Testing
  public ActivityLifecycleMonitorImpl(boolean declawThreadCheck) {
    this.declawThreadCheck = declawThreadCheck;
  }

  // Accessed from any thread.
  private final List<WeakReference<ActivityLifecycleCallback>> callbacks = new ArrayList<>();

  // Only accessed on main thread.
  private List<ActivityStatus> activityStatuses = new ArrayList<ActivityStatus>();

  @Override
  public void addLifecycleCallback(ActivityLifecycleCallback callback) {
    // there will never be too many callbacks, so iterating over a list will probably
    // be faster then the constant time costs of setting up and maintaining a map.
    checkNotNull(callback);

    synchronized (callbacks) {
      boolean needsAdd = true;
      Iterator<WeakReference<ActivityLifecycleCallback>> refIter = callbacks.iterator();
      while (refIter.hasNext()) {
        ActivityLifecycleCallback storedCallback = refIter.next().get();
        if (null == storedCallback) {
          refIter.remove();
        } else if (storedCallback == callback) {
          needsAdd = false;
        }
      }
      if (needsAdd) {
        callbacks.add(new WeakReference<>(callback));
      }
    }
  }

  @Override
  public void removeLifecycleCallback(ActivityLifecycleCallback callback) {
    checkNotNull(callback);

    synchronized (callbacks) {
      Iterator<WeakReference<ActivityLifecycleCallback>> refIter = callbacks.iterator();
      while (refIter.hasNext()) {
        ActivityLifecycleCallback storedCallback = refIter.next().get();
        if (null == storedCallback) {
          refIter.remove();
        } else if (storedCallback == callback) {
          refIter.remove();
        }
      }
    }
  }

  @Override
  public Stage getLifecycleStageOf(Activity activity) {
    checkMainThread();
    checkNotNull(activity);
    Iterator<ActivityStatus> statusIterator = activityStatuses.iterator();
    while (statusIterator.hasNext()) {
      ActivityStatus status = statusIterator.next();
      Activity statusActivity = status.activityRef.get();
      if (null == statusActivity) {
        statusIterator.remove();
      } else if (activity == statusActivity) {
        return status.lifecycleStage;
      }
    }
    throw new IllegalArgumentException("Unknown activity: " + activity);
  }

  @Override
  public Collection<Activity> getActivitiesInStage(Stage stage) {
    checkMainThread();
    checkNotNull(stage);

    List<Activity> activities = new ArrayList<Activity>();
    Iterator<ActivityStatus> statusIterator = activityStatuses.iterator();
    while (statusIterator.hasNext()) {
      ActivityStatus status = statusIterator.next();
      Activity statusActivity = status.activityRef.get();
      if (null == statusActivity) {
        statusIterator.remove();
      } else if (stage == status.lifecycleStage) {
        activities.add(statusActivity);
      }
    }

    return activities;
  }

  /**
   * Called by the runner after a particular onXXX lifecycle method has been called on a given
   * activity.
   */
  public void signalLifecycleChange(Stage stage, Activity activity) {
    // there are never too many activities in existence in an application - so we keep
    // track of everything in a single list.
    Log.d(TAG, "Lifecycle status change: " + activity + " in: " + stage);

    boolean needsAdd = true;
    Iterator<ActivityStatus> statusIterator = activityStatuses.iterator();
    while (statusIterator.hasNext()) {
      ActivityStatus status = statusIterator.next();
      Activity statusActivity = status.activityRef.get();
      if (null == statusActivity) {
        statusIterator.remove();
      } else if (activity == statusActivity) {
        needsAdd = false;
        status.lifecycleStage = stage;
      }
    }

    if (needsAdd) {
      activityStatuses.add(new ActivityStatus(activity, stage));
    }

    synchronized (callbacks) {
      Iterator<WeakReference<ActivityLifecycleCallback>> refIter = callbacks.iterator();
      while (refIter.hasNext()) {
        ActivityLifecycleCallback callback = refIter.next().get();
        if (null == callback) {
          refIter.remove();
        } else {
          try {
            callback.onActivityLifecycleChanged(activity, stage);
          } catch (RuntimeException re) {
            Log.e(
                TAG,
                String.format(
                    "Callback threw exception! (callback: %s activity: %s stage: %s)",
                    callback, activity, stage),
                re);
          }
        }
      }
    }
  }

  private void checkMainThread() {
    if (declawThreadCheck) {
      return;
    }

    if (!Thread.currentThread().equals(Looper.getMainLooper().getThread())) {
      throw new IllegalStateException("Querying activity state off main thread is not allowed.");
    }
  }

  private static class ActivityStatus {
    private final WeakReference<Activity> activityRef;
    private Stage lifecycleStage;

    ActivityStatus(Activity activity, Stage stage) {
      this.activityRef = new WeakReference<Activity>(checkNotNull(activity));
      this.lifecycleStage = checkNotNull(stage);
    }
  }
}