139 lines
4.9 KiB
Markdown
139 lines
4.9 KiB
Markdown
# Dagger 2 in SystemUI
|
|
*Dagger 2 is a dependency injection framework that compiles annotations to code
|
|
to create dependencies without reflection*
|
|
|
|
## Recommended reading
|
|
|
|
Go read about Dagger 2.
|
|
|
|
- [User's guide](https://google.github.io/dagger/users-guide)
|
|
|
|
## State of the world
|
|
|
|
Dagger 2 has been turned on for SystemUI and much of
|
|
[Dependency.java](../src/com/android/systemui/Dependency.java)
|
|
has been converted to use Dagger. Since a lot of SystemUI depends on Dependency,
|
|
stubs have been added to Dependency to proxy any gets through to the instances
|
|
provided by dagger, this will allow migration of SystemUI through a number of CLs.
|
|
|
|
### How it works in SystemUI
|
|
|
|
There are three high level "scopes" of concern in SystemUI. They all represent
|
|
singleton scopes, but serve different purposes.
|
|
|
|
* `@Singleton` - Instances that are shared everywhere. There isn't a lot of
|
|
code in this scope. Things like the main thread, and Android Framework
|
|
provided instances mostly.
|
|
* `@WMShell` - WindowManager related code in the SystemUI process. We don't
|
|
want this code relying on the rest of SystemUI, and we don't want the rest
|
|
of SystemUI peeking into its internals, so it runs in its own Subcomponent.
|
|
* `@SysUISingleton` - Most of what would be considered "SystemUI". Most feature
|
|
work by SystemUI developers goes into this scope. Useful interfaces from
|
|
WindowManager are made available inside this Subcomponent.
|
|
|
|
The root dagger graph is created by an instance of `SystemUIInitializer`.
|
|
See [README.md](../README.md) for more details.
|
|
For the classes that we're using in Dependency and are switching to dagger, the
|
|
equivalent dagger version is using `@Singleton` and therefore only has one instance.
|
|
To have the single instance span all of SystemUI and be easily accessible for
|
|
other components, there is a single root `@Component` that exists that generates
|
|
these. The component lives in
|
|
[ReferenceGlobalRootComponent.java](../src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java).
|
|
|
|
### Adding a new injectable object
|
|
|
|
First annotate the constructor with `@Inject`. Also annotate it with
|
|
`@SysUISingleton` if only one instance should be created.
|
|
|
|
```kotlin
|
|
@SysUISingleton
|
|
class FeatureStartable
|
|
@Inject
|
|
constructor(
|
|
/* ... */
|
|
) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
If you have an interface class and an implementation class, Dagger needs to
|
|
know how to map it. The simplest way to do this is to add an `@Binds` method
|
|
in a module. The type of the return value tells dagger which dependency it's
|
|
providing:
|
|
|
|
```kotlin
|
|
@Module
|
|
abstract class FeatureModule {
|
|
@Binds
|
|
abstract fun bindsFeature(impl: FeatureImpl): Feature
|
|
}
|
|
```
|
|
|
|
If you have a class that you want to make injectable that has can not
|
|
be easily constructed by Dagger, write a `@Provides` method for it:
|
|
|
|
```kotlin
|
|
@Module
|
|
abstract class FeatureModule {
|
|
@Module
|
|
companion object {
|
|
@Provides
|
|
fun providesFeature(ctx: Context): Feature {
|
|
return FeatureImpl.constructFromContext(ctx)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Module Organization
|
|
|
|
Please define your modules on _at least_ per-package level. If the scope of a
|
|
package grows to encompass a great number of features, create per-feature
|
|
modules.
|
|
|
|
**Do not create catch-all modules.** Those quickly grow unwieldy and
|
|
unmaintainable. Any that exist today should be refactored into obsolescence.
|
|
|
|
You can then include your module in one of three places:
|
|
|
|
1) Within another module that depends on it. Ideally, this creates a clean
|
|
dependency graph between features and utilities.
|
|
2) For features that should exist in all versions of SystemUI (AOSP and
|
|
any variants), include the module in
|
|
[SystemUIModule.java](../src/com/android/systemui/dagger/SystemUIModule.java).
|
|
3) For features that should exist only in AOSP, include the module in
|
|
[ReferenceSystemUIModule.java](../src/com/android/systemui/dagger/ReferenceSystemUIModule.java).
|
|
Similarly, if you are working on a custom version of SystemUI and have code
|
|
specific to your version, include it in a module specific to your version.
|
|
|
|
### Using injection with Fragments
|
|
|
|
Fragments are created as part of the FragmentManager, so they need to be
|
|
setup so the manager knows how to create them. To do that, add a method
|
|
to com.android.systemui.fragments.FragmentService$FragmentCreator that
|
|
returns your fragment class. That is all that is required, once the method
|
|
exists, FragmentService will automatically pick it up and use injection
|
|
whenever your fragment needs to be created.
|
|
|
|
```java
|
|
public interface FragmentCreator {
|
|
NavigationBarFragment createNavigationBar();
|
|
}
|
|
```
|
|
|
|
If you need to create your fragment (i.e. for the add or replace transaction),
|
|
then the FragmentHostManager can do this for you.
|
|
|
|
```java
|
|
FragmentHostManager.get(view).create(NavigationBarFragment.class);
|
|
```
|
|
|
|
## Updating Dagger2
|
|
|
|
We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates
|
|
when that repository is updated.
|
|
|
|
## TODO List
|
|
|
|
- Eliminate usages of Dependency#get: http://b/hotlists/3940788
|