What does @Scope do?

If a scope annotation is present, the injector may retain the instance for possible reuse in a later injection.

@SomeScope
@Component(dependencies = SomeModule.class)
interface SomeComponent {}

@Module
class SomeModule {
  @SomeScope SomeObject createObject();
}

Given that there is @Scope annotated Dagger Component above. The effect of the @SomeScope is that: for the lifetime of the SomeComponent, there will be one and only one SomeObject instance exists. In other words, @SomeScope can be used to "instruct" the SomeComponent to keep the SomeObject for later use.

How is @Scope implemented

Under the hood, the DoubleCheck class is used internally to keep the object reference and "re-inject" when requested. If we throw out the code related to being thread-safe, it will look like this:

public final class DoubleCheck<T> {
  private static final Object UNINITIALIZED = new Object();
  private volatile Provider<T> provider;
  private volatile Object instance = UNINITIALIZED;

  @Override
  public T get() {
    if (instance == UNINITIALIZED) {
       instance = provider.get();
    }
    return (T) instance;
  }
}

From the code above, multiple calls to DoubleCheck.get() will return the same instance which serves the purpose of the scoped injection.

In Android, a @ActivityScope declared as:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {}

Is often used to ensure that the scoped annotation object is singleton within the lifecycle of the Activity given that, there is only one DaggerComponent associated to that Activity.