-
Notifications
You must be signed in to change notification settings - Fork 115
TP 2 TP 3: Migration Guide
To migrate from TP 2 to TP 3, here below are the most important changes. Note that we have also introduced new Toothpick Extensions.
In TP 2, scopes annotations and singletons were entangled together. This confusion comes from the JSR 330. In TP 3, we interpreted the JSR differently in order to provide more flexibility and expressivity to DI.
In TP2, we typically used a scope annotation such as:
@ActivitySingleton class Foo {}
It meant that class Foo
could only be instantiated in a scope that supported the ActivitySingleton
annotation & that Foo
will have a single instance (singleton) in such a scope.
In TP3, we offer a more fine grained distinction of the 2 concepts:
@ActivityScope class Foo {}
means that Foo
can only be instantiated in a scope that supported the ActivitySingleton
annotation. But a new instance will be created for each injection.
Independently, Foo
can be annotated using @Singleton
as well to indicate that Foo
will have a singleton instance (singleton) of such a scope:
@ActivityScope @Singleton
class Foo {}
If the annotation @Singleton
is used by itself, it designates a singleton of the root scope.
This new mechanism allows to enforce scope verification for virtually all injected components in an app.
We highly recommend that you rename your annotation to reflect this change. They should now end with the suffix Scope
.
In TP 3, scope annotations and bindings have the same expressivity. The new binding DSL and a partial rewrite of TP internals now offer a 1:1 relationship between scope annotations and bindings.
The documentation, the conceptualization, and the code of TP 2 were not clear about the equivalence between scope annotations and bindings, and the binding API was inconsistent in several ways. TP 3 solves this. Bindings and Scope annotations offer exactly the same features, and they work complementarily.
@ActivityScope class Foo
is exactly the same as defining:
scope.supportScopeAnnotation(ActivityScope::class)
.installModule( module {
bind<Foo>()
})
@ActivityScope @Singleton class Foo
is exactly the same as defining:
scope.supportScopeAnnotation(ActivityScope::class)
.installModule( module {
bind<Foo>().singleton()
})
@ActivityScope @Singleton @Releasable class Foo
is exactly the same as defining:
scope.supportScopeAnnotation(ActivityScope::class)
.installModule( module {
bind<Foo>().singleton().releasable()
})
@ActivityScope @Singleton
@ProvidesSingleton @ProvidesReleasable
class FooProvider implements Provider<Foo>
is exactly the same as defining:
scope.supportScopeAnnotation(ActivityScope::class)
.installModule( module {
bind<Foo>().toClass<FooProvider>()
.providesSingleton()
.providesReleasable()
.singleton()
})
Note that it is possible to mix annotations and bindings information. The resulting behavior is to "add" all the behaviors expressed by both annotations and bindings.
In TP 2, to open a branch in the scope tree, we typically did something like
Toothpick.openScopes(application, activity);
In TP 3, we prefer the more fluent API (available for java & kotlin):
KTP.openScope(application)
.openSubScope(activity)
In TP 3, we have introduced a new lambda to configure a scope when it is created (the lambda is not used when the scope was previously opened)
KTP.openScope(application) { it.installModule( module {...} ) }
.openSubScope(activity) { it.installModule( module {...} ) }
Scopes can now follow an activity or fragment or viewmodel lifecyle, see Toothpick Extensions
In TP 3, the Scope API is now fluent and allows to chain calls in a more elegant way:
KTP.openScope(application) { ... }
.openSubScope(activity) { ... }
.supportScopeAnnotation(ActivityScope::class)
.inject(this)
In TP 3, Toothpick can now release all singletons that are marked as releasable, either by binding or annotations.
KTP.openScope(application).release()
will release all singletons marked as releasable: making them ready for garbage collection. This is typically used when your app is under memory pressure.
In TP 3, we have introduced new annotations:
-
@ProvidesSingleton
is used to annotate a provider class and indicates that the instance provided will be a singleton. -
@ProvidesReleasable
can only be used with@ProvidesSingleton
, it is used to annotate a provider class and indicates that the instance provided will be a releasable singleton. -
@Releasable
can only be used with@Singleton
, it is used to annotate a class and indicates that the instance will be a releasable singleton. -
@InjectConstructor
can be used to annotate a class, it's equivalent to annotate its primary constructor with@Inject
.
As you can see from the above examples there is a new Kotlin API. You can find more here: KTP