Magnet

General

Category
Free
Tag
Dependency Injections
License
N/A
Registered
Jul 22, 2018
Favorites
0
Link
https://github.com/beworker/magnet
See also
DecleX
Shortbread
DaggerBinds
Michelangelo
Dart

Additional

Language
Java
Version
3.2 (Jul 1, 2019)
Created
Feb 28, 2018
Updated
Oct 17, 2019
Owner
Sergej Shafarenka (beworker)
Contributors
Sergej Shafarenka (beworker)
tbsandee
realdadfish
3
Activity
Badge
Generate
Download
Source code
APK file

Announcement

Magnet is a concise dependency injection and dependency inversion library for Android, designed for highly modular applications. Magnet operates on hierarchical dependency scopes where a child scope extends its parent scope by keeping a reference to it.

An instance is typically injected within a scope. Instance can depend on other instances whithin the same or a parent scope. Magnet will take care for injecting and keeping the instance in the right scope, where all required instance dependencies can be satisfied. Thus you don't have to declare any modules and componets, and then bind them together. You just define dependencies in your class constructor, optionally declare how to scope the instance and Magnet will do the rest.

Here is a slightly simplified example of how Magnet would build Dagger's coffe maker.

interface Pump
interface Heater

@Instance(type = Pump::class)
internal class Thermosiphon(private val heater: Heater) : Pump

@Instance(type = Heater::class)
internal class ElectricHeater(): Heater

@Instance(type = CoffeeMaker::class)
class CoffeeMaker(
   private val heater: Heater,
   private val pump: Pump
)

val scope = Magnet.createScope()
val coffeeMaker: CoffeeMaker = scope.getSingle()

This desing makes dependency injection so easy that it becomes hard not to use it.

Unique features

  1. Magnet does not force you to use any generated classes in your code. This dramatically improves user experience when code does not compile due to an error. Delevoper will see a single error at a single location and not hundreds of errors at all places, where generated code is referenced. If you used dagger, you know what I mean.

  2. Magnet is capable of injecting annotated classes from compiled libraries. This means you can extend funtionality of your application by just adding libraries as a dependency to the compilation. No source modification is necessary. See how magnetx-app-leakcanary and magnetx-app-rxandroid leverage this feature.

  3. Magnet has a concept of extensible declarative injection selectors, which gives you additional control over when instances should be injected and when not. The example down below injects AudioFocusImplLegacy implementation of AudioFocus interface, if current Android API level is less than 26 and AudioFocusImpl26 one otherwise.

interface AudioFocus

@Instance(
    type = AudioFocus::class,
    selector = "android.api < 26"
)
internal class AudioFocusLegacy : AudioFocus

@Instance(
    type = AudioFocus::class,
    selector = "android.api >= 26"
)
internal class AudioFocusV26: AudioFocus

val scope = Magnet.createScope()
val audioFocus: AudioFocus = scope.getSingle()

Custom selectors are easy to write. For more details checkout magnetx-selector-android or magnetx-selector-features modules.

  1. Magnet supports dependency inversion between app modules. See sample app for more detail.

Documentation

  1. Developer Guide
  2. Sample application
  3. Dependency Inversion
  4. Hierarchical Scopes
  5. How to inject Android ViewModels
  6. Magnet – an alternative to Dagger

Scope inspection

Dynamic instance binding into scopes is the power of Magnet, which comes with its costs - a necessity to see how instances are allocated at runtime. Fortunately Magnet has an easy to use Stetho powered scope dumper extension for this purpose. See this Wiki page to learn how to configure and use it.

Gradle

Kotlin

repositories {
    mavenCentral()
}
dependencies {
    api 'de.halfbit:magnet-kotlin:<version>'
    kapt 'de.halfbit:magnet-processor:<version>'
}

Java

repositories {
    mavenCentral()
}
dependencies {
    api 'de.halfbit:magnet:<version>'
    annotationProcessor 'de.halfbit:magnet-processor:<version>'
}

Proguard & R8

-keep class magnet.internal.MagnetIndexer { *; }

License

Copyright 2018-2019 Sergej Shafarenka, www.halfbit.de

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.