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.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: contributor-docs/components/dependencies.md
+182-1Lines changed: 182 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -3,5 +3,186 @@ parent: Firebase Components
3
3
---
4
4
5
5
# Dependencies
6
+
{: .no_toc}
6
7
7
-
TODO
8
+
1. TOC
9
+
{:toc}
10
+
11
+
This page gives an overview of the different dependency types supported by the Components Framework.
12
+
13
+
## Background
14
+
15
+
As discussed in [Firebase Components]({{ site.baseurl }}{% link components/components.md %}), in order
16
+
for a `Component` to be injected with the things it needs to function, it has to declare its dependencies.
17
+
These dependencies are then made available and injected into `Components` at runtime.
18
+
19
+
Firebase Components provide different types of dependencies.
20
+
21
+
## Lazy vs Eager dependencies
22
+
23
+
When it comes to initialize a component, there are 2 ways of provide its dependencies.
24
+
25
+
### Direct Injection
26
+
27
+
With this type of injection, the component gets an instance of its dependency directly.
28
+
29
+
```kotlin
30
+
classMyComponent(privatevaldep:MyDep) {
31
+
funsomeMethod() {
32
+
dep.use();
33
+
}
34
+
}
35
+
```
36
+
37
+
As you can see above the component's dependency is passed by value directly,
38
+
which means that the dependency needs to be fully initialized before
39
+
it's handed off to the requesting component. As a result `MyComponent` may have to pay the cost
40
+
of initializing `MyDep` just to be created.
41
+
42
+
### Lazy/Provider Injection
43
+
44
+
With this type of injection, instead of getting an instance of the dependency directly, the dependency
45
+
is passed into the `Component` with the help of a `com.google.firebase.inject.Provider`
46
+
47
+
```java
48
+
publicinterfaceProvider<T> { Tget(); }
49
+
```
50
+
51
+
```kotlin
52
+
classMyComponent(privatevaldep:Provider<MyDep>) {
53
+
funsomeMethod() {
54
+
// Since all components are singletons, each call to
55
+
// get() will return the same instance.
56
+
dep.get().use();
57
+
}
58
+
}
59
+
```
60
+
61
+
On the surface this does not look like a big change, but it has an important side effect. In order to create
62
+
an instance of `MyComponent`, we don't need to initialize `MyDep` anymore. Instead, initialization can be
63
+
delayed until `MyDep` is actually used.
64
+
65
+
It is also benefitial to use a `Provider` in the context of [Play's dynamic feature delivery](https://developer.android.com/guide/playcore/feature-delivery).
66
+
See [Dynamic Module Support]({{ site.baseurl }}{% link components/dynamic_modules.md %}) for more details.
67
+
68
+
## Required dependencies
69
+
70
+
This type of dependency informs the `ComponentRuntime` that a given `Component` cannot function without a dependency.
71
+
When the dependency is missing during initialization, `ComponentRuntime` will throw a `MissingDependencyException`.
72
+
This type of dependency is useful for built-in components that are always present like `Context`, `FirebaseApp`,
73
+
`FirebaseOptions`, [Executors]({{ site.baseurl }}{% link components/executors.md %}).
74
+
75
+
To declare a required dependency use one of the following in your `ComponentRegistrar`:
The provider will return `null` if the dependency is not present in the app.
101
+
102
+
{: .warning }
103
+
When the app uses [Play's dynamic feature delivery](https://developer.android.com/guide/playcore/feature-delivery),
104
+
`provider.get()` will return your dependency when it becomes available. To support this use case, don't store references to the result of `provider.get()` calls.
105
+
106
+
See [Dynamic Module Support]({{ site.baseurl }}{% link components/dynamic_modules.md %}) for details
107
+
108
+
{: .warning }
109
+
See Deferred dependencies if you your dependency has a callback based API
110
+
111
+
## Deferred Dependencies
112
+
113
+
Useful for optional dependencies which have a listener-style API, i.e. the dependent component registers a
114
+
listener with the dependency and never calls it again (instead the dependency will call the registered listener).
115
+
A good example is `Firestore`'s use of `Auth`, where `Firestore` registers a token change listener to get
116
+
notified when a new token is available. The problem is that when `Firestore` initializes, `Auth` may not be
117
+
present in the app, and is instead part of a dynamic module that can be loaded at runtime on demand.
118
+
119
+
To solve this problem, Components have a notion of a `Deferred` dependency. A deferred is defined as follows:
120
+
121
+
```java
122
+
publicinterfaceDeferred<T> {
123
+
interfaceDeferredHandler<T> {
124
+
@DeferredApi
125
+
voidhandle(Provider<T>provider);
126
+
}
127
+
128
+
voidwhenAvailable(DeferredHandler<T>handler);
129
+
}
130
+
```
131
+
132
+
To use it a component needs to call `Dependency.deferred(SomeType.class)`:
133
+
134
+
```kotlin
135
+
classMyComponent(deferred:Deferred<SomeType>) {
136
+
init {
137
+
deferred.whenAvailable { someType ->
138
+
someType.registerListener(myListener)
139
+
}
140
+
}
141
+
}
142
+
```
143
+
144
+
See [Dynamic Module Support]({{ site.baseurl }}{% link components/dynamic_modules.md %}) for details
145
+
146
+
## Set Dependencies
147
+
148
+
The Components Framework allows registering components to be part of a set, such components are registered explicitly to be a part of a `Set<T>` as opposed to be a unique value of `T`:
0 commit comments