Utiliser koin comme outil d'injection Android

Mots clés:

koin fournit une interface API facile à utiliser pour Android , vous permettant d'accéder facilement au framework koin.

[configuration progressive de koin dans Android]

mp.weixin.qq.com/s/bscC7mO4O…

1. startKoin dans la classe Application

Depuis votre classe, vous pouvez utiliser la fonction et injecter le contexte Android comme ceci :

Application startKoin androidContext
class MainApplication : Application() 
override fun onCreate() 
    super.onCreate()

    startKoin 
        // Log Koin into Android logger
        androidLogger()
        // Reference Android context
        androidContext(this@MainApplication)
        // Load modules
        modules(myAppModules)

Si vous avez besoin de démarrer Koin à partir d'une autre classe Android, vous pouvez utiliser cette fonction pour fournir votre instance Android comme suit :startKoin Context

startKoin 
    //inject Android context
    androidContext(/* your android context */)
    // ...

2. Configuration supplémentaire

Depuis votre configuration Koin (en code bloc), vous pouvez également configurer différentes parties de Koin.startKoin

2.1 Koin Logging pour Android

koin fournit une implémentation Android de log.

startKoin 
    // use Android logger - Level.INFO by default
    androidLogger()
    // ...

2.2 Charger les propriétés

Vous pouvez utiliser les propriétés Koin pour stocker les clés/valeurs dans le fichier : assets/koin.properties

startKoin 
    // ...
    // use properties from assets/koin.properties
    androidFileProperties()

3. Injecter une instance d'objet dans Android

3.1 Préparation pour le cours Android

koin fournit KoinComponentsdes extensions, qui sont disponibles pour les composants Android, y comprisActivity Fragment Service ComponentCallbacks

Vous pouvez accéder aux extensions Kotlin comme suit :

by inject()- Instance de calcul paresseux du conteneur Koin

get()- Obtenir une instance du conteneur Koin

Nous pouvons déclarer qu'une propriété est injectée paresseusement :

module 
    // definition of Presenter
    factory  Presenter() 

classe DetailActivity : AppCompatActivity()

// Lazy inject Presenter
override val presenter : Presenter by inject()

override fun onCreate(savedInstanceState: Bundle?) 
    //...

Ou nous pouvons obtenir une instance directement :

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
// Retrieve a Presenter instance
val presenter : Presenter = get()

Remarque : Si votre classe n'est pas étendue, ajoutez simplement l'interface KoinComponent si vous avez besoin d'une instance d'une autre classe. injecter() obtenir()

3.2 Utilisation du contexte Android

class MainApplication : Application() 
override fun onCreate() 
    super.onCreate()

    startKoin 
        //inject Android context
        androidContext(this@MainApplication)
        // ...

Dans votre définition, la fonction suivante vous permet d'obtenir des instances dans le module Koin pour vous aider à écrire facilement des expressions qui nécessitent des instances.androidContext() androidApplication() Context Application

val appModule = module 
// create a Presenter instance with injection of R.string.mystring resources from Android
factory 
    MyPresenter(androidContext().resources.getString(R.string.mystring))

4. Constructeurs DSL pour Android

4.1 Constructeurs DSL

Koin fournit désormais un nouveau mot-clé DSL qui vous permet de cibler directement les constructeurs de classe et d'éviter de taper vos définitions dans des expressions lambda.

Pour Android, cela signifie les nouveaux mots-clés DSL constructeur suivants :

viewModelOf()- équivalent àviewModel

fragmentOf()- équivalent àfragment

workerOf()- équivalent àworker

Remarque : Assurez-vous d'utiliser avant le nom de la classe pour localiser le constructeur de la classe : :

4.2 Exemple de fonction Android DSL

Soit une application Android avec les composants suivants :

// A simple service
class SimpleServiceImpl() : SimpleService

// un présentateur, utilisant SimpleService et peut recevoir la classe de paramètres injectée "id"
FactoryPresenter(val id : String, val service : SimpleService)

// un ViewModel qui peut recevoir le paramètre injecté "id", utiliser SimpleService et obtenir
la classe SavedStateHandle SimpleViewModel(val id : String, val service : SimpleService, val handle : SavedStateHandle) : ViewModel()

// une session étendue, qui peut recevoir un lien vers la
session de classe MyActivity (depuis l'étendue) (activité val : MyActivity)

// un Worker, utilisant SimpleService et obtenant
la classe Context & WorkerParameters SimpleWorker(
private val simpleService: SimpleService,
appContext: Context,
private val params: WorkerParameters
) : CoroutineWorker(appContext, params)

On peut les déclarer ainsi :

module 
    singleOf(::SimpleServiceImpl) bind<SimpleService>() 
factoryOf(::FactoryPresenter)

viewModelOf(::SimpleViewModel)

scope&lt;MyActivity&gt;()
    scopedOf(::Session)


workerOf(::SimpleWorker)

5. Utilisation de plusieurs modules koin dans Android

En utilisant Koin, vous pouvez décrire des définitions dans des modules. Dans cette section, nous verrons comment déclarer, organiser et lier des modules.

Multi-module 5.1 koin

Les composants ne doivent pas nécessairement se trouver dans le même module. Les modules sont des espaces logiques qui vous aident à organiser les définitions et peuvent dépendre d'autres modules de définition. Les définitions sont paresseuses et résolues uniquement lorsqu'un composant le demande.

Prenons un exemple où les composants liés sont dans des modules séparés :

// ComponentB <- ComponentA
class ComponentA()
class ComponentB(val componentA : ComponentA)

val moduleA = module
// Singleton ComposantA
single ComposantA()

val moduleB = module
// Singleton ComponentB avec instance liée ComponentA
single ComponentB(get())

Il suffit de déclarer la liste des modules utilisés au démarrage du conteneur Koin :

class MainApplication : Application() 
override fun onCreate() 
    super.onCreate()

    startKoin 
        // ...

        // Load modules
        modules(moduleA, moduleB)

5.2 Contenu du module

Une nouvelle fonction est disponible dans la classe qui permet de combiner des modules en incluant d'autres modules de manière organisée et structuréeincludes() Module

Le nouveau module a 2 caractéristiques exceptionnelles :

Divisez les grands modules en modules plus petits et plus ciblés.

Dans les projets modulaires, il permet un contrôle plus fin de la visibilité des modules (voir exemple ci-dessous).

Comment ça marche? Prenons quelques modules, nous incluons les modules dans : parentModule

// `:feature` module
val childModule1 = module 
    /* Other definitions here. */

val childModule2 = module
/* Autres définitions ici. */

val parentModule = le module
inclut (childModule1, childModule2)

// :appmodule
startKoin modules(parentModule)

Notez que nous n'avons pas besoin de définir explicitement tous les modules : en incluant, tous les modules déclarés seront chargés automatiquement.

parentModule includes childModule1 childModule2 parentModule childModule1 childModule2

INFO : Le chargement des modules est désormais optimisé pour aplatir tous les graphiques de modules et éviter les définitions de modules en double.

Enfin, vous pouvez inclure plusieurs modules imbriqués ou répétés et Koin aplatira tous les modules inclus, supprimant les doublons :

// :feature module
val dataModule = module 
    /* Other definitions here. */

val domainModule = module
/* Autres définitions ici. */

val featureModule1 = le module
inclut(domainModule, dataModule)

val featureModule2 = le module
inclut(domainModule, dataModule)

// :
classe de module d'application MainApplication : Application()

override fun onCreate() 
    super.onCreate()

    startKoin 
        // ...

        // Load modules
         modules(featureModule1, featureModule2)

Notez que tous les modules ne seront inclus qu'une seule fois :dataModule domainModule featureModule1 featureModule2

5.3 Android ViewModel 和 Navigation

Le module Gradle introduit un nouveau mot-clé DSL qui est ajouté pour aider à déclarer et à lier les composants ViewModel au cycle de vie des composants Android. Le mot-clé est également disponible vous permettant de déclarer un ViewModel à l'aide de son constructeur.koin-android viewModel singlefactory viewModelOf

val appModule = module 
// ViewModel for Detail View
viewModel  DetailViewModel(get(), get()) 

// or directly with constructor
viewModelOf(::DetailViewModel)

Le composant déclaré doit étendre au moins la classe. Vous pouvez spécifier comment injecter le constructeur d'une classe et utiliser cette fonction pour injecter des dépendances.android.arch.lifecycle.ViewModel get()

Remarque : le mot-clé aide à déclarer l'instance d'usine de ViewModel. Cette instance sera gérée par la ViewModelFactory interne et rattachera l'instance ViewModel si nécessaire. Il permettra également d'injecter des paramètres.viewModel viewModelOf

5.4 Injecter ViewModel

Utilisez viewModel dans le composant Android,Activity Fragment Service

by viewModel()- Propriétés déléguées paresseuses pour injecter des modèles de vue dans les propriétés

getViewModel()- Obtenez l'instance du modèle de vue directement

class DetailActivity : AppCompatActivity() 
// Lazy inject ViewModel
val detailViewModel: DetailViewModel by viewModel()

5.5 Modèle de vue partagé d'activité

Une instance ViewModel peut être partagée entre un fragment et son activité principale.

Pour injecter le modèle de vue partagé en utilisant : Fragment

by activityViewModel()- Propriétés déléguées paresseuses pour injecter des instances viewModel partagées dans les propriétés

get ActivityViewModel()- Obtenez directement l'instance viewModel partagée

Déclarez simplement le modèle de vue une fois :

val weatherAppModule = module 
// WeatherViewModel declaration for Weather View components
viewModel  WeatherViewModel(get(), get()) 

Remarque : les qualificatifs de viewModel seront traités comme des balises de viewModel

et réutilisez-le dans Activity et Fragment :

class WeatherActivity : AppCompatActivity() 
/*
 * Declare WeatherViewModel with Koin and allow constructor dependency injection
 */
private val weatherViewModel by viewModel&lt;WeatherViewModel&gt;()

classe WeatherHeaderFragment : Fragment()

/*
 * Declare shared WeatherViewModel with WeatherActivity
 */
private val weatherViewModel by activityViewModel&lt;WeatherViewModel&gt;()

classe WeatherListFragment : Fragment()

/*
 * Declare shared WeatherViewModel with WeatherActivity
 */
private val weatherViewModel by activityViewModel&lt;WeatherViewModel&gt;()

5.6 Passer des arguments aux constructeurs

Transmettez les paramètres à viewModel, l'exemple de code est le suivant :

dans le module

val appModule = module 
// ViewModel for Detail View with id as parameter injection
viewModel  parameters -&gt; DetailViewModel(id = parameters.get(), get(), get()) 
// ViewModel for Detail View with id as parameter injection, resolved from graph
viewModel  DetailViewModel(get(), get(), get()) 
// or Constructor DSL
viewModelOf(::DetailViewModel)

Paramètres entrants du point d'injection de dépendance

class DetailActivity : AppCompatActivity() 
val id : String // id of the view

// Lazy inject ViewModel with id parameter
val detailViewModel: DetailViewModel by viewModel parametersOf(id)

5.7 Injection SavedStateHandle

Ajoutez de nouvelles propriétés saisies dans le constructeur pour gérer l'état de ViewModel :SavedStateHandle

class MyStateVM(val handle: SavedStateHandle, val myService : MyService) : ViewModel()Dans le module Koin, analysez-le simplement avec le paramètre ou : get()

viewModel MyStateVM(get(), get()) ou utilisez le constructeur DSL :

viewModelOf(::MyStateVM)Dans le fragment d'activité

by viewModel()- Propriétés déléguées paresseuses pour injecter des instances de modèle de vue d'état dans les propriétés

getViewModel()- Obtenez directement l'instance du modèle de vue d'état

class DetailActivity : AppCompatActivity() 
// MyStateVM viewModel injected with SavedStateHandle
val myStateVM: MyStateVM by viewModel()

5.8 ViewModel dans le diagramme de navigation de navigation

Vous pouvez étendre les instances ViewModel au graphique de navigation. Transmettez simplement l'identifiant àby koinNavGraphViewModel()

class NavFragment : Fragment() 
val mainViewModel: NavViewModel by koinNavGraphViewModel(R.id.my_graph)

5.9 API commune viewModel

Koin fournit des API "de bas niveau" pour ajuster directement votre instance ViewModel.viewModelForClass ComponentActivity Fragment

ComponentActivity.viewModelForClass(
    clazz: KClass<T>,
    qualifier: Qualifier? = null,
    owner: ViewModelStoreOwner = this,
    state: BundleDefinition? = null,
    key: String? = null,
    parameters: ParametersDefinition? = null,
): Lazy<T>

Une fonction de niveau supérieur est également fournie :

fun <T : ViewModel> getLazyViewModelForClass(
    clazz: KClass<T>,
    owner: ViewModelStoreOwner,
    scope: Scope = GlobalContext.get().scopeRegistry.rootScope,
    qualifier: Qualifier? = null,
    state: BundleDefinition? = null,
    key: String? = null,
    parameters: ParametersDefinition? = null,
): Lazy<T>

5.10 API ViewModel - Compatibilité Java

La compatibilité Java doit être ajoutée aux dépendances :

// Java Compatibility
implementation "io.insert-koin:koin-android-compat:$koin_version"
您可以使用以下函数或静态函数将 ViewModel 实例注入到 Java 代码库中:viewModel() getViewModel() ViewModelCompat

@JvmOverloads
@JvmStatic
@MainThread
fun <T : ViewModel> getViewModel(
propriétaire : ViewModelStoreOwner,
clazz : Class<T>,
qualificateur : Qualifier ? = null,
parameters : ParametersDefinition ? = null
)

6. Injecter dans Jetpack Compose

Veuillez d'abord en savoir plus sur Jetpack Compose :

developer.android.com/jetpack/com…

6.1 Injection de @Composable

Lors de l'écriture de fonctions composables, vous pouvez accéder aux API Koin suivantes :

get()- Obtenir une instance du conteneur Koin

getKoin()- Obtenir l'instance Koin actuelle

Pour un module déclarant le composant "MyService" :

val androidModule = module 
single  MyService() 

Nous pouvons obtenir votre instance comme ceci :

@Composable
fun App() 
    val myService = get<MyService>()

Remarque : Pour des raisons de cohérence dans les fonctionnalités de Jetpack Compose, il est préférable d'injecter l'instance directement dans l'attribut de fonction. Cette approche permet d'utiliser Koin pour l'implémentation par défaut, mais la laisse ouverte pour injecter des instances si nécessaire.

@Composable
fun App(myService: MyService = get()) 

6.2 viewModel @Composable

De la même manière que vous accédez à une instance singleton/factory classique, vous pouvez accéder aux API Koin ViewModel suivantes :

getViewModel()ou - obtenir une instancekoinViewModel()

Pour le module déclarant le composant "MyViewModel" :

module 
    viewModel  MyViewModel() 
    // or constructor DSL
    viewModelOf(::MyViewModel)

Nous pouvons obtenir votre instance comme ceci :

@Composable
fun App() 
    val vm = koinViewModel<MyViewModel>()

Nous pouvons obtenir votre instance dans le paramètre de fonction :

@Composable
fun App(vm : MyViewModel = koinViewModel()) 

7. Gérer les portées Android

Les composants Android, par exemple Activity、Fragment、Service, ont un cycle de vie, ces composants sont instanciés par System et il existe des rappels de cycle de vie correspondants dans les composants.

Étant donné que les composants Android ont des attributs de cycle de vie, les instances de composants ne peuvent pas être transmises à koin. Selon la durée du cycle de vie, les composants peuvent être divisés en trois catégories :

  • • Composant à longue durée de vie ( Service、database) - utilisé par plusieurs écrans, jamais jeté
  • • Composants de période moyenne ( User session) - utilisés par plusieurs écrans et doivent être supprimés après un certain temps
  • • Composants de courte durée ( ViewModel)--utilisés par un seul écran et doivent être supprimés à la fin de l'écran

Pour les composants à long terme, nous utilisons généralement single pour créer une seule instance globalement dans l'application

En mode architecture MVP, Presenter est un composant à cycle court

La façon de le créer dans Activity est la suivante

class DetailActivity : AppCompatActivity() 
// injected Presenter
override val presenter : Presenter by inject()

Nous pouvons également créer dans le module

Nous utilisons la portée de l'usine pour créer l'instance Presenter

val androidModule = module 
// Factory instance of Presenter
factory  Presenter() 

Générer une portée d'instance liée à la portée

val androidModule = module 
scope&lt;DetailActivity&gt; 
    scoped  Presenter() 

La plupart des fuites de mémoire Android proviennent du référencement de composants UI/Android à partir de composants non Android. Le système conserve des références à celui-ci et ne peut pas le récupérer entièrement via la récupération de place.

7.1 Déclarer la portée Android

Pour qualifier une dépendance sur un composant Android, il faut déclarer une portée à l'aide d'un bloc comme celui-ci : scope

class MyPresenter()
class MyAdapter(val presenter : MyPresenter)

module
// Déclare la portée de MyActivity
scope<MyActivity>
// obtient l'instance de MyPresenter à partir de la portée actuelle
scoped MyAdapter(get())
scoped MyPresenter()

7.2 Classe de portée Android

Koin fournit des classes Scope liées aux composants du cycle de vie AndroidScopeActivity Retained ScopeActivity ScopeFragment

class MyActivity : ScopeActivity() 
// MyPresenter is resolved from MyActivity's scope
val presenter : MyPresenter by inject()

Android Scope doit être utilisé avec des interfaces pour implémenter des champs comme celui-ci :AndroidScopeComponent scope

abstract class ScopeActivity(
    @LayoutRes contentLayoutId: Int = 0,
) : AppCompatActivity(contentLayoutId), AndroidScopeComponent 
override val scope: Scope by activityScope()

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)

    checkNotNull(scope)

Nous devons utiliser des interfaces et implémenter des propriétés. Cela définira la portée par défaut utilisée par la classe.AndroidScopeComponent scope

7.3 Interface de portée Android

Pour créer un scope Koin lié à un composant Android, il suffit d'utiliser la fonction suivante :

createActivityScope()- Créer un Scope pour l'Activité en cours (la partie Scope doit être déclarée)

createActivityRetainedScope()- Créer un RetainedScope (supporté par ViewModel Lifecycle) pour l'activité en cours (la partie Scope doit être déclarée)

createFragmentScope()- Créer un Scope pour le Fragment actuel et le lier au Scope d'Activité parent Ces fonctions peuvent être utilisées comme délégués pour implémenter différents types de scopes :

activityScope()- Créer un Scope pour l'Activité en cours (la partie Scope doit être déclarée)

activityRetainedScope()- Créer un RetainedScope (supporté par ViewModel Lifecycle) pour l'activité en cours (la partie Scope doit être déclarée)

fragmentScope()- Créer un champ d'application pour le fragment actuel et le lier au champ d'activité parent

class MyActivity() : AppCompatActivity(contentLayoutId), AndroidScopeComponent 
override val scope: Scope by activityScope()

Nous pouvons également définir la portée de rétention (alimentée par le cycle de vie ViewModel) en utilisant ce qui suit :

class MyActivity() : AppCompatActivity(contentLayoutId), AndroidScopeComponent 
override val scope: Scope by activityRetainedScope()

Si vous ne souhaitez pas utiliser la classe Android Scope, vous pouvez utiliser votre propre classe et créer une API avec ScopeAndroidScopeComponent

7.4 Lien portée

Les liens d'étendue permettent de partager des instances entre des composants avec des étendues personnalisées. Dans une utilisation plus large, vous pouvez utiliser des instances sur plusieurs composants. Par exemple, si nous devons partager une instance.Scope UserSession

Déclarez d'abord une définition de portée :

module 
    // Shared user session data
    scope(named("session")) 
        scoped  UserSession() 

Lorsqu'il est temps de commencer à utiliser une instance, créez-lui un champ d'application :UserSession

val ourSession = getKoin().createScope("ourSession",named("session"))

// lier la portée ourSession à current scope, de ScopeActivity ou ScopeFragment
scope.linkTo(ourSession)

Utilisez-le ensuite partout où vous en avez besoin :

class MyActivity1 : ScopeActivity() 
fun reuseSession()
    val ourSession = getKoin().createScope("ourSession",named("session"))

    // link ourSession scope to current `scope`, from ScopeActivity or ScopeFragment
    scope.linkTo(ourSession)

    // will look at MyActivity1's Scope + ourSession scope to resolve
    val userSession = get&lt;UserSession&gt;()

classe MyActivity2 : ScopeActivity()

fun reuseSession()
    val ourSession = getKoin().createScope("ourSession",named("session"))

    // link ourSession scope to current `scope`, from ScopeActivity or ScopeFragment
    scope.linkTo(ourSession)

    // will look at MyActivity2's Scope + ourSession scope to resolve
    val userSession = get&lt;UserSession&gt;()

8.Usine de fragments

Depuis qu'AndroidX a publié une série de packages pour étendre les fonctionnalités d'Androidandroidx.fragment Fragment

developer.android.com/jetpack/et…

8.1 Usine de fragments

Depuis la sortie, une classe dédiée à la création d'instances de classe a été introduite : 2.1.0-alpha-3 FragmentFactoryFragment

developer.android.com/reference/k…

Koin fournit également une classe d'usine KoinFragmentFactoryFragment pour créer Fragment

8.2 Configuration de l'usine de fragments

Tout d'abord, dans KoinApplicationla déclaration, définissez l'instance par défaut à l'aide du mot-clé : fragmentFactory()KoinFragmentFactory

 startKoin 
    // setup a KoinFragmentFactory instance
    fragmentFactory()
modules(...)

8.3 Déclarer et injecter le Fragment

Déclarer un Fragment et l'injecter dans le module

class MyFragment(val myService: MyService) : Fragment() 

val appModule = module
single MyService()
fragment MyFragment(get())

8.4 Obtenir un fragment

utiliser setupKoinFragmentFactory()les paramètresFragmentFactory

Pour interroger votre fragment, utilisezsupportFragmentManager

supportFragmentManager.beginTransaction()
            .replace<MyFragment>(R.id.mvvm_frame)
            .commit()

Ajouter des paramètres facultatifs

supportFragmentManager.beginTransaction()
            .replace<MyFragment>(
                containerViewId = R.id.mvvm_frame,
                args = MyBundle(),
                tag = MyString()
            )

8.5 Usine de fragments et portées Koin

Si vous souhaitez utiliser Koin Activity Scope, vous devez déclarer votre Fragment en tant que définition dans votre Scope :scoped

val appModule = module 
    scope<MyActivity> 
        fragment  MyFragment(get()) 

Et configurez votre Koin Fragment Factory avec votre Scope :setupKoinFragmentFactory(lifecycleScope)

class MyActivity : AppCompatActivity() 
override fun onCreate(savedInstanceState: Bundle?) 
    // Koin Fragment Factory
    setupKoinFragmentFactory(lifecycleScope)

    super.onCreate(savedInstanceState)
    //...

9. Injection Koin de WorkManager

koin fournit un package de composants séparé koin-androidx-workmanager pour WorkManager

Tout d'abord, dans la déclaration KoinApplication, utilisez le mot clé pour définir une instance WorkManager personnalisée :workManagerFactory()

class MainApplication : Application(), KoinComponent 
override fun onCreate() 
    super.onCreate()
    startKoin 
        // setup a WorkManager instance
        workManagerFactory()
        modules(...)
    
    setupWorkManagerFactory()

Modification d'AndroidManifest.xml pour éviter d'utiliser la valeur par défaut

    <application . . .>
        . . .
        <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="$applicationId.workmanager-init"
            tools:node="remove" />
  </application>

9.1 Déclarer ListenableWorker

val appModule = module 
single  MyService() 
worker  MyListenableWorker(get()) 

9.2 Créer une WorkManagerFactory supplémentaire

class MainApplication : Application(), KoinComponent 
override fun onCreate() 
    super.onCreate()

    startKoin 
       workManagerFactory(workFactory1, workFactory2)
       . . .
    

    setupWorkManagerFactory()

Si Koin et workFactory1 fournis WorkManagerFactorypeuvent être instanciés ListenableWorker, la fabrique fournie par Koin sera celle utilisée.

9.3 Modifier le manifeste de koin lib lui-même

Si koin-androidx-workmanagerl'usine par défaut dans est désactivée et que le développeur de l'application n'initialise pas l'infrastructure du gestionnaire de travail de koin, il se retrouvera sans usine de gestionnaire de travail disponible.

Compte tenu de la situation ci-dessus, nous apportons les améliorations DSL suivantes :

val workerFactoryModule = module 
factory<WorkFactory>  WorkFactory1() 
factory<WorkFactory>  WorkFactory2() 

Ensuite, demandez à koin de faire quelque chose en interne comme

fun Application.setupWorkManagerFactory(
// no vararg for WorkerFactory
) 
. . .
getKoin().getAll<WorkerFactory>()
.forEach 
delegatingWorkerFactory.addFactory(it)

lien de référence

insert-koin.io/

lecture recommandée

Auteur : Calvin873
Lien : https://juejin.cn/post/7189917106580750395

Je suppose que tu aimes

Origine blog.csdn.net/gqg_guan/article/details/131801957
conseillé
Classement