Introduction
If you don´t know why dependency injection? You can first start here.
-
Why Kinject?
Dependency injection frameworks are nothing new, in Android Dagger or more recently Dagger2 are well known examples (even some Kinject concepts are based on them).
Kinject has been thought to get the following objectives:
- Ease to configure.
- Clean way to satisfy dependencies.
- High performance without lose flexibility.
- Integration little intrusive and easily abstractable.
- Dependencies graph validation in compilation time.
- Based on code generation.
- Proguard friendly.
Using Kinject
The flow is simple, define your dependencies and inject them!
-
Defining dependencies
Use a
@Provides
annotated method to define a dependency. The method’s return type define which dependency it satisfies.
For example,provideHeater()
is invoked whenever aHeater
is required:@Provides public Heater provideHeater() { return new EletricalHeater(); }
Is possible for
@Provides
methods to have dependencies of their own.@Provides public Pump providePump(Heater heater) { return new Thermosiphon(heater); }
All
@Provides
annotated methods must belong to a@Module
annotated class.@Module public class HeaterModule { @Provides public Heater provideHeater() { return new ElectricalHeater(); } }
-
Building the Graph
Before you can inject dependencies, you must define and load a graph. You can understand a graph as a set of injectables dependencies (defined by
@Provides
annotation) at the same time, linked to other dependencies.
In code, you have to set the graph root@Module
annotation ascompleted = true
.@Module(completed = true) public class CoffeeMakerModule { }
You can lean on
@Includes
annotation to define more flexible graphs. With@Includes
you can define modules componses by other modules. Each dependency defined in the included module will be part of the final graph.@Module(completed = true) public class CoffeeMakerModule { @Includes public HeaterModule includeHeaterModule() { return new HeaterModule(); } }
An implementation of
ModuleMapper
(Kinject needs it to load the graph), will be generated by each graph. That is named as the graph root module ended with Mapper.@Generated("com.wokdsem.kinject.codegen.CodeGen") public final class CoffeeMakerModuleMapper implements ModuleMapper { public static ModuleMapper from(CoffeeMakerModule coffeeMakerModule) { } }
Now, you can initialize your injector and request dependencies.
// Create injector ModuleMapper moduleMapper = CoffeeMakerModuleMapper.from(new CoffeeMakerModule()); Kinject injector = Kinject.instantiate(moduleMapper); // Injecting Heater heater = injector.get(Heater.class);
-
Aditional features
-
Scope Kinject provides the following scopes:
- NONE A new instance is created when the dependency is requested. This is the default behavior when no scope is defined.
- SINGLETON The injector provides the same instance for all injection requests of the dependency.
- WEAK_SINGLETON While a previous dependency instance is still referenced, then, like a singleton, the same instance is shared. In other cases, a new instance is created.
@Provides(scope = SINGLETON) public Heater provideHeater() { return new ElectricalHeater(); }
-
Named When the type isn’t enought to identify a dependency, you can set
named
field in@Provides
annotation. By default, all dependencies have an empty named value.Use
Kinject.get(Class<T> tClass, String named)
to inject a named dependency.@Provides(named = "Application") public Context provideApplicationContext() { return appContext; }
-
Compile-Time
-
Validation
The Kinject annotation processor throws a compiler error if any graph has an invalid state. For example, this completed module doesn’t know the
Logger
dependency.@Module(completed = true) public class CoffeeMakerModule { @Provides public void CoffeeMaker provideCoffeeMaker(Logger logger) { return new LogCoffeeMaker(logger); } }
When compiling it,
javac
rejects something like:[[ KINJECT : ERROR ]] Unknown dependency(Logger@) on @Provides(CoffeeMaker@) building graph(CoffeeMakerModule).
-
Code Generation
Kinject annotation processor generates source files with names ended like
*Adapter.java
or*Mapper.java
. These files are Kinject implementation details and you shouldn’t edit them. Maybe they are usefull when you are debugging an injection.
Proguard
- Kinject is Proguard friendly, you don’t need to do anything.
Additional android notes
- Perhaps you would need to set up
android.compileOptions.incremental = false
in the app build file if you are having issues while compiling.
Installation
-
Status
- Release version: 1.3.0
-
Download
-
You will need to include the
kinject-${kinject.version}.jar
in your application’s runtime. -
In order to activate code generation, you will need to include
kinject-compiler-${kinject.version].jar
in your build at compile time. - In a gradle project, include the
kinject
artifact in the dependencies section of yourbuild.gradle
and thekinject-compiler
artifact asprovided
dependency:dependencies { compile 'com.wokdsem.kinject:kinject:${kinject.version}' provided 'com.wokdsem.kinject:kinject-compiler:${kinject.version}' }
- You can also find downloadable .jars on jCenter. Kinject / Kinject-Compiler.
-
License
Copyright 2017 Wokdsem
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.