Singletons And ContextSingletons

stephanenicolas edited this page Oct 16, 2014 · 1 revision

You should be familiar with injection of Pojos before reading this, see Your First Pojo Injection.

Overview

  1. Extend RoboActivity
  2. Annotate your POJO with @Inject
  3. Annotate your POJO class with @Singleton

Your First Singleton

class MyActivity extends RoboActivity {
    @Inject Foo foo; // this will basically call new Foo();
}

In the example above, every time a new instance of MyActivity is created, it will receive a new instance of Foo.

If we now annotate the class Foo with @Singleton, RoboGuice will instantiate only one instance of Foo and inject this same instance every time an injection of Foo is required.

@Singleton //a single instance of Foo is now used though the whole app
class Foo {
}

In that case :

new MyRoboActivity().foo = new MyRoboActivity().foo

⚠ Warning ⚠

When you use the annotation @Singleton, you create an Object that will never be garbage collected. It will be destroyed when the application itself is destroyed, but will remain in memory even if your activity doesn't use it anymore, as long as your app is still alive. This annotation can create memory leaks if you don't use it properly. Read below and see if @ContextSingleton would be enough for your needs.

Context singletons

To the opposite of singletons created via @Singleton, the singletons created via @ContextSingleton are tied to a Context lifecycle and are garbage collected when this context gets destroyed.

@ContextSingleton //a single instance of Foo is now used per context
class Foo {
}

Within the example above, the class Foo will now be instantiated once and only once within a Context scope. This means that 2 instances of MyActivity would receive 2 different instances of Foo (as opposed to using @Singleton, as in that case a single instance would be shared across activities). But, within the same Context, Foo is instantiated once and only once (as opposed to not using @Singleton or @ContextSingleton at all, as in that case we would receive a different instance of Foo for each injection).

For more details :

public MyActivity extends RoboActivity {
  @Inject Foo foo;
  @Inject Bar bar;
}

public class Foo {
  @Inject Bar bar;
}

@ContextSingleton
public class Bar {
}

In that case :

new MyRoboActivity().foo != new MyRoboActivity().foo
MyRoboActivity a = new MyRoboActivity();
a.bar == a.foo.bar

⚠ Warning ⚠

When you use the annotation @ContextSingleton, you create an Object that will not be garbage collected within a given Context lifecycle. It will be destroyed when the context itself is destroyed, but will remain in memory even if your context doesn't use it anymore. This annotation can still create memory leaks if you don't use it properly, for instance when using fragments. Read below and see if @FragmentSingleton would be enough for your needs.

RoboGuice 3.0

The version 3.0 of RoboGuice, will introduce a new scope for fragments : FragmentScope. This scope spans for the entire lifecycle of a given fragment : the injections defined inside this scope will live as long as the fragment lives and will be destroyed when the fragment is destroyed.

See issue : #201

Within a FragmentScope, it is possible to define singletons. Each FragmentSingleton will be instantiated only once within its associated FragmentScope:

public MyFragment extends RoboFragment {
  @Inject Foo foo;
  @Inject Bar bar;
}

public class Foo {
  @Inject Bar bar;
}

@FragmentSingleton
public class Bar {
}

In that case, every annotated field : @Inject Foo foo; will receive a different instance of Foo. On the opposite, all the annotated fields @Inject Bar bar;, within the same fragment scope will receive the same instance of Bar per fragment.

For instance, in the example above,

myFragment.bar = myFragment.foo.bar
new MyFragment().bar = new MyFragment().foo.bar
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.