Use of Android hilt and problems encountered

Time:2021-10-23
catalogue
  • brief introduction
  • Import hilt
  • Component hierarchy
  • Component default binding
  • Simple use
  • @HiltAndroidApp
    • introduce
    • use
  • @AndroidEntryPoint
    • introduce
    • use
  • @Module and @ installin
    • introduce
    • use
  • @Provides and @ bindings
    • introduce
    • use
  • @HiltViewModel
    • introduce
    • use
  • @EntryPoint
    • introduce
  • Summary

    brief introduction

    Hilt provides a standard way to inject dagger dependencies into Android applications. Provide a set of standard, simplified settings and readable components for Android application simplification; It also provides a simple method for different types of construction (such as testing, debugging and distribution).

    It can be understood that Google injects components for unified dependency injection, but dagger is more complex to use. Developed a set of adaptation library for Android.

    Import hilt

    
    apply plugin: 'com.android.application'
    apply plugin: 'dagger.hilt.android.plugin'
    
    android {
      // ...
    }
    
    dependencies {
      implementation 'com.google.dagger:hilt-android:2.34.1-beta'
      kapt 'com.google.dagger:hilt-compiler:2.34.1-beta'
    
      // For instrumentation tests
      androidTestImplementation  'com.google.dagger:hilt-android-testing:2.34.1-beta'
      kaptAndroidTest 'com.google.dagger:hilt-compiler:2.34.1-beta'
    
      // For local unit tests
      testImplementation 'com.google.dagger:hilt-android-testing:2.34.1-beta'
      kaptTest 'com.google.dagger:hilt-compiler:2.34.1-beta'
    }
    
    kapt {
     correctErrorTypes true
    }
    

    Set correcterrortypes to true and configure kapt to correct errors.
    There was a problem when my gradle version was 3.4.1

    
    classpath 'com.android.tools.build:gradle:3.4.1'
    

    Apply plugin: ‘dagger. Hilt. Android. Plugin’ plug-in installation fails all the time,
    Tip: “COM / Android / version” cannot be found. Change gradle to 4.1.2
    Note that if you are a multi module project,
    Apply plugin: ‘dagger. Hit. Android. Plugin’ must be under the main module
    (that is, together with the application plugin: ‘com. Android. Application’),
    If it is only under the sub module, the injection of the main module will not be implemented. (question 1, the reason will be explained later)

    
    buildscript {
      repositories {
        // other repositories...
        mavenCentral()
      }
      dependencies {
        // other plugins...
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.34.1-beta'
      }
    }
    

    Component hierarchy

    Hilt changed Dagger’s manually created component into a predefined component, which is automatically integrated into each life cycle of Android applications. Bind @ installin (xxxcomponent. Class) by annotation.
    The following figure shows the standard hilt component hierarchy. The comments above each component are scope comments that limit the binding scope to the lifetime of the component. The arrow below the component points to any child component. Typically, a binding in a child component can depend on any binding in the ancestor component.

    Component default binding

    Each hilt component has a set of default bindings that can be injected into your custom bindings as dependencies

    Component Default Bindings
    SingletonComponent Application
    ActivityRetainedComponent Application
    ViewModelComponent SavedStateHandle
    ActivityComponent Application, Acitvity
    FragmentComponent Application, Acitvity, Fragment
    ViewComponent Application, Acitvity, View
    ViewWithFragmentComponent Application, Acitvity, Fragment, View
    ServiceComponent Application, Service

    Simple use

    Let me introduce the use of the following annotations:

    • @HiltAndroidApp
    • @AndroidEntryPoint
    • @InstallIn
    • @Module
    • @Provides
    • @Binds
    • @HiltViewModel
    • @EntryPoint

    For more suggestions, check the official documents directly

    @HiltAndroidApp

    introduce

    All apps using hilt must contain an application class annotated by @ hiltandroidapp.
    @The hiltandroidapp will generate a hilt_ The base class of myapplication, inherits the base class of the class annotated with @ hiltandroidapp, and then replaces the base class of the class annotated with @ hiltandroidapp with hilt_ MyApplication。 For example:
    This is our myapplication

    
    @HiltAndroidApp
    class MyApplication extends BaseApplication{
    }
    

    Using @ hiltandroidapp will generate a hilt_ MyApplication

    
    public abstract class Hilt_MyApplication extends BaseApplication implements GeneratedComponentManagerHolder {
      private final ApplicationComponentManager componentManager = new ApplicationComponentManager(new ComponentSupplier() {
        @Override
        public Object get() {
          return DaggerMyApplication_HiltComponents_SingletonC.builder()
              .applicationContextModule(new ApplicationContextModule(Hilt_MyApplication.this))
              .build();
        }
      });
    
      @Override
      public final ApplicationComponentManager componentManager() {
        return componentManager;
      }
    
      @Override
      public final Object generatedComponent() {
        return this.componentManager().generatedComponent();
      }
    
      @CallSuper
      @Override
      public void onCreate() {
        // This is a known unsafe cast, but is safe in the only correct use case:
        // MyApplication extends Hilt_MyApplication
        ((MyApplication_GeneratedInjector) generatedComponent()).injectMyApplication(UnsafeCasts.<MyApplication>unsafeCast(this));
        super.onCreate();
      }
    }
    

    And make our myapplication inherit hilt_ Myapplication, inject modules into our application in this way.
    You can see that the specific injection method is hilt_ In the myapplication oncreate() function
    ((MyApplication_GeneratedInjector) generatedComponent()).injectMyApplication(UnsafeCasts.unsafeCast(this));
    In this code, generatedcomponent () returns myapplication_ Hiltcomponents.singletonc object, which is the code implementation of all our modules. Interested students can go and have a look. I won’t post the code here

    use

    There are two cases of using, with and without the hilt gradle plug-in

    //No plug-ins added
    @HiltAndroidApp(BaseApplication.class)
    class MyApplication extends Hilt_MyApplication{}
    
    //Add plug-in
    @HiltAndroidApp
    class MyApplication extends BaseApplication{}

    It is recommended to add plug-ins, which will be easier to use. The following examples in this article assume to use plug-ins.
    Note that if you want to use the injected object in myapplication, you need to use it after super. Oncreate(). For the reasons, see hilt in the introduction_ Myapplication source code.
    The reason for problem 1 is that I didn’t add a plug-in, but @ hiltandroidapp uses the usage of adding a plug-in. Therefore, module injection will not be implemented.

    @AndroidEntryPoint

    introduce

    Android member injection. After @ androidentrypoint annotation is used, the member variables injected by module can be used in this class. However, @ androidentrypoint has type restrictions and can only be used on the following classes:

    1. Activity
    2. Fragment
    3. View
    4. Service
    5. BroadcastReceiver

    use

    
    @AndroidEntryPoint
    public final class MyActivity extends MyBaseActivity {
      // Bindings in SingletonComponent or ActivityComponent
      @Inject Bar bar;
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
        // Injection happens in super.onCreate().
        super.onCreate();
    
        // Do something with bar ...
      }
    }
    

    Also note that you need to use the injected member variable after super. Oncreate()

    @Module and @ installin

    introduce

    @The module is the same as that in dagger. There’s nothing to say.
    @Installin installs the module into the specified component by using @ installin (xxxcomponent. Class). This comment must be added to all modules in the hit. If the module is not found in the component, compilation errors may be caused.
    Of course, a module can also be installed on multiple components, such as: @ installin ({viewcomponent. Class, viewwithfragmentcomponent. Class})

    use

    
    @Module
    @InstallIn(SingletonComponent.class)
    public final class FooModule {
      // @InstallIn(SingletonComponent.class) module providers have access to
      // the Application binding.
      @Provides
      static Bar provideBar(Application app) {...}
    }
    

    Each component has a scope comment that can be used to remember the binding to the component lifetime. For example, to bind a scope to a singletoncomponent component, use the @ singleton annotation:

    
    @Module
    @InstallIn(SingletonComponent.class)
    public final class FooModule {
      // @Singleton providers are only called once per SingletonComponent instance.
      @Provides
      @Singleton
      static Bar provideBar() {...}
    }
    

    In addition, each component has bindings that are available by default. For example, the singletoncomponent component provides an application binding:

    
    @Module
    @InstallIn(SingletonComponent.class)
    public final class FooModule {
      // @InstallIn(SingletonComponent.class) module providers have access to
      // the Application binding.
      @Provides
      static Bar provideBar(Application app) {...}
    }
    

    @Provides and @ bindings

    introduce

    @Provides annotates the methods in the module to create a provider method binding. The return type of the method is bound to its return value.
    @Bindings annotates the abstract method in the module. The return of a general method is an interface. The parameter is a subclass that implements the interface. In the call, the method implementation in the subclass that will call the parameter.

    use

    
    @Module
    @InstallIn(SingletonComponent.class)
    public final class FooModule {
      @Provides
      @Singleton
      static Bar provideBar() {...}
    }
    
    @Module
    @InstallIn(SingletonComponent.class)
    public abstract class BindModule {  
      @Binds
      @Singleton
      abstract Random bindRandom(SecureRandom secureRandom);
    }
    

    @HiltViewModel

    introduce

    Use @ hiltviewmodel to annotate the ViewModel. When the ViewModel is created, it will be created using the hiltviewmodelfactory created by hilt. You can use the instance provided in the module when creating

    use

    
    @HiltViewModel
    public final class FooViewModel extends ViewModel {
    
      @Inject
      FooViewModel(SavedStateHandle handle, Foo foo) {
        // ...
      }
    }
    

    Then it can be used in the activity and fragment with @ androidentrypoint annotation

    
    @AndroidEntryPoint
    public final class MyActivity extends AppCompatActivity {
    
      private FooViewModel fooViewModel;
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        fooViewModel = new ViewModelProvider(this).get(FooViewModel.class);
      }
    }
    

    @EntryPoint

    introduce

    Provide injected objects where annotations cannot be used. Because @ androidentrypoint has a limited scope of use, instances that need to use hilt injection outside this scope can be implemented using @ entrypoint.
    This is like a solution that hilt can’t add methods to the component after standardizing it, so it can’t provide dependencies where annotations can’t be used.

    
    @EntryPoint
    @InstallIn(SingletonComponent.class)
    public interface FooBarInterface {
      Bar getBar();
    }
    

    If the above definition is used

    
    Bar bar = EntryPoints.get(applicationContext, FooBarInterface.class).getBar();
    

    Summary

    When I first used it, I saw the Android development platform “hilt and jetpack integration” document. It was really a pit. The document was not updated in time and the official link was not put down. Make complaints about it. Then, after several rounds of turnover and finding the official documents, we can have the honor to introduce hilt to you.
    It is much more comfortable to use than dagger, with a lot less template code, and better understanding of the binding of scope and life cycle. Not much BB learning it

    The above is the details of the use of Android hilt and the problems encountered. For more information about Android hilt, please pay attention to other relevant articles of developeppaer!

    Recommended Today

    SQL statement of three-level linkage of provinces, cities and counties

    The first is the table creation statement Copy codeThe code is as follows: CREATE TABLE `t_address_province` ( `id` INT AUTO_ Increment primary key comment ‘primary key’,`Code ` char (6) not null comment ‘province code’,`Name ` varchar (40) not null comment ‘province name’)Engine = InnoDB default charset = utf8 comment = ‘province information table’; CREATE TABLE […]