This simplifies the dagger initilization, removing constructs that provided no value to the process, but did serve to make the code more complex to analyze. Update dagger.md while we're here. Fixes: 161911916 Test: manual Change-Id: I84ced47d7cd6ce90664b68339acb7d7db765d56f
171 lines
6.4 KiB
Markdown
171 lines
6.4 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)
|
|
|
|
TODO: Add some links.
|
|
|
|
## State of the world
|
|
|
|
Dagger 2 has been turned on for SystemUI and a early first pass has been taken
|
|
for converting everything in [Dependency.java](packages/systemui/src/com/android/systemui/Dependency.java)
|
|
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
|
|
|
|
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 [SystemUIFactory](packages/systemui/src/com/android/systemui/SystemUIFactory.java)
|
|
and is called `SystemUIRootComponent`.
|
|
|
|
```java
|
|
|
|
@Singleton
|
|
@Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class,
|
|
ContextHolder.class})
|
|
public interface SystemUIRootComponent {
|
|
@Singleton
|
|
Dependency.DependencyInjector createDependency();
|
|
}
|
|
```
|
|
|
|
The root component is composed of root modules, which in turn provide the global singleton
|
|
dependencies across all of SystemUI.
|
|
|
|
- `SystemUIFactory` `@Provides` dependencies that need to be overridden by SystemUI
|
|
variants (like other form factors e.g. Car).
|
|
|
|
- `DependencyBinder` creates the mapping from interfaces to implementation classes.
|
|
|
|
- `DependencyProvider` provides or binds any remaining depedencies required.
|
|
|
|
### Adding injection to a new SystemUI object
|
|
|
|
SystemUI object are made injectable by adding an entry in `SystemUIBinder`. SystemUIApplication uses
|
|
information in that file to locate and construct an instance of the requested SystemUI class.
|
|
|
|
### Adding a new injectable object
|
|
|
|
First tag the constructor with `@Inject`. Also tag it with `@Singleton` if only one
|
|
instance should be created.
|
|
|
|
```java
|
|
@Singleton
|
|
public class SomethingController {
|
|
@Inject
|
|
public SomethingController(Context context,
|
|
@Named(MAIN_HANDLER_NAME) Handler mainHandler) {
|
|
// context and mainHandler will be automatically populated.
|
|
}
|
|
}
|
|
```
|
|
|
|
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 `@Provides` method to
|
|
DependencyProvider. The type of the return value tells dagger which dependency it's providing.
|
|
|
|
```java
|
|
public class DependencyProvider {
|
|
//...
|
|
@Singleton
|
|
@Provides
|
|
public SomethingController provideSomethingController(Context context,
|
|
@Named(MAIN_HANDLER_NAME) Handler mainHandler) {
|
|
return new SomethingControllerImpl(context, mainHandler);
|
|
}
|
|
}
|
|
```
|
|
|
|
If you need to access this from Dependency#get, then add an adapter to Dependency
|
|
that maps to the instance provided by Dagger. The changes should be similar
|
|
to the following diff.
|
|
|
|
```java
|
|
public class Dependency {
|
|
//...
|
|
@Inject Lazy<SomethingController> mSomethingController;
|
|
//...
|
|
public void start() {
|
|
//...
|
|
mProviders.put(SomethingController.class, mSomethingController::get);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 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. Thats all thats 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);
|
|
```
|
|
|
|
### Using injection with Views
|
|
|
|
DO NOT ADD NEW VIEW INJECTION. VIEW INJECTION IS BEING ACTIVELY DEPRECATED.
|
|
|
|
Needing to inject objects into your View's constructor generally implies you
|
|
are doing more work in your presentation layer than is advisable.
|
|
Instead, create an injected controller for you view, inject into the
|
|
controller, and then attach the view to the controller after inflation.
|
|
|
|
View injection generally causes headaches while testing, as inflating a view
|
|
(which may in turn inflate other views) implicitly causes a Dagger graph to
|
|
be stood up, which may or may not contain the appropriately
|
|
faked/mocked/stubbed objects. It is a hard to control process.
|
|
|
|
## Updating Dagger2
|
|
|
|
We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates
|
|
when that repository is updated.
|
|
|
|
*Deprecated:*
|
|
|
|
Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded
|
|
into
|
|
[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/)
|
|
|
|
The following commands should work, substituting in the version that you are looking for:
|
|
|
|
````
|
|
cd prebuilts/tools/common/m2/repository/com/google/dagger/
|
|
|
|
wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger/2.28.1/
|
|
|
|
wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.28.1/
|
|
|
|
wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-spi/2.28.1/
|
|
|
|
wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.28.1/
|
|
````
|
|
|
|
Then update `prebuilts/tools/common/m2/Android.bp` to point at your new jars.
|
|
|
|
## TODO List
|
|
|
|
- Eliminate usages of Dependency#get
|
|
- Add links in above TODO
|