Last active
November 29, 2024 09:31
-
-
Save murki/7c99e2d011c663deb25267e5462cc02d to your computer and use it in GitHub Desktop.
The poor man's Dagger: Exemplifying how to implement dependency injection on Android by (ab)using ApplicationContext's getSystemService(). Here we attain inversion of control without the need of any external library. We also use Kotlin's extension methods to provide a friendlier, strongly-typed API to locate dependencies.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PlacesActivity : AppCompatActivity() { | |
private lateinit var placesPresenter: PlacesPresenter | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
// This is how you instantiate your Presenter while the service locator resolves all of its dependencies | |
// Note that the explicit type argument <PlacesPresenter> is not even necessary since Kotlin can infer the type | |
placesPresenter = application.getSystemService<PlacesPresenter>() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ServiceLocatorApplication : Application() { | |
/** | |
* Dependency injection using service locator pattern | |
*/ | |
override fun getSystemService(name: String?): Any { | |
// All this logic can be extracted into a separate "Module" class | |
return when (name) { | |
// We use the full class' name as the key | |
PlacesPresenter::class.java.name -> PlacesPresenter(getSystemService<ILocationRepository>(), getSystemService<IPlacesRepository>()) | |
ILocationRepository::class.java.name -> GmsLocationRepository(getSystemService<FusedLocationProviderClient>()) | |
IPlacesRepository::class.java.name -> GmsPlacesRepository(getSystemService<GeoDataClient>()) | |
FusedLocationProviderClient::class.java.name -> LocationServices.getFusedLocationProviderClient(this) | |
GeoDataClient::class.java.name -> Places.getGeoDataClient(this, null) | |
else -> super.getSystemService(name) | |
} | |
} | |
} | |
/** | |
* Generic strongly-typed extension method for injection | |
*/ | |
inline fun <reified T : Any> Application.getSystemService() : T { | |
// We extract the class name from the generic type | |
return this.getSystemService(T::class.java.name) as T | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As an addition you can override the Activity's base context to have an acitivity scope.