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.
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.
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)・ ・ ・
}
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)・ ・ ・
// }
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.
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());
});
}
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.
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.
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();
}
À 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.
J'organiserai les points de Hilt à travers cet échantillon.
@ AndroidEntryPoint
@ Inject
au constructeur de la classe à injecter.@ 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!Recommended Posts