Essayez d'implémenter Android Hilt en Java

introduction

Une version alpha de Hilt a été publiée, alors je l'ai étudiée. Ce Dagger 2 déroutant était très facile à comprendre. Je pense que le seuil d’introduction a été abaissé. Par conséquent, je voudrais expliquer les bases lors de la création d'un exemple d'application pour ceux qui veulent "DI, utiliser Hilt, et veulent connaître les bases". De plus, la méthode de migration de Dagger2 vers Hilt n'est pas décrite.

Soudainement implémenté

L'explication telle que le contour est omise et elle est mise en œuvre soudainement. Veuillez consulter la page officielle pour DI et Hilt. L'exemple créé cette fois est une application qui recherche la base de données et affiche les résultats lorsque vous appuyez sur le bouton à l'écran.

La structure de la classe à créer est la suivante. MainActivity --> SampleUseCase --> SampleRepository --> SampleDao --> DB

Implémentez cette application en utilisant Hilt. J'utilise «Room» dans la base de données, mais je ne mentionne pas «Room».

L'environnement est le suivant.

Ajouter une bibliothèque

Tout d'abord, définissez la racine build.gradle.


buildscript {
    dependencies {
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
        //···(réduction)・ ・ ・
   }
}

Vient ensuite le paramétrage de ʻapp / build.gradle`.


apply plugin: 'dagger.hilt.android.plugin'

android {
    //・ ・ ・(réduction)・ ・ ・
}

dependencies {
    implementation "com.google.dagger:hilt-android:2.28-alpha"
    annotationProcessor "com.google.dagger:hilt-android-compiler:2.28-alpha"
    //・ ・ ・(réduction)・ ・ ・
}

Créer une classe d'application

Ensuite, créez la classe Application. Ajoutez simplement @ HiltAndroidApp à la classe Application. Jusqu'à présent, il héritait de DaggerApplication ou impmpled HasAndroidInjector, mais dans Hilt, il est juste d'ajouter une annotation.

Après avoir créé la classe Application, ajoutez-la à AndroidManifest.xml.


@HiltAndroidApp
public class SampleApplication extends Application {
}

AndroidManifest.xml


<application
    android:name=".SampleApplication"    
    android:icon="@mipmap/ic_launcher">
···(réduction)···
</application>

J'avais l'habitude de créer AppComponent, mais Hilt n'en a plus besoin. Si vous migrez depuis Dagger2, supprimez-le.


// @Singleton
// @Component(modules={AndroidInjectionModule.class})
// public interface AppComponent extends AndroidInjector<SampleApplication> {
//···(réduction)・ ・ ・
// }

Injecter dans l'activité

Vous pouvez injecter en annotant Activity avec @ AndroidEntryPoint. Jusqu'à présent, Impl de HasAndroidInjector et ʻAndroidInjection.inject (this);` étaient exécutés, mais dans Hilt, il est seulement annoté.

Dans cet exemple, nous injecterons SampleUseCase dans MainActiviyt.

MainActivity.java



@AndroidEntryPoint     //・ ・ ・(1)
public class MainActivity extends AppCompatActivity {

    @Inject            //・ ・ ・(2)
    SampleUseCase useCase; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.execute);
        button.setOnClickListener(v -> useCase.execute());   //・ ・ ・(3)
    }
}

(1) Ajoutez l'annotation AndroidEntryPoint. (2) Ajoutez l'annotation ʻInject. Hilt injecte une instance dans cette variable ʻuseCase. (3) Exécutez ʻuseCase` lorsque le bouton est enfoncé. Dans le code, SampleUseCase peut être exécuté même s'il n'est pas nouveau. En effet, Hilt a créé et injecté l'instance.

Vient ensuite le SampleUseCase. Tout d'abord, l'implémentation consiste simplement à sortir le journal.

SampleUseCase.java



public class SampleUseCase {
    private static String TAG = SampleUseCase.class.getName();

    @Inject    //・ ・ ・(1)
    public SampleUseCase() {
    }

    public void execute() {
        Log.d(TAG, "Courir!!");
    }
}

(1) Ajoutez l'annotation ʻInject` au constructeur. Sans lui, ce ne sera pas un objet géré par Hilt et ne sera pas injecté dans l'activité.

Cela fonctionne réellement jusqu'à ce point. DI est prêt. C'est très facile. C'est extrêmement plus facile qu'avec Dagger2.

Créer un module Hilt

Dans l'exemple ci-dessus, dans la classe à injecter (SampleUseCase), @ Inject est spécifié dans le constructeur. Cependant, il peut ne pas être possible d'accorder «@ Inject». Par exemple, pour des interfaces ou des classes dans des bibliothèques externes. Dans ce cas, créez une classe avec l'annotation @ Module et indiquez à Hilt comment créer l'instance.

Dans cet exemple, cela correspond à l'appel de l'interface SampleRepository pour SampleUseCase. Ajoutez une implémentation à la classe SampleUseCase.

SampleUseCase.java


public class SampleUseCase {
    private static String TAG = SampleUseCase.class.getName();

    @Inject
    SampleRepository repository;   //interface

    @Inject
    public SampleUseCase() {
    }

    public void execute() {
        Log.d(TAG, "Courir!!");

        //je le ferai
        List<SampleEntity> results = repository.find();

        //Afficher les résultats dans le journal
        results.forEach(result -> {
            Log.d(TAG, result.getName());
        });
    }

Injecter des instances en utilisant Binds

Une implémentation de SampleRepository. L'interface et la classe d'entité sont les suivantes.

SampleRepository.java


public interface SampleRepository {
    List<SampleEntity> find();
}

SampleRepositoryImpl.java


public class SampleRepositoryImpl implements SampleRepository {
    public static final String TAG = SampleRepositoryImpl.class.getName();

    @Inject                           //・ ・ ・(1)
    public SampleRepositoryImpl() {
    }

    public List<SampleEntity> find() {
        Log.d(TAG, "find!");
        return null;
    }
}

(1) Ajoutez @ Inject au constructeur de la classe d'entité.

Cela seul ne peut pas être injecté. Je dois apprendre à Hilt comment instancier cette interface.

Le module Hilt est une classe annotée avec @ Module. Contrairement aux modules de Dagger, Hilt utilise l'annotation @ InstallIn pour spécifier les dépendances.

DataModule.java


@Module                                        //· · · (1)
@InstallIn(ApplicationComponent.class)         //・ ・ ・(2)
abstract public class DataModule {

    @Binds                                     //・ ・ ・(3)
    public abstract SampleRepository bindSampleRepository(SampleRepositoryImpl impl);
                                                                              
}

(1) Ajoutez l'annotation @ Module et déclarez qu'il s'agit d'une classe de module Hilt. Le nom de la classe peut être n'importe quoi. (2) Spécifiez la dépendance de ce module. Dans cet exemple, les classes déclarées ici peuvent être injectées dans n'importe quelle classe de l'application. Cette spécification peut être spécifiée de différentes manières, comme indiqué dans le tableau ci-dessous. Par exemple, si vous spécifiez FragmentComponent, vous pouvez injecter dans Fragment mais pas Activity. Cette fois, nous allons spécifier un ApplicationComponent afin qu'il puisse être injecté dans n'importe quelle classe de l'application.

composant Cible de l'injection
ApplicationComponent Application
ActivityRetainedComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent Afficher avec l'annotation WithFragmentBindings
ServiceComponent Service

(3) Ajoutez l'annotation Binds et déclarez quelle entité générer. La valeur de retour de la méthode spécifie l'interface. Dans les paramètres de méthode, spécifiez l'entité que vous souhaitez générer.

Injecter des instances à l'aide de «Fournit»

En plus des liaisons, vous pouvez spécifier comment créer une instance. Les bibliothèques externes ne peuvent pas donner d'injections aux constructeurs. Dans un tel cas, utilisez «Fournit».

Dans cet exemple, c'est là que SampleRepositoryImpl appelle Dao. Il s'agit d'une implémentation lorsque DI est lié à Room. (Je n'expliquerai pas sur Room. Je le ferai dans un autre article)

Ajoutez-le à DataMudule.java dans l'exemple de code ci-dessus.

DataModule.java


@Module
@InstallIn(ApplicationComponent.class)
abstract public class DataModule {

    @Provides                                           //・ ・ ・(1) 
    @Singleton                                          //・ ・ ・(2)
    public static SampleDatabase provideDb(Application context) {
        return Room.databaseBuilder(context.getApplicationContext(), SampleDatabase.class, "sample.db")
                .addCallback(SampleDatabase.INITIAL_DATA)
                .allowMainThreadQueries()
                .build();
    }

    @Provides                                           //・ ・ ・(3)
    @Singleton                                         
    public static SampleDao provideSampleDao(SampleDatabase db) {
        return db.getSampleDao();
    }


    @Binds
    public abstract SampleRepository bindSampleRepository(SampleRepositoryImpl impl);
}

(1) Ajoutez l'annotation «Fournit» et déclarez quelle entité générer. La valeur de retour de la méthode est l'instance créée. Le paramètre peut être passé à une instance gérée par Hilt. (2) Cette méthode a une annotation Singleton. Il s'agit du paramètre de portée. Normalement, Hilt crée une nouvelle instance à chaque fois qu'il y a une demande. Cela peut être contrôlé en l'annotant. Puisque cet exemple est «Singleton», l'état d'une instance est réalisé dans l'application. (Je ne crée pas de nouvelle instance à chaque fois). L'injection de n'importe quelle classe aboutira à la même instance.

Les étendues suivantes sont disponibles.

Classe Android Composant généré portée
Application ApplicationComponent Singleton
View Model ActivityRetainedComponent ActivityRetainedScope
Activity ActivityComponent ActivityScoped
Fragment FragmentComponent FragmentScoped
View ViewComponent ViewScoped
WithFragmentBindings ViewWithFragmentComponent ViewScoped
Service ServiceComponent ServiceScoped

Par exemple, si vous changez l'InstantRun de DataModule.java de cet exemple en ʻActivityComponent et changez SampleDao en ʻActivityScoped, ce sera la même instance pour la durée de vie de l'activité. Si vous injectez Dao dans SampleActivity, SampleUseCase et SampleRespository, les Dao sont tous la même instance.

Revenez à l'exemple d'implémentation d'application. Injectez Dao dans SampleRepositoryImpl pour terminer l'implémentation.

SampleRepositoryImpl.java


public class SampleRepositoryImpl implements SampleRepository {
    public static final String TAG = SampleRepositoryImpl.class.getName();

    @Inject                    //・ ・ ・(1)
    SampleDao dao; 

    @Inject
    public SampleRepositoryImpl() {
    }

    public List<SampleEntity> find() {
        Log.d(TAG, "find!");
        return dao.find();     //・ ・ ・(2)
    }
}

(1) Injectez l'échantillon de Dao. Puisque la portée est «Singleton», la même instance est injectée à chaque fois. (2) Bien qu'il ne soit pas nouveau, il ne provoque pas d'exception NullPointerException car il est injecté par Hilt.

Autre code

Voici Dao et l'entité des exemples d'applications non expliquées ci-dessus.

SampleEntity.java


@Entity(tableName = "sample")
public class SampleEntity implements Serializable {

    @PrimaryKey
    @NonNull
    private String code;
    private String name;

    //setter/getter omis
}

SampleDao.java


@Dao
public interface SampleDao {

    @Insert
    long save(SampleEntity dto);

    @Query("select * from sample")
    List<SampleEntity> find();
}

Achevée! !!

À ce stade, lorsque vous appuyez sur le bouton à l'écran, les résultats de la recherche seront affichés dans le journal. Ce qui était nécessaire pour Dagger2 est presque inutile, et cela peut être réalisé simplement. C'est très facile.

Résumé

J'organiserai les points de Hilt à travers cet échantillon.

  1. Donner une activité @ AndroidEntryPoint
  2. N'oubliez pas d'ajouter @ Inject au constructeur de la classe à injecter.
  3. Utilisez @ Binds ou @ Provides lorsque vous ciblez des interfaces et d'autres bibliothèques pour l'injection. c'est tout. C'est facile. La prochaine fois, j'aimerais utiliser Hilt et utiliser ViewModel pour afficher les résultats de la recherche à l'écran. à plus!

référence

Recommended Posts

Essayez d'implémenter Android Hilt en Java
Il est tard! Essayez d'implémenter la notification Android en Java (débutant)
Il est tard! Essayez d'implémenter Android Work Manager en Java (débutant)
Essayez d'utiliser RocksDB avec Java
Essayez d'appeler JavaScript en Java
Essayez de développer Spresense avec Java (1)
Essayez le type fonctionnel en Java! ①
Essayez d'implémenter le traitement asynchrone dans Azure
Implémentons la vérification de signature du code de courbe elliptique en Java
Essayez d'exécuter Selenuim 3.141.59 avec eclipse (java)
Essayez une expression If en Java
Essayez d'exécuter AWS X-Ray en Java
Essayez d'implémenter Yuma en Java
Java: essayez d'implémenter vous-même un formateur séparé par des virgules
Essayez de résoudre Project Euler en Java
Essayez d'implémenter l'ajout n-aire en Java
Essayez d'utiliser l'API Stream en Java
Essayez d'utiliser l'API au format JSON en Java
Essayez d'appeler le service CORBA sur Java 11+
Créons une application de calcul avec Java
De Java à C et de C à Java dans Android Studio
Partition en Java
Essayez Java 8 Stream
Changements dans Java 11
Janken à Java
Taux circonférentiel à Java
Essayez grossièrement Java 9
FizzBuzz en Java
Essayez d'utiliser Firebase Cloud Functions sur Android (Java)
[AWS IoT] Implémentation de l'autorisation d'appels directs en Java [Java]
Essayez de gratter environ 30 lignes en Java (sortie CSV)
[Android / Java] Exploitez une base de données locale dans la salle
Essayez de créer un babillard en Java
Deuxième décoction: essayez une expression If en Java
Essayez d'utiliser Sourcetrail (version win) avec du code Java
Essayez d'utiliser l'API Cloud Vision de GCP en Java
Essayez d'utiliser Sourcetrail (version macOS) avec du code Java
Essayez la communication en utilisant gRPC sur un serveur Android + Java
Difficultés lors de la mise en œuvre d'Alarm Manager dans Android Studio
Essayez d'utiliser l'analyse syntaxique de l'API COTOHA en Java
Représente le «jour suivant» et le «jour précédent» en Java / Android
Lire JSON en Java
Implémentation de l'interpréteur par Java
Faites un blackjack avec Java
[Android / Java] Transition d'écran et traitement de retour par fragments
Essayez d'appeler des méthodes synchronisées à partir de plusieurs threads en Java
Application Janken en Java
Programmation par contraintes en Java
Mettez java8 dans centos7
NVL-ish guy en Java
Joindre des tableaux en Java
"Hello World" en Java
Interface appelable en Java
Essayez d'implémenter le tamis Eratostenes en utilisant la bibliothèque standard de Java
Commentaires dans la source Java
Fonctions Azure en Java
Essayez LetCode dans Ruby-TwoSum
Formater XML en Java
Simple htmlspecialchars en Java