Seria de aplicații Kriptofolio – Partea 4

Injecția de dependență vă va îmbunătăți semnificativ codul. Îți face codul mai modular, mai flexibil și mai testabil. De fapt, numele său sună mai complicat decât ideea care stă în spatele ei.

În această parte a seriei vom învăța despre injectarea dependenței. Îl vom implementa apoi în aplicația „Kriptofolio” (anterior „Monedele mele criptografice”). Vom folosi Dagger 2. Dagger 2 este cel mai popular cadru open-source de injectare a dependenței pentru Android. Aceasta este o abilitate valoroasă pentru a crea aplicații moderne, chiar dacă am considerat că curba de învățare este suficient de grea.

Conținutul seriei

  • Introducere: o foaie de parcurs pentru a construi o aplicație Android modernă în 2018-2019
  • Partea 1: O introducere la principiile SOLID
  • Partea 2: Cum să începeți să vă construiți aplicația Android: crearea machetelor, interfeței și a aspectelor XML
  • Partea 3: Totul despre acea arhitectură: explorarea diferitelor modele de arhitectură și modul de utilizare a acestora în aplicația dvs.
  • Partea 4: Cum să implementați injecția de dependență în aplicația dvs. cu Dagger 2 (sunteți aici)
  • Partea 5: Gestionarea serviciilor web RESTful folosind Retrofit, OkHttp, Gson, Glide și Coroutines

Ce este injecția de dependență?

Pentru a explica mai întâi injectarea dependenței, trebuie să înțelegem ce înseamnă dependență în programare. O dependență este atunci când unul dintre obiecte depinde de implementarea concretă a unui alt obiect. Puteți identifica o dependență în codul dvs. ori de câte ori creați un obiect în altul. Să aruncăm o privire la un exemplu practic.

class MyAppClass() {

    private val library: MyLibrary = MyLibrary(true)
    ...
}

class MyLibrary(private val useSpecialFeature: Boolean) {
    
    ...
}

După cum vedeți din acest exemplu, clasa dvs. MyAppClass va depinde direct de configurarea concretă și implementarea clasei de bibliotecă MyLibrary. Ce-ar fi dacă doriți ca într-o zi să folosiți o bibliotecă terță parte? Ce se întâmplă dacă doriți să aveți o altă clasă în care doriți să utilizați exact aceeași configurație de bibliotecă? De fiecare dată va trebui să căutați codul dvs., să găsiți locul exact și să-l schimbați. Sunt doar câteva exemple.

Ideea este că această cuplare strânsă între componentele aplicației va face ca dezvoltarea dvs. să funcționeze mai greu pe măsură ce proiectul dvs. crește. Pentru a evita orice probleme, să folosim injecția de dependență pentru slăbirea cuplajului descris.

class MyAppClass(private val library: MyLibrary) {
    
    ...
}

class MyLibrary(private val useSpecialFeature: Boolean) {
    
    ...
}

Gata, acesta este un exemplu de injecție de dependență foarte primitiv. În loc să creați și să configurați un nou MyLibrary obiect de clasă din clasa ta MyAppClass, pur și simplu îl treceți sau îl injectați în constructor. Asa de MyAppClass poate fi total iresponsabil pentru MyLibrary.

Ce este Dagger 2?

Dagger este un cadru de injectare a dependenței open-source complet static, în timp de compilare, atât pentru Java cât și pentru Android. În acest articol voi vorbi despre a doua versiune pe care Google o menține. Square și-a creat versiunea anterioară.

Pumnalul 2 este considerat a fi unul dintre cele mai eficiente cadre de injectare a dependenței construite până în prezent. De fapt, dacă comparați pumnalul 1, pumnalul 2 și pumnalul 2.10, veți descoperi că fiecare implementare este diferită. Trebuie să o reînvățați de fiecare dată, deoarece au existat modificări semnificative făcute de autori. Când scriu acest articol, folosesc versiunea Dagger 2.16 și ne vom concentra doar asupra ei.

După cum înțelegeți acum despre injectarea dependenței, clasele noastre nu ar trebui să creeze sau să aibă dependențe. În schimb, trebuie să obțină totul din afară. Deci, atunci când utilizați Dagger 2, acest cadru va furniza toate dependențele necesare.

Face acest lucru generând o mulțime de coduri de cazan pentru noi. Acest cod generat va fi pe deplin trasabil și va imita codul pe care un utilizator îl poate scrie manual. Pumnalul 2 este scris în Java și codul generat de procesorul său de adnotare va fi și codul Java.

Cu toate acestea, funcționează cu Kotlin fără probleme sau modificări. Amintiți-vă că Kotlin este pe deplin interoperabil cu Java. Dacă este comparat cu cadre similare, Dagger 2 este unul mai puțin dinamic. Funcționează la timp de compilare, mai degrabă decât la rulare, cu reflecție. Nu există deloc o utilizare a reflexiei. Tot ceea ce înseamnă este că acest cadru va fi mai greu de configurat și de învățat. Acesta va oferi un spor de performanță cu siguranță în timpul compilării.

Injecție manuală de dependență fără instrumente

Este posibil să fi observat în aplicația My Crypto Coins cod sursă din partea anterioară că există o bucată de cod pentru injectarea obiectelor fără a utiliza instrumente de injectare dependente. Funcționează bine și această soluție ar fi suficient de bună pentru o aplicație atât de mică ca aceasta. Aruncați o privire asupra pachetului de utilități:

/**
 * Static methods used to inject classes needed for various Activities and Fragments.
 */
object InjectorUtils {

    private fun getCryptocurrencyRepository(context: Context): CryptocurrencyRepository {
        return CryptocurrencyRepository.getInstance(
                AppDatabase.getInstance(context).cryptocurrencyDao())
    }

    fun provideMainViewModelFactory(
            application: Application
    ): MainViewModelFactory {
        val repository = getCryptocurrencyRepository(application)
        return MainViewModelFactory(application, repository)
    }

    fun provideAddSearchViewModelFactory(
            context: Context
    ): AddSearchViewModelFactory {
        val repository = getCryptocurrencyRepository(context)
        return AddSearchViewModelFactory(repository)
    }
}

După cum vedeți, această clasă va face toată treaba. Acesta va crea fabrici ViewModel pentru activități sau fragmente care le necesită.

/**
 * Factory for creating a [MainViewModel] with a constructor that takes a
 * [CryptocurrencyRepository].
 */
class MainViewModelFactory(private val application: Application, private val repository: CryptocurrencyRepository) : ViewModelProvider.NewInstanceFactory() {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MainViewModel(application, repository) as T
    }

}

Atunci folosești InjectorUtils clasa de acest gen, unde trebuie să obțineți o fabrică ViewModel specifică:

/**
 * A placeholder fragment containing a simple view.
 */
class MainListFragment : Fragment() {

    ...

    private lateinit var viewModel: MainViewModel

    ...

    override fun onActivityCreated(savedInstanceState: Bundle?) {

        super.onActivityCreated(savedInstanceState)

        setupList()
        ...
    }

    ...

    private fun subscribeUi(activity: FragmentActivity) {

        // This is the old way how we were injecting code before using Dagger.
        val factory = InjectorUtils.provideMainViewModelFactory(activity.application)

        // Obtain ViewModel from ViewModelProviders, using parent activity as LifecycleOwner.
        viewModel = ViewModelProviders.of(activity, factory).get(MainViewModel::class.java)

        ...
    }

}

După cum vedeți noastre MainListFragment clasa nici măcar nu știe despre CryptocurrencyRepository sau AppDatabase. Obține o fabrică construită cu succes din clasa InjectorUtils. De fapt, acesta este un mod simplu de a face acest lucru. Vom scăpa de el și vom învăța cum să configurăm instrumentul Dagger 2 pentru injectarea avansată a dependenței. Dacă această aplicație s-ar extinde în funcționalitate și cod, nu mă îndoiesc că vom începe să vedem beneficiile foarte rapide ale utilizării unui cadru profesional de injectare a dependenței peste o soluție manuală.

Deci, să ștergem InjectorUtils clasa chiar acum și aflați cum să configurați Dagger 2 în codul sursă al aplicației My Crypto Coins.

Injecție de dependență pentru MVVM cu Kotlin

Cum se configurează Dagger 2 cu ViewModels, Activități și Fragmente

Acum vom trece prin configurarea Dagger 2 pas cu pas în proiectul aplicației My Crypto Coins.

Pentru început, ar trebui să activați propriul Kotlin Instrument de procesare a adnotărilor (kapt). Apoi adăugați dependențe speciale Dagger 2.

Puteți face acest lucru adăugând aceste linii în fișierul gradle:

apply plugin: 'kotlin-kapt' // For annotation processing

...

implementation "com.google.dagger:dagger:$versions.dagger"
implementation "com.google.dagger:dagger-android:$versions.dagger"
implementation "com.google.dagger:dagger-android-support:$versions.dagger"
kapt "com.google.dagger:dagger-compiler:$versions.dagger"
kapt "com.google.dagger:dagger-android-processor:$versions.dagger"
Modul: aplicație

Pluginul Kapt va permite compilatorului să genereze clase de stub necesare pentru interoperabilitatea dintre Java și Kotlin. Pentru comoditate, vom defini versiunea concretă Dagger 2 într-un fișier gradle separat, așa cum facem cu toate dependențele noastre.

def versions = [:]

versions.dagger = "2.16"

ext.versions = versions

Pentru a găsi cea mai recentă versiune disponibilă, verificați versiunile la Depozitul oficial al lui Dagger 2 pe Github.

Acum, creați aplicația App clasă.

Omiteți acest lucru dacă aveți deja această clasă setată. După ce ați făcut acest lucru, îl vom lăsa așa pentru un timp, dar ne vom întoarce mai târziu.

class App : Application() {

    override fun onCreate() {
        super.onCreate()
    }

}

Pentru aplicația My Crypto Coins, am creat deja clasa aplicației mai devreme.

Apoi, actualizați fișierul manifest pentru a activa fișierul App clasă.

Omiteți acest lucru dacă ați făcut deja acest lucru înainte.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.baruckis.mycryptocoins">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        ...

Pentru aplicația My Crypto Coins, am setat deja App clasă în manifest mai devreme.

Acum să creăm un nou pachet numit dependencyinjection.

Aici vom păstra toate fișierele legate de implementarea Dagger.

Crea AppModule modul de clasă care va oferi dependențe în întreaga aplicație.

/**
 * AppModule will provide app-wide dependencies for a part of the application.
 * It should initialize objects used across our application, such as Room database, Retrofit, Shared Preference, etc.
 */
@Module(includes = [ViewModelsModule::class])
class AppModule() {

    @Singleton // Annotation informs Dagger compiler that the instance should be created only once in the entire lifecycle of the application.
    @Provides // Annotation informs Dagger compiler that this method is the constructor for the Context return type.
    fun provideContext(app: App): Context = app // Using provide as a prefix is a common convention but not a requirement.

    @Singleton
    @Provides
    fun provideCryptocurrencyRepository(context: Context): CryptocurrencyRepository {
        return CryptocurrencyRepository.getInstance(AppDatabase.getInstance(context).cryptocurrencyDao())
    }
}

După cum vedeți, pentru a crea un modul Dagger, trebuie să-l adnotăm cu specialul @Module adnotare. Proiectele au de obicei mai multe module Dagger. Este tipic ca unul dintre ei să ofere dependențe la nivel de aplicație. Acest AppModule va fi folosit pentru a inițializa obiecte utilizate în aplicația noastră, cum ar fi baza de date Room, Retrofit, Preferințe partajate etc.

De exemplu, am putea discuta despre un scenariu foarte comun pentru AppModule pentru a furniza un obiect contextual în cazul în care avem nevoie de acesta pentru a avea acces la el oriunde în aplicația noastră. Să analizăm codul pentru a vedea cum se face acest lucru.

Trebuie să folosim o adnotare specială Dagger @Provides. Îi spune lui Dagger că metoda oferă un anumit tip de dependență, în cazul nostru, un obiect contextual. Deci, când undeva în aplicație solicităm să injectăm un context, AppModule este locul în care Dagger îl găsește. Și nu contează numele metodelor noastre, deoarece lui Dagger îi pasă doar de tipul de returnare. Este o practică obișnuită să numiți metoda cu prefixul de furnizare, dar poate fi orice doriți.

@Singleton adnotarea pe care o vedeți aplicată aceleiași metode nu face parte din adnotările Dagger. Este conținut în pachetul javax. Această adnotare îi spune lui Dagger că ar trebui să existe doar o singură instanță a dependenței respective.

Nu trebuie să scrieți codul boilerplate pentru a verifica dacă o altă instanță a obiectului este deja disponibilă. Când generați codul, Dagger se va ocupa de toate acele logici pentru dvs. din cauza acestei adnotări. Observați că AppModule include un alt modul ViewModelsModule. Să-l creăm acum.

Creeaza o ViewModelsModule modulul clasei. Acest modul va fi responsabil pentru furnizarea ViewModels în întreaga aplicație.

/**
 * Will be responsible for providing ViewModels.
 */
@Module
abstract class ViewModelsModule {

    // We'd like to take this implementation of the ViewModel class and make it available in an injectable map with MainViewModel::class as a key to that map.
    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class) // We use a restriction on multibound map defined with @ViewModelKey annotation, and if don't need any, we should use @ClassKey annotation provided by Dagger.
    abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel

    @Binds
    @IntoMap
    @ViewModelKey(AddSearchViewModel::class)
    abstract fun bindAddSearchViewModel(addSearchViewModel: AddSearchViewModel): ViewModel

    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}

Acest modul folosește legături multiple cu harta caracteristică Dagger 2. Folosind-o, contribuim la obiecte pe care le alegem într-o hartă care devine injectabilă oriunde în aplicația noastră. Folosind combinația de adnotări Dagger @Binds, @IntoMap și adnotarea noastră personalizată @ViewModelKey(aceasta o vom crea), creăm o intrare în interiorul hărții noastre cu cheia MainViewModel::class și valoare MainViewModel instanță. Legăm anumite fabrici cu ajutorul unor obișnuite ViewModelFactory clasă. Trebuie să creăm această clasă.

Creați o clasă de adnotare personalizată ViewModelKey.

/**
 * An annotation class which tells dagger that it can be used to determine keys in multi bound maps.
 */
@MustBeDocumented
@Target(
        AnnotationTarget.FUNCTION,
        AnnotationTarget.PROPERTY_GETTER,
        AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>) // We might use only those classes which inherit from ViewModel.

Această clasă este utilizată pentru legarea ViewModels în ViewModelsModule. Adnotarea specifică @ViewModelKey reprezintă cheia hărții noastre. Cheia noastră poate fi doar o clasă care moștenește de la ViewModel.

Creați ViewModelFactory clasă.

/**
 * Factory to auto-generate a Class to Provider Map.
 * We use Provider<T> to create an injectable object at a later time.
 */
@Suppress("UNCHECKED_CAST")
@Singleton
class ViewModelFactory @Inject constructor(private val viewModelsMap: Map<Class<out ViewModel>,
        @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        var creator: Provider<out ViewModel>? = viewModelsMap[modelClass]
        if (creator == null) {
            for (entry in viewModelsMap.entries) {
                if (modelClass.isAssignableFrom(entry.key)) {
                    creator = entry.value
                    break
                }
            }
        }
        if (creator == null) {
            throw IllegalArgumentException("Unknown model class $modelClass")
        }

        try {
            return creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}

Acest ViewModelFactory este o clasă de utilitate care vă ajută să creați dinamic ViewModels. Aici furnizați harta generată ca argument. create() metoda va putea alege instanța potrivită de pe hartă.

Creați ActivityBuildersModule modulul clasei.

/**
 * All activities intended to use Dagger @Inject should be listed here.
 */
@Module
abstract class ActivityBuildersModule {

    @ContributesAndroidInjector(modules = [MainListFragmetBuildersModule::class]) // Where to apply the injection.
    abstract fun contributeMainActivity(): MainActivity

    @ContributesAndroidInjector
    abstract fun contributeAddSearchActivity(): AddSearchActivity
}

Acest modul este responsabil pentru construirea tuturor activităților dvs. Va genera AndroidInjector pentru toate activitățile definite în această clasă. Apoi, obiectele pot fi injectate în activități folosind AndroidInjection.inject(this) în onCreate funcționează din ciclul de viață al activității. Observați că acest modul folosește și un alt modul separat responsabil pentru fragmente. Vom crea acest modul în continuare.

Creați MainListFragmetBuildersModule modulul clasei.

/**
 * All fragments related to MainActivity intended to use Dagger @Inject should be listed here.
 */
@Module
abstract class MainListFragmetBuildersModule {

    @ContributesAndroidInjector() // Attaches fragment to Dagger graph.
    abstract fun contributeMainListFragment(): MainListFragment
}

Acest modul vă va construi toate fragmentele legate de MainActivity. Va genera AndroidInjector pentru toate fragmentele definite în această clasă. Obiectele pot fi injectate în fragmente folosind AndroidSupportInjection.inject(this) în onAttach funcționează din ciclul de viață al fragmentului.

Creați AppComponent componenta clasei.

/**
 * Singleton component interface for the app. It ties all the modules together.
 * The component is used to connect objects to their dependencies.
 * Dagger will auto-generate DaggerAppComponent which is used for initialization at Application.
 */
@Singleton
@Component(
        modules = [
            // AndroidSupportInjectionModule is a class of Dagger and we don't need to create it.
            // If you want to use injection in fragment then you should use AndroidSupportInjectionModule.class else use AndroidInjectionModule.
            AndroidSupportInjectionModule::class,
            AppModule::class,
            ActivityBuildersModule::class
        ]
)
interface AppComponent {

    @Component.Builder // Used for instantiation of a component.
    interface Builder {

        @BindsInstance // Bind our application instance to our Dagger graph.
        fun application(application: App): Builder

        fun build(): AppComponent
    }

    // The application which is allowed to request the dependencies declared by the modules
    // (by means of the @Inject annotation) should be declared here with individual inject() methods.
    fun inject(app: App)
}

Componenta este o clasă foarte importantă. Acesta va permite ca toate cele de mai sus să înceapă să lucreze împreună. Face acest lucru conectând obiecte la dependențele lor. Dagger va utiliza această interfață pentru a genera codul necesar pentru a efectua injecția de dependență.

Pentru a crea o clasă de componente, va trebui să utilizați adnotarea Dagger @Component. Este nevoie de o listă de module ca intrare. O altă adnotare @Component.Builder ne permite să legăm o instanță de componentă.

Apoi generați un obiect grafic.

În acest moment aveți toate modulele și configurarea componentelor. Puteți genera obiectul grafic selectând Build -> Make Module în Android Studio IDE. Vom avea nevoie de această generație pentru pașii viitori.

Acum creați un Injectable interfață.

/**
 * It is just a plain empty marker interface, which tells to automatically inject activities or fragments if they implement it.
 */
interface Injectable

Acest lucru va fi necesar și pentru pașii viitori. Injectable interfața ar trebui implementată prin activități sau fragmente pe care dorim să le injectăm automat.

Creați o nouă clasă de ajutor numită AppInjector.

/**
 * It is simple helper class to avoid calling inject method on each activity or fragment.
 */
object AppInjector {
    fun init(app: App) {
        // Here we initialize Dagger. DaggerAppComponent is auto-generated from AppComponent.
        DaggerAppComponent.builder().application(app).build().inject(app)

        app.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity) {

            }

            override fun onActivityResumed(activity: Activity) {

            }

            override fun onActivityStarted(activity: Activity) {

            }

            override fun onActivityDestroyed(activity: Activity) {

            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {

            }

            override fun onActivityStopped(activity: Activity) {

            }

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                handleActivity(activity)
            }
        })
    }

    private fun handleActivity(activity: Activity) {
        if (activity is HasSupportFragmentInjector || activity is Injectable) {
            // Calling inject() method will cause Dagger to locate the singletons in the dependency graph to try to find a matching return type.
            // If it finds one, it assigns the references to the respective fields.
            AndroidInjection.inject(activity)
        }

        if (activity is FragmentActivity) {
            activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
                override fun onFragmentCreated(fragmentManager: FragmentManager, fragment: Fragment, savedInstanceState: Bundle?) {
                    if (fragment is Injectable) {
                        AndroidSupportInjection.inject(fragment)
                    }
                }
            }, true)
        }
    }

}

Este doar o simplă clasă de ajutor pentru a evita apelarea metodei de injectare pentru fiecare activitate sau fragment.

Apoi, configurați fișierul App clasa pe care am creat-o deja înainte.

class App : Application(), HasActivityInjector {

    @Inject // It implements Dagger machinery of finding appropriate injector factory for a type.
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()

        // Initialize in order to automatically inject activities and fragments if they implement Injectable interface.
        AppInjector.init(this)

        ...
    }


    // This is required by HasActivityInjector interface to setup Dagger for Activity.
    override fun activityInjector(): AndroidInjector<Activity> = dispatchingAndroidInjector
}

Deoarece aplicația are activități, trebuie să implementăm HasActivityInjector interfață. Dacă vedeți o eroare chemată de Android Studio pe DaggerAppComponent, deoarece nu ați generat un fișier nou, așa cum sa subliniat în pasul anterior.

Deci, configurare MainActivity pentru a injecta fabrica principală ViewModel și a adăuga un suport pentru injecții cu fragmente.

// To support injecting fragments which belongs to this activity we need to implement HasSupportFragmentInjector.
// We would not need to implement it, if our activity did not contain any fragments or the fragments did not need to inject anything.
class MainActivity : AppCompatActivity(), HasSupportFragmentInjector {

    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var mainViewModel: MainViewModel


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

        // Obtain ViewModel from ViewModelProviders, using this activity as LifecycleOwner.
        mainViewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)

        ...
    }

    ...

    override fun supportFragmentInjector(): AndroidInjector<Fragment> = dispatchingAndroidInjector

    ...
}

Deoarece activitățile noastre au fragmente pentru copii, trebuie să le implementăm HasSupportFragmentInjector interfață. De asemenea, avem nevoie de acest lucru, deoarece intenționăm să facem injecții în fragmentele noastre. Activitatea noastră nu ar trebui să știe cum este injectată. Noi folosim AndroidInjection.inject(this) linie de cod în interiorul suprascrierii onCreate() metodă.

Apelare inject() metoda va face ca Dagger 2 să localizeze singletonii în graficul de dependență pentru a încerca să găsească un tip de returnare corespunzător. Cu toate acestea, nu este nevoie să scriem niciun cod aici, deoarece este făcut pentru noi prin crearea anterioară AppInjector clasa helper pe care am inițializat-o în clasa noastră de aplicații.

Apoi, configurați MainListFragment pentru a injecta fabrica ViewModel principală.

/**
 * A placeholder fragment containing a simple view.
 */
class MainListFragment : Fragment(), Injectable {

    ...

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var viewModel: MainViewModel

    ...

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        ...
        subscribeUi(activity!!)
    }

    ...

    private fun subscribeUi(activity: FragmentActivity) {

        // Obtain ViewModel from ViewModelProviders, using parent activity as LifecycleOwner.
        viewModel = ViewModelProviders.of(activity, viewModelFactory).get(MainViewModel::class.java)
        
        ...

    }

}

Similar cu activitățile, dacă vrem ca fragmentul nostru să fie injectabil, atunci în al său onAttach metoda ar trebui să scriem codul AndroidSupportInjection.inject(this). Dar, din nou, aceasta este o treabă făcută de AppInjector ajutor, deci putem sări peste asta. Observați doar că trebuie să adăugăm Injectable interfață pe care am creat-o mai devreme pentru ca ajutorul să funcționeze.

Felicitări, am implementat Dagger 2 în proiectul aplicației My Crypto Coins. Desigur, acest articol este un ghid rapid pentru a implementa imediat Dagger 2 în aplicația dvs., dar nu o acoperire profundă a acestuia. Vă recomand să continuați cercetarea acestui subiect dacă vă simțiți pierdut pe elementele de bază.

Repertoriu

Verificați codul sursă al aplicației actualizate „Kriptofolio” (anterior „Monedele mele criptografice”) pe GitHub.

Vizualizați sursa pe GitHub


Ačiū! Mulțumesc pentru lectură! Am publicat inițial această postare pentru blogul meu personal www.baruckis.com pe 7 octombrie 2018.