IT knowledge base
CTRL+F per cercare la tua parola chiave

Dagger 2 per sviluppatori Android inesperti. Pugnale 2.Parte 1

Questo articolo è la quarta parte di una serie di articoli destinati, secondo l'autore, a coloro che non riescono a capire come gestire l' iniezione di dipendenza e il framework Dagger 2 , o semplicemente lo faranno. Scritto originariamente il 10 dicembre 2017. Traduzione gratis.
Immagine
Questo è il quarto articolo della serie Dagger 2 per sviluppatori Android principianti. ... Se non hai letto i precedenti, allora sei qui .

Serie di articoli

All'inizio della serie

Nell'ultimo articolo, ci siamo resi conto che una classe non dovrebbe creare dipendenze. Invece, dovrebbe riceverli dall'esterno.
Abbiamo anche esaminato un semplice esempio di iniezione di dipendenza in azione. Ha preso un esempio dalla battaglia dei bastardi e ha cercato di sbarazzarsi delle forti dipendenze attraverso l'iniezione di dipendenza.

In che modo l'iniezione di dipendenza può complicarsi?

Se il progetto è semplice come l'esempio discusso in precedenza, creare istanze e inserire manualmente un numero limitato di dipendenze, tramite il punto di ingresso (main() oonCreate() metodo) nel programma è molto ragionevole. Tuttavia, in molti progetti ci sono molte classi, ognuna con diverse dipendenze che devono essere soddisfatte. Ci vuole molto codice per creare un'istanza e collegare tutto insieme. Ancora peggio, questo codice cambierà costantemente ogni volta che nuove classi vengono aggiunte all'applicazione e quando le classi esistenti vengono modificate per iniettare nuove dipendenze.
Per illustrare il problema descritto, complichiamo un po' il nostro esempio. Durante la guerra, nella battaglia dei bastardi (BattleOfBastards ) avrà probabilmente bisogno dell'aiuto degli alleati (Allies ). Anche banca di ferro (IronBank ) finanzierà le case. Il metodo principale modificato sarà simile a questo:
public class BattleOfBastards {

    public static void main(String[] args){
        IronBank bank = new IronBank();
        Allies allies = new Allies(bank);
        Starks starks = new Starks(allies, bank);
        Boltons boltons = new Boltons(allies, bank);

        War war = new War(starks, boltons);
        war.prepare();
        war.report();
    }
}
Molto rapidamente, il punto di ingresso dell'applicazione verrà riempito con un'enorme quantità di codice per inizializzare tutte le dipendenze. Per creare una classe, con la quale lavoreremo, dobbiamo inizializzarne molte altre. Man mano che l'applicazione cresce e vengono aggiunte nuove classi, il punto di ingresso dell'applicazione si gonfia e alla fine diventa molto difficile da mantenere.

Dagger 2 si precipita in soccorso

Dagger 2 è uno dei framework open source per l'iniezione delle dipendenze (di seguito userò DI, da Dependency Injection), che genera molto codice standard per te. Perché è migliore degli altri? Attualmente è l'unico framework DI che genera codice Java completamente tracciabile che imita ciò che potresti aver scritto a mano. Ciò significa che non c'è magia nella costruzione del grafico delle dipendenze. Dagger 2 è meno dinamico di altri (non utilizza la riflessione), ma la semplicità e le prestazioni del codice generato sono allo stesso livello di quello scritto a mano. In breve, Dagger 2 genera tutto il codice standard per l'iniezione di dipendenza per te.
La gestione manuale dell'iniezione di dipendenza è come estrarre il vetro del drago. Prima ottieni il permesso dalla regina dei draghi, poi forgi armi e solo allora vai in guerra con gli Estranei (problemi di forti legami). Dagger 2 è simile alla spada di Valyrian: è stata realizzata da artigiani e tutto ciò che devi fare è semplicemente usarla.
media
Immagine

Comprensione dei processori di annotazione

# Annotazioni

Le annotazioni sono un tipo di metadati che possono essere associati a classi, metodi, campi e persino altre annotazioni. Le annotazioni vengono utilizzate in Java per fornire informazioni aggiuntive, in alternativa alle interfacce XML o token (interfacce vuote). È possibile accedere alle annotazioni anche in fase di esecuzione tramite il meccanismo di riflessione.

# Processori di annotazione

I processori di annotazione sono generatori di codice che ti nascondono il codice standard, creandolo per te in fase di compilazione. Finché queste azioni vengono eseguite in fase di compilazione, non vi è alcun impatto negativo sulle prestazioni.

# Perché dovrei conoscere i processori di annotazione?

Dagger 2 li usa. Pertanto, è possibile tracciare tutto il codice generato in fase di compilazione. Pertanto, non vi è alcun degrado delle prestazioni e gli errori sono facilmente rintracciabili.

# Esempi

Vedi spesso annotazioni nelle classi@Override ... Se hai usato Butteknife ,@BindView È anche un'annotazione che nasconde alcuni metadati dietro di essa per aiutare a generare codice.

Annotazioni di Dagger 2

Diamo un'occhiata ad alcune delle annotazioni di Dagger 2 prima di usarlo. Per ora, concentriamoci su due...@Inject e@Component ...

@Inject

Questa è l'annotazione più importante. JSR-330 definisce questa annotazione come markup per le dipendenze che devono essere fornite da un framework di inserimento delle dipendenze.
  • Inserimento del costruttore: utilizzato con un costruttore di classi.
  • Iniezione di campi: utilizzata con i campi di classe.
  • Iniezione del metodo - utilizzato con i metodi
public class Starks {
  / **
  * Explanation of different uses
  * Inject annotations in Dagger
  ** /
  
  // Feild injection
  @Inject
  Allies allies;
  
  // Constructor injection
  @Inject
  public Starks () {
    // something happens
  }
  
  // Method injection
  @Inject
  private void prepareForWar () {
    // something happens
  }
}
In altre parole, l'annotazione@Inject dirà a Dagger quali dipendenze dovrebbero essere fornite all'oggetto dipendente. È come gli agenti della banca di ferro che negoziano con le case e determinano l'importo del credito che possono prestare alla casa.

@Component

Questa annotazione viene utilizzata per un'interfaccia che riunirà tutte le parti del processo di iniezione delle dipendenze. Quando si utilizza questa annotazione, determiniamo da quali moduli o altri componenti verranno prese le dipendenze. Anche qui puoi definire quali dipendenze saranno visibili apertamente (possono essere iniettate) e dove il componente può iniettare oggetti.@Component , in generale, qualcosa come un ponte tra@Module (daremo un'occhiata a questa annotazione più avanti) e@Inject ...
In altre parole, questa annotazione è come l'agente della banca di ferro, che è responsabile dell'approvazione del prestito e del trasferimento di denaro sul conto appropriato.

Uccidi gli Estranei con la spada di Valyria

Usiamo Dagger 2 per l'esempio della battaglia bastarda. Questo esempio richiede due dipendenze per la classeWar -Starks eBoltons ...

Configurazione di Dagger 2

Per configurare Dagger 2 nell'uso di IntelliJ Ideabuild.gradle file dal mio ramo di progetto. Assicurati inoltre che l'elaborazione delle annotazioni sia abilitata (File -> Impostazioni -> Compilazione, esecuzione e distribuzione -> Compilatore -> Elaborazione annotazioni -> Abilita elaborazione annotazioni (il flag deve essere impostato)). Non dimenticare di notare anche questo: File -> Impostazioni -> Crea, esecuzione e distribuzione -> Gradle -> Runner -> Delega build / esegui azioni IDE su culla.

Aggiunta di annotazioni@Inject

Il piano è iniettare le dipendenzeStarks eBoltons andare in classeWar con l'aiuto di Dagger 2. Quello che dobbiamo dirgli esplicitamente. Di seguito è riportato un esempio di come eseguire questa operazione utilizzando l'iniezione del costruttore.
public class Boltons implements House {

   @Inject // Dagger 2
   public Boltons () {
   }

    @Override
    public void prepareForWar () {
        // something happens
        System.out.println (this.getClass (). GetSimpleName () + "prepared for war");
    }

    @Override
    public void reportForWar () {
        // something happens
        System.out.println (this.getClass (). GetSimpleName () + "reporting ..");
    }
}
public class Starks implements House {

    @Inject // Dagger 2
    public Starks () {
    }

    @Override
    public void prepareForWar () {
        // something happens
        System.out.println (this.getClass (). GetSimpleName () + "prepared for war");
    }

    @Override
    public void reportForWar () {
        // something happens
        System.out.println (this.getClass (). GetSimpleName () + "reporting ..");
    }
}
Queste due dipendenze sono usate nel costruttore della classeWar dove dovremmo contrassegnarlo.
Il piano è creare una dipendenza o un oggetto di classeWar disponibile per tutte le altre classi. Ma per il lavoro in classeWar è necessario fornirgli due classi da cui dipende -Starks eBoltons ...
public class War {
    private Starks 
    private Boltons boltons;

    @Inject
    public War(Starks starks, Boltons bolton){
        this.starks = starks;
        this.boltons = bolton;
    }

    public void prepare(){
        starks.prepareForWar();
        boltons.prepareForWar();
    }

    public void report(){
        starks.reportForWar();
        boltons.reportForWar();
    }
}

Aggiunta di annotazioni@Component

Come abbiamo appreso in precedenza,@Component È il ponte tra il codice generato e le dipendenze. Anche@Component dice a Dagger 2 come iniettare la dipendenza. Facciamo un'interfacciaBattleComponent  all'interno della classeBattleOfBastards (può essere fatto separatamente).
@Component
interface BattleComponent {
    War getWar();
}
Questa interfaccia sarà implementata dalla classe che genererà Dagger 2 e dalla funzionegetWar() restituirà un'istanzaWar che possiamo usare in un luogo adatto.
Ora devi ricostruire il progetto!
Dopo aver creato il progetto, vedrai che Dagger 2 ha generato una classe chiamataDaggerBattleComponent - ci aiuterà a implementare la classeWar ... Usiamo questa classe per ottenere un'istanzaWar ...
@Component
interface BattleComponent {
    War getWar ();
}

public class BattleOfBastards {

    public static void main (String [] args) {
// Manual dependency injection
// Starks starks = new Starks ();
// Boltons boltons = new Boltons ();
// War war = new War (starks, boltons);
// war.prepare ();
// war.report ();

// Using Dagger 2
        BattleComponent component = DaggerBattleComponent.create ();
        War war = component.getWar ();
        war.prepare ();
        war.report ();
    }
}
Usando la classeDaggerBattleComponent possiamo usare il metodogetWar() che restituisce un'istanzaWar che inietta le dipendenzeStarks eBoltons ...
Congratulazioni! Hai creato il tuo primo progetto utilizzando Dagger 2. Apprezzo davvero che tu abbia dedicato del tempo per arrivare a questo punto. Tempo di festeggiare.

Sommario

Abbiamo discusso di come l'uso manuale di DI aggiunge complessità e codice standard. Quindi abbiamo discusso di come Dagger 2 ci aiuta a sbarazzarci di questo dolore e genera il codice standard stesso.
Dopo aver analizzato le informazioni sui processori di annotazione e le annotazioni di base in Dagger 2 (@Inject e@Component ). Quindi abbiamo applicato le annotazioni nel nostro esempio e abbiamo inserito le dipendenze utilizzando Dagger 2.

Qual è il prossimo?

Nel prossimo articolo, lavoreremo con le classi generate da Dagger 2 e esamineremo altre annotazioni di questo framework. Il prossimo articolo uscirà tra una settimana.