Verdienen Sie Geld mit Ihren Tech-Blogs, Gadgets und Tipps

Mikä on Dagger Android-ohjelmoinnissa (Dependency Injection)?

Huomautus: Seuraava artikkeli auttaa sinua: Mikä on Dagger Android-ohjelmoinnissa (Dependency Injection)?

Riippuvuus injektio voi olla ongelmallista Android-projektisi koosta riippuen, minkä vuoksi Dagger on ollut olemassa jonkin aikaa ja Android-kehittäjät ovat työskennelleet Dagger-kehyksen kanssa tai ainakin kuulleet siitä. Dagger-opetusartikkelissa Androidille tutustumme sen ominaisuuksiin ja toimintoihin. Tule meille saadaksesi lisätietoja Daggerista Androidissa, oppiaksesi lisää siitä ja voidaksesi työskennellä sen kanssa ja käyttää sen ominaisuuksia.

Mikä on tikari Androidissa?

Lyhyesti sanottuna se on työkalu koodin luomiseen eri objektien välisten riippuvuuksien hallitsemiseksi.

Dagger on riippuvuussuutin Javalle ja Androidille. Dagger on riippuvuuden lisäyskehys, joka toimii käännöshetkellä. Lisäksi Dagger ei käytä mitään koodia ajon aikana, suorittaa kaiken käännösajan analyysin ja luo Java-lähdekoodia.

Kuten tiedät, Dagger käyttää huomautuksia, jotka auttavat lukemaan ja luomaan kaiken työhön tarvittavan koodin. Lisäksi kaikki Daggerissa käytetyt erilaiset merkinnät ovat tapa ilmaista asioita, joita Dagger ei tiedä, ja merkintöjä käytetään saavuttamaan tavoitteesi ja luomaan koodi, joka sinun muuten joutuisi Kirjoittamaan itse.

Riippuvuusinjektio antaa sinulle seuraavat edut:

Erot tikari 1:n ja Dagger 2:n välillä

Lyhyesti sanottuna Dagger 2 on parannettu versio Dagger 1:stä ja se on osittain ratkaissut Dagger 1:n ongelmat.

Tikarin ongelmat 1:

  • Ruma luotu koodi
  • Suoritusaikakaavion kokoonpano
  • Tehoton kartoitus
  • Osittainen jäljitettävyys
  • Karttamainen API

Ja Dagger 2 -ratkaisut Dagger 1 -ongelmiin:

  • Kääntää aika validointi koko kaavio
  • Helppo virheenkorjaus; täysin konkreettinen puhelupino käyttöönottoa varten Ja luominen
  • Täysin ymmärrettävää
  • POJO API
  • Esitys

Ja yksi Dagger 2:n ongelmista on sen joustavuuden puute.

Dagger 2 käyttää seuraavia merkintöjä:

  • Moduulit @ ja Provides @ Tarjoavat luokkia ja menetelmiä, joilla voit luottaa meihin.
  • Inject @: on riippuvuuspyyntö, jota voidaan käyttää kentässä, konstruktorissa tai menetelmässä.
  • Komponentti @: Ottaa käyttöön valitut moduulit ja sitä käytetään riippuvuuden lisäämiseen.

Dagger 2 käyttää luotua koodia päästäkseen kenttiin. Siksi yksityisten kenttien käyttö kenttäruiskutukseen ei ole sallittua.

Määritä riippuvuuden tarjoajat (objektien tarjoajat).

Termiä riippuvuuden lisäyskonteksti käytetään yleisesti kuvaamaan joukkoa injektoitavia objekteja.

Lisäksi Dagger 2:ssa moduulilla @ merkityt luokat vastaavat ruiskettavien esineiden valmistelusta. Siksi tällaiset luokat voivat määrittää menetelmiä, joihin on merkitty Provides @. Näillä menetelmillä palautetut objektit ovat käytettävissä riippuvuuslisäystä varten.

Tarjoaa @:n avulla merkintämenetelmät voivat ilmaista riippuvuuksia menetelmäparametrien avulla. Dagger 2 täyttää nämä riippuvuudet aina kun mahdollista.

Määrittele riippuvuudet (objektikuluttajat)

Käytät @Inject-merkintöjä riippuvuuden määrittämiseen. Jos merkitset konstruktoriin @Injectilla, Dagger 2 voi käyttää kyseisen objektin esiintymää riippuvuuksien suorittamiseen. Tämä tehdään estämään lisämenetelmien luominen näille objekteille.

Viestintä kuluttajien ja palveluntarjoajien välillä

Niitä käytetään käyttöliittymässä. Dagger 2 käyttää tällaista käyttöliittymää koodin luomiseen. Luodun luokan perusmalli on käyttää Daggeria etuliitteenä ja sitten käyttöliittymänimenä. Se luo luokan, joka luo menetelmän ja sallii objektien konfiguroinnin annetun konfiguraation perusteella. Käyttöliittymässä määritellyt menetelmät ovat käytettävissä luotujen objektien käyttämiseen.

@Component-rajapinta ilmaisee objektien (moduulien) tarjoajan ja riippuvuutta ilmaisevien objektien välisen suhteen.

Laajuus Huomautuksia

Voit käyttää @Singleton-merkintää määrittääksesi, että objekti-ilmentymiä saa olla vain yksi.

Kentät tikarissa

Dagger 2 ei lisää kenttiä automaattisesti. Yksityisiä kenttiä ei myöskään voi lisätä. Jos haluat käyttää kenttäinjektiota, sinun on määritettävä Component @ -rajapinnassa menetelmä, joka lisää sen esiintymän parametriksi.

Käytä Daggeria Android Studiossa

Ota Dagger 2 käyttöön lisäämällä seuraavat riippuvuudet koontiversioosi. Gradle-tiedosto.

Toteutus “com.google.dagger: dagger: 2.15” annotationProcessor “com.google.dagger: dagger-compiler: 2.10”

Monet Androidin komponentit (Android-komponentit), kuten Activities, suoritetaan Android-kehyksen avulla, eivätkä ne sisälly koodiimme. Tämä vaikeuttaa Android-Komponenttien riippuvuuden varmistamista rakentajien kautta.

Oletetaan, että haluat käyttää tikaria. Android-pakettiluokat, kuten DaggerActivity-luokka, lisäävät seuraavat riippuvuudet koontiversioosi. gradle-tiedosto, ja jos haluat sisällyttää aktiviteettikomponentteja, kuten aktiviteetteja tai fragmentteja, tämä on myös pakollinen.

Toteutus “com.google.dagger: dagger-android: 2.15” annotationProcessor “com.google.dagger: dagger-android-processor: 2.10”

Jos haluat käyttää tukikirjastoa Dagger 2:n kanssa, sinun on myös lisättävä koontiversioon seuraavat tiedot. Gradle.

Toteutus ‘com.google.dagger:dagger-android-support:2.10’

Jos saat saman virheen: (ristiriita riippuvuuden “com.google.code.findbugs:jsr305” kanssa projektissa “:app”)

Voit lisätä app/build.gradle-tiedostoosi seuraavan.

Android { kokoonpanot. all { ResolutionStrategy.force ‘com.google.code.findbugs: jsr305: 1.3.9’ } }

Esimerkki Daggerista RxJavalla ja Retrofit MVVM-arkkitehtuurilla

def supportVersion = ’27 .1.1 ‘ def retrofitVersion = ‘ 2.3.0 ‘ def rxJavaVersion = ‘ 2.0.1 ‘ def butterKnifeVersion = ‘ 8.8.1 ‘ def daggerVersion = ‘ android Imppendationecycle 2.15: ‘ . : 1.1.1″ toteutus “com.squareup.retrofit2: Retrofit: $RetrofitVersion” toteutus “com.squareup.retrofit2: Converter-Gson: $RetrofitVersion” toteutus “com.squareup.retrofit2: Adapter-rxjava2: $RetrofitVersion” toteutus com.squareup.retrofit2 : converter-moshi: $ retrofitVersion ” toteutus ” io.reactivex.rxjava2: rxandroid: $ rxJavaVersion ” toteutus ” io.reactivex.rxjava2: rxjava: ” toteutus ” com.jakewharton: butterknife: $ sion ”toteutus com.android.support:support-v4:27.1.1’ annotationProsessori “com.jakewharton: butterknife-compiler: $ butterKnifeVersion” toteutus “com.google.dagger: tikari: $ daggerVersion ” annotationProcessor ” com.google.dagger: tikari- kääntäjä: $ daggerVersion ” toteutus ” com.google.dagger: dagger-android-support: $ daggerVersion ” annotationProcessor ” com.google.dagger: dagger-android-processor: $ daggerVersion ” … }

Toimimme pakettina ominaisuuden mukaan. Tämä tekee koodistasi modulaarisemman ja ohjattavamman.

Mikä on Dagger?

Aloita jälkiasennus

julkinen käyttöliittymä RepoService { @GET (“orgs / Google / repos” ) Yksittäinen < List > getRepositories (); @GET (“repos / {owner} / {name}” ) Yksi getRepo (@Path (“omistaja”) Stringowner, @Path (“nimi” ) Merkkijononimi); }

Aseta perusfragmentti, perusaktiivisuus ja sovellusluokka.

BaseApplication.java

public class BaseApplication laajentaa DaggerApplication { @Override public void onCreate () { super . onCreate(); } @Override suojattu AndroidInjector laajentaa DaggerApplication > applicationInjector () { ApplicationComponent komponentti = DaggerApplicationComponent. rakentaja (). Sovellus (tämä). rakentaa (); Komponentti. pistää (tämä); palata komponentti; } }

BaseActivity.java

public abstrakti luokka BaseActivity laajentaa DaggerAppCompatActivity { @LayoutRes suojattu abstrakti int layoutRes(); @Override suojattu void onCreate (@Nullable Bundle savingInstanceState) { super.onCreate(savedInstanceState); setContentView(layoutRes()); ButterKnife.bind(this); } }

Käytämme abstraktia funktiota LayoutRes() resurssien asettelun tunnuksen määrittämiseen.

BaseFragment.java

public abstrakti luokka BaseFragment laajentaa DaggerFragment { private Unbinder unbinder; yksityinen AppCompatActivity-toiminta; @LayoutRes suojattu abstrakti int layoutRes(); @Override julkinen näkymä onCreateView ( @NonNull LayoutInflater inflater, ViewGroup-säilö, Bundle savingInstanceState ) { View view = inflater. inflate(layoutRes(), kontti, false); unbinder = ButterKnife . sitoa(tämä, näkymä); näkymä takaa; } @Override public void onAttach (kontekstikonteksti) { super. onAttach(konteksti); Activity = (AppCompatActivity) -konteksti; } @Override public void onDetach () { super . onDetach(); aktiviteetti = nolla; } public AppCompatActivity getBaseActivity () { returnactivity; } @Override public void onDestroyView () { super . onDestroyView(); if (unbinder ! = null ) { unbinder. release(); unbinder = null ; } } }

Aseta Dagger 2:n komponentit ja moduulit.

ApplicationComponent.java

@Singleton @Component (moduulit = { ContextModule. Class , ApplicationModule. Class , AndroidSupportInjectionModule. Class , ActivityBindingModule. Class }) julkinen käyttöliittymä ApplicationComponent laajentaa AndroidInjector < DaggerApplication > { void inject (BaseApplication-sovellus); @Component.Builder interface Builder { @BindsInstance Builder -sovellus (sovellussovellus); ApplicationComponent build(); } }

Kuten näet, kirjoitimme juuri AndroidSupportInjectionModule, ActivityBindingModule ja ViewModelModule moduuliparametriin. Kirjoitamme muut vaaditut moduulit, jotka vaativat Aktiviteetin tai Fragmentin.

ActivityBindingModule.java

@Module julkinen abstrakti luokka ActivityBindingModule { @ContributesAndroidInjector (moduulit = {MainFragmentBindingModule. Class }) abstrakti MainActivity bindMainActivity (); }

MainFragmentBindingModule.java

@Module julkinen abstrakti luokka MainFragmentBindingModule { @ContributesAndroidInjector abstract ListFragment ProvideListFragment(); @ContributesAndroidInjector abstrakti DetailsFragment ProvideDetailsFragment(); }

ApplicationModule.java

@Singleton @Module (sisältää = ViewModelModule. Class ) public class ApplicationModule { private static final String BASE_URL = “https://api.github.com/” ; @Singleton @Tarjoaa staattisen jälkiasennuksen ProvideRetrofit () { palauta uusi Retrofit.Builder (). baseUrl (BASE_URL) .addCallAdapterFactory (RxJava2CallAdapterFactory.create ()) .addConverterFactory (GsonConverterFactory.create ()) .build (); } @Singleton @Tarjoaa staattisen RepoServicen ProvideRetrofitService (Retrofit Retrofit) { return retrofit.create (RepoService. class ); } }

ContextModule.java

@Module julkinen abstrakti luokka ContextModule { @Sitoutuu abstraktin kontekstin ProvideContext(sovellussovellus); }

ViewModelModule.java

@Singleton @Module abstrakti luokka ViewModelModule { @Sidos @IntoMap @ViewModelKey ( ListViewModel. Class ) abstract ViewModel bindListViewModel (ListViewModel listViewModel); @Binds @IntoMap @ViewModelKey ( DetailsViewModel. Class ) abstrakti ViewModel bindDetailsViewModel (DetailsViewModel detailsViewModel); @Sitoja abstraktin ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory tehdas); }

Luo mukautettu ViewModel Factory

ViewModelFactory on tehdas, joka laajentaa ViewModelProvider.Factiven tarjoamaan ViewModel-esiintymiä kuluttajafragmenttiluokille. Loimme tämän luokan käyttämällä Injectia ja ViewModelModulea.

ViewModelFactory.java

@Singleton julkinen luokka ViewModelFactory toteuttaa ViewModelProvider.Factory { yksityinen lopullinen Map , Provider > Creator; @Inject public ViewModelFactory (Kartta < Luokka laajenee ViewModel >, Provider < ViewModel >> Luojat) { this.creators = Creators; } @NonNull @SuppressWarnings (“ei valittu”) @Ohita julkinen T luo (@NonNull Class < T > modelClass ) { Palveluntarjoaja laajentaa ViewModelin > Creator = Creators.get (ModelClass); if (creator == null ) { for (Map.Entry < Class extends ViewModel >, Provider < ViewModel >> Entry : Creators . EntrySet ()) { if (ModelClass.isAssignableFrom (entry.getKey ())) { Creator = Entry .getValue(); tauko ; } } } if (creator == null ) { heittää uusi IllegalArgumentException (“tuntematon malliluokka” + modelClass); } yritä { return (T) Creator.get(); } Catch (Poikkeus e) { throw new RuntimeException (e); } } }

Käynnistä ViewModel.

ListViewModel.java

public class ListViewModel laajentaa ViewModel { yksityinen lopullinen Arkistovarasto arkisto; yksityiset CompositeKertakäyttöiset tuotteet; yksityinen lopullinen MutableLiveData < List > repos = uusi MutableLiveData <> (); yksityinen lopullinen MutableLiveData < Boolean > repoLoadError = uusi MutableLiveData <> (); yksityinen lopullinen MutableLiveData < Boolean > Ladataan = uusi MutableLiveData <> (); @Inject public ListViewModel(Arkistotietovarasto) { this.repoRepository = arkistoArkisto; kertakäyttöinen = new CompositeDisposable(); fetchRepos(); } LiveData < List > getRepos () { return repos; } LiveData < Boolean > getError () { return repoLoadError; } LiveData < Boolean > getLoading () { return Ladataan; } yksityinen void fetchRepos() { Loading.setValue(true); disposable.add (repoRepository.getRepositories (). subscribeOn (Schedulers.io ()) .observeOn (AndroidSchedulers.mainThread ()). subscribeWith ( new DisposableSingleObserver < List > () { @Override public void onSuccess. Loista arvo. setValue ( false ); repos.setValue ( arvo ); Loading.setValue ( False ); } @Override public void onError ( Throwable e) { repoLoadError.setValue ( True ); Loading.setValue ( False ); } })); } @Override protected void onCleared () { super.onCleared (); if (kertakäyttöinen! = null ) { disposable.clear (); kertakäyttöinen = tyhjä ; } } }

Luo fragmentti.

ListFragment.java

public class ListFragment laajentaa BaseFragment toteuttaa RepoSelectedListener { @BindView (R. id . RecyclerView ) RecyclerView listView; @BindView (R. id . Tv_error ) TextView errorTextView; @BindView (R. id . Loading_view ) Näytä LoadingView; @Inject ViewModelFactory viewModelFactory; yksityinen ListViewModel viewModel; @Override protected int layoutRes () { return R. layout . screen_list ; } @Override public void onViewCreated ( @NonNull View -näkymä, @Nullable Bundle savingInstanceState ) { viewModel = ViewModelProviders . from ( tämä , viewModelFactory). get ( ListViewModel . luokka ); Listanäkymä. addItemDecoration ( uusi DividerItemDecoration ( getBaseActivity (), DividerItemDecoration . VERTICAL )); Listanäkymä. setAdapter(new RepoListAdapter(viewModel, this, this)); Listanäkymä. setLayoutManager ( uusi LinearLayoutManager ( getContext ())); observableViewModel(); } @Override public void onRepoSelected ( Repo repo ) { DetailsViewModel detailsViewModel = ViewModelProviders . from (getBaseActivity(), viewModelFactory). get ( DetailsViewModel . class ); DetailsViewModel. setSelectedRepo(arkisto); getBaseActivity(). getSupportFragmentManager(). beginTransaction(). korvaa (R. id . screenContainer , new DetailsFragment ()) . addToBackStack ( null ). tehdä(); } yksityinen void observableViewModel () { viewModel. getRepos(). watch ( this , repos -> { if (repos ! = null ) listView. setVisibility ( View . VISIBLE ); }); viewModel. getError(). tarkkailla ( this , isError -> { if (isError! = null ) if (isError) { errorTextView. setVisibility ( View . VISIBLE ); listView. setVisibility ( View . GONE ); errorTextView. setText (“Tapahtui virhe ladattaessa tietoja !” ); } else { errorTextView. setVisibility ( View . GONE ); errorTextView. setText ( null ); } }); viewModel. getLoading(). watch ( this , isLoading -> { if (isLoading! = null ) { LoadingView. setVisibility ( isLoading ? View . VISIBLE : View . GONE ); if (isLoading) { errorTextView. setVisibility ( Näytä . GONE ); listView. setVisibility ( Näytä . POISTU ); } } }); } }

Luo RecyclerView-sovitin.

RepoListAdapter.java

Julkinen luokka RepoListAdapter laajentaa RecyclerView’ta. Sovitin < RepoListAdapter . RepoViewHolder > { yksityinen RepoSelectedListener repoSelectedListener; yksityinen lopullinen List data = uusi ArrayList <> (); RepoListAdapter(ListViewModel viewModel, LifecycleOwner lifecycleOwner, RepoSelectedListener repoSelectedListener) { this.repoSelectedListener = repoSelectedListener; viewModel.getRepos(). watch(lifecycleOwner, repos -> { data.clear (); if (repos! = null ) { data.addAll (repos); notifyDataSetChanged (); } }); setHasStableIds(true); } @NonNull @Override julkinen RepoViewHolder onCreateViewHolder (@NonNull ViewGroup vanhempi , int viewType) { View view = LayoutInflater. from (parent .getContext ()). inflate (R.layout.view_repo_list_item, vanhempi , false ); return new RepoViewHolder(view, repoSelectedListener); } @Override public void onBindViewHolder (@NonNull RepoViewHolder holder, int position) { holder.bind(data.get(position)); } @Override public int getItemCount () { return data.size (); } @Override public long getItemId ( int position) { return data.get (sijainti) .id; } Staattinen viimeinen luokka RepoViewHolder laajentaa RecyclerView’ta. ViewHolder { @BindView (R.id.tv_repo_name) TextView repoNameTextView; @BindView (R.id.tv_repo_description) TextView repoDescriptionTextView; @BindView (R.id.tv_forks) TextView forksTextView; @BindView (R.id.tv_stars) TextView starsTextView; yksityinen repo repo; RepoViewHolder(View itemView, RepoSelectedListener repoSelectedListener) { super(itemView); ButterKnife.bind(this, itemView); itemView.setOnClickListener (v -> { if (repo! = null ) { repoSelectedListener.onRepoSelected (repo); } }); } void bind(Repo repo) { this.repo = repo; repoNameTextView.setText(repo.name); repoDescriptionTextView.setText(repo.description); forksTextView.setText(String .valueOf(repo.forks)); starsTextView.setText(String .valueOf(repo.stars)); } } }

Yhteenveto :

Dagger-opetusohjelmassa Androidille opimme Daggerista ja sen toiminnoista sekä tajusimme Daggerin käytön edut Android-sovelluskehitykseen.