Simple Service Locator Library

Overview

ScrapServiceLocator

A small, asynchronous IoC library for Android that might be half compile-time safe (?)

Before I start, I'm very poor at English, so please forgive the parts of the README that may not be properly understood.

Although strongly influenced by Koin,

I made it because it was too cumbersome to manually change module dependency definitions one by one in code that changes hundreds of lines a day.

Hilt also exists as an option, but

  1. I hate lateinit,
  2. It is cumbersome to annotate each component that needs to be injected with @Inject.
  3. It was unbearable for all component classes to be initialized on the main thread.
  4. It was a waste of time to touch the bytecode for an apk over 100MB at compile time.

So, as a simple trick using kapt , I wanted to make the dependency injection structure as simple as possible.

How to use ( Gradle Settings )

  1. Add it in your root build.gradle at the end of repositories:
	allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}
  1. Add Depdendencies in Your application level build.gradle

Release

plugins {
...
    id 'kotlin-kapt'
}

android {

...
// If you are using `serviceLocator-Android` you need to enable ViewBinding.
    buildFeatures {
        viewBinding = true
    }
}

// The corresponding kapt option is required by all modules. 
// If you are too lazy to write this down, please refer to `kapt_sample.gradle` in the repository. It might be helpful.
kapt {
    arguments {
        arg("moduleName", 'Your module-specific class name')
    }
}

dependencies {
    def latest_version = '0.0.4.5-alpha'
...
    implementation "com.github.heukhyeon:scrap_service_locator:$latest_version"
    implementation "com.github.heukhyeon:scrap_service_locator_android:$latest_version"
    kapt "com.github.heukhyeon:scrap_service_locator:$latest_version"
    
    // The dependencies below are optional. Please refer to the wiki for what each role does.
    implementation "com.github.heukhyeon:scrap_service_locator_android_viewbinding:$latest_version"
    implementation "com.github.heukhyeon:scrap_service_locator_android_fragment:$latest_version"
    implementation "com.github.heukhyeon:scrap_service_locator_android_recyclerview:$latest_version"
}

How to Use (in Kotlin)

I think it would be good if you take a look around the sample project.

The basic dependency injection method is the same as that of Koin.

For classes that cannot control the constructor (activities, fragments, etc.), use the inject() delegate function,

class SampleActivity : AppCompatActivity(), AndroidInitializer {

   ...
    private val presenter by inject(SamplePresenter::class)
}

Classes that can control constructors (most classes) use constructor injection.

class SamplePresenter(
    private val sampleRepository: SampleRepository // Interface.
) {
  ...
}

Okay, will you look pretty? What more should we do here?

Let me explain it step by step.

1. All classes that need to be injected must be annotated with @Component.

In the example above, SamplePresenter should be injected into SampleActivity, so it should be annotated with @Component.

import kr.heukhyeon.service_locator.Component

@Component
class SamplePresenter(
    private val sampleRepository: SampleRepository
) {
  ...
}

With some exceptions, all classes included in the constructor of a class annotated with @Component must be annotated with @Component.

Taking the above example again, would SampleRepository also need the @Component annotation?

2. Instead of adding @Component annotation to the interface, add @Component annotation to the class to be injected.

// Types referenced in the presentation layer
interface SampleRepository {
    fun getTestText(): String
    suspend fun putLatestClickedTime() : String
}

// A data layer class that is actually injected, but does not exist in the Presentation Layer
class SampleRepositoryImpl : SampleRepository {

    private val time = System.currentTimeMillis()
    private var latestClickedTime : Long? = null

    override fun getTestText(): String {
        // BLABLA...
    }

    override suspend fun putLatestClickedTime(): String {
        // BLABLA...
    }
}

The implementation of SampleRepository must exist at runtime, but on the contrary, its higher layer (such as Presenter or Activity) must not know about its existence.

So while annotating @Component, we add a few extras.

@Component(scope = ComponentScope.IS_SINGLETON, bind = SampleRepository::class)
class SampleRepositoryImpl : SampleRepository {
}
  • scope : Set the caching policy for requests for the same type of component.

    • SHARED_IF_EQUAL_OWNER : This is the default. Components with the same ComponentOwner share components.
    • IS_SINGLETON : Once created, an object is returned for every request during the application cycle.
    • NOT_CACHED : Whenever a request comes in, a new object is created. Don't use it except in cases like RecyclerView.ViewHolder.
  • bind : Specifies what type of class this class will be returned for dependency requests.

The default value is returned only when requesting a dependency on itself (SampleRepositoryImpl).

3. Add @ApplicationEntryPoint annotation to your Application class and call RootInjector.initialize(this) at onCreate time.

// You don't necessarily have to implement AndroidInitializer in your Application.
// This is explained in wiki
@ApplicationEntryPoint
class SampleApp : Application(), AndroidInitializer {

...
    override fun onCreate() {
        super.onCreate()
        // IMPORTANT
        RootInjector.initialize(this)
	// If you are using the `service_locator_android` library, you must call this.
	InjectLifecycleManager.initialize(this)
        startInitialize()
    }
}

4. Move your initialization logic after overriding the onInitialize function.

class SampleActivity : AppCompatActivity(), AndroidInitializer {

    private val presenter by inject(SamplePresenter::class)
    private val binding by inject(ActivitySampleBinding::class)

...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sample_loading)

        // AS-IS, BAD !!!!
        onInit()
    }

    override suspend fun onInitialize() {
        super.onInitialize()
        withContext(Dispatchers.Main) {

            // TO-BE, GOOD!
            onInit()
        }
    }

    // My Initialize Function
    private fun onInit() {
        binding.textView.text = presenter.getTestText()
        binding.updateButtonView.setOnClickListener {
            binding.updateButtonView.isEnabled = false
            binding.loadingView.visibility = View.VISIBLE
            getCoroutineScope().launch {
                updateTime()
            }
        }
    }

...

5. If you are using proguard, add the following statement to your proguard rules.

-keepclassmembers class * extends kr.heukhyeon.service_locator.RootInjector {
    public <init>(android.content.Context);
}

More details that are not explained in the above and sample projects are described in the Wiki.

You might also like...
Simple Android Library, that provides easy way to start the Activities with arguments.

Warning: Library is not maintained anymore. If you want to take care of this library, propose it via Pull Request. It needs adjustmensts for newer ver

🚟 Lightweight, and simple scheduling library made for Kotlin (JVM)
🚟 Lightweight, and simple scheduling library made for Kotlin (JVM)

Haru 🚟 Lightweight, and simple scheduling library made for Kotlin (JVM) Why did you build this? I built this library as a personal usage library to h

A lightweight and simple Kotlin library for deep link handling on Android 🔗.

A lightweight and simple Kotlin library for deep link handling on Android 🔗.

This library is a set of simple wrapper classes that are aimed to help you easily access android device information.
This library is a set of simple wrapper classes that are aimed to help you easily access android device information.

SysInfo Simple, single class wrapper to get device information from an android device. This library provides an easy way to access all the device info

A lightweight, simple, smart and powerful Android routing library.

RxRouter Read this in other languages: 中文, English A lightweight, simple, smart and powerful Android routing library. Getting started Setting up the d

Very simple Kotlin caching library
Very simple Kotlin caching library

Very simple Kotlin caching library

 A Kotlin library providing a simple, high-performance way to use off-heap native memory in JVM applications.
A Kotlin library providing a simple, high-performance way to use off-heap native memory in JVM applications.

native_memory_allocator A library which uses sun.misc.Unsafe to allocate off-heap native memory. Motivation The goal of this project is to provide a s

[Android Library] A SharedPreferences helper library to save and fetch the values easily.

Preference Helper A SharedPreferences helper library to save and fetch the values easily. Featured in Use in your project Add this to your module's bu

Simple(vanilla) yet 'Do it all' place picker for your place picking needs in Android
Simple(vanilla) yet 'Do it all' place picker for your place picking needs in Android

Vanilla Place Picker Vanilla Place Picker provides a UI that displays an interactive map to get the place details and Autocomplete functionality, whic

Releases(0.0.4.6-alpha)
Owner
HyungWoo Kim
HyungWoo Kim
Account-Touch is a simple account-sharing service.

account-touch A-Touch is a simple account-sharing service. feature user & permission Create an user with a nickname and emoji account You can see the

Euphony 2 Aug 4, 2022
Location Service Manager for Kotlin Multiplatform Mobile iOS and android

Location Service Manager for Kotlin Multiplatform Mobile iOS and android Features Provides simple permission settings Dramatically reduce the amount o

LINE 55 Dec 10, 2022
Example of migrating from Dagger to Hilt with a real service/repository example

DaggerToHilt Overview This repo provides a real example of using Hilt for dependency injection. It hits endpoints provided by the Movie Database, and

null 0 Nov 29, 2021
Survey-service - Application for creating online surveys and polls

Survey Service Application for creating online surveys and polls Functionality A

Anatoly Babushkin 2 Apr 6, 2022
Link-converter - A web service that converts links between web url and deeplink for mobile and web applications

Deep Link Converter Linkleri, mobil ve web uygulamaları için web url ile deeplin

Muhammed Eren DURSUN 2 Apr 9, 2022
Android app of LINDAT translation service

Charles Translator Android app of LINDAT translation service For now just translate Czech <-> Ukrainian, but if future will be more languages Architec

ÚFAL 2 Jun 7, 2022
NewsAppKt is an Android app designed for searching news using TheGuardianOpenPlatform public web service.

NewsAppKt is an updated version of NewsApp. It is written entirely in Kotlin and uses MVVM with Clean Architecture practices. The UI implementation uses Jetpack Compose.

Daniel Bedoya 2 Sep 22, 2022
Android app using Kotlin to manage to-do notes with firebase as backend service

TO-DO Manager TO-DO Manager is a simple note management app. Unlike other apps, TO-DO Manager is free and open source. You can access your nots from a

Ahmed Badr 3 Dec 10, 2022
A simple library that can connect your autocomplete edittext to Google places api

Google Places AutoComplete EditText A simple library that can connect your autocomplete edittext to Google's places api Supporting Places AutoComplete

Mukesh Solanki 71 Dec 28, 2022
Simple android library to present an animated ferris wheel

Ferris Wheel View Overview An Android Library used to implement an animated Ferris Wheel in android. API SDK 15+ Written in Kotlin Supports landscape

Igor Lashkov 318 Dec 7, 2022