android_框架_hilt

转载自: https://www.jianshu.com/p/818f91376d1f

相关资料

https://developer.android.com/codelabs/android-hilt?hl=zh-cn#11

https://developer.android.com/training/dependency-injection/hilt-android

https://blog.csdn.net/guolin_blog/article/details/109787732

项目引用

注意: 同时使用 Hilt 和数据绑定的项目需要 Android Studio 4.0 或更高版本

项目的根级 build.gradle添加

    buildscript {
     ...
     dependencies {
     ...
     classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
     }
    }

然后,应用 Gradle 插件并在 app/build.gradle 文件中添加以下依赖项:

    apply plugin: 'kotlin-kapt'
    apply plugin: 'dagger.hilt.android.plugin'
    
    android {
     ...
    }
    
    dependencies {
     implementation "com.google.dagger:hilt-android:2.28-alpha"
     kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
    }

Hilt 使用 Java 8 功能,将以下代码添加到 app/build.gradle 文件中:

    android {
     ...
     compileOptions {
     sourceCompatibility JavaVersion.VERSION_1_8
     targetCompatibility JavaVersion.VERSION_1_8
     }
    }

注解关键字

@HiltAndroidApp

使用在Application上,不用就报错

@AndroidEntryPoint

使用在要注入的地方的类上

@InstallIn

作用在Module上,标明作用域范围。

@Inject

用在要注入的类的构造参数上

@Binds

标记抽象方法, 返回接口类型, 实现是方法的唯一参数.

@Named

别名,基本用于接口多实现/多构造参数时候

@Provides

用在方法上, 提供返回值类型的依赖,

@Singleton

单例

@Qualifier

用在注解上,注解用来区分要提供的参数

@Module

用在类上,标记这是一个module. 在Kotlin代码中, module可以是一个Object.

@ViewScoped

用于提供对象的方法上,标识为作用于view范围

@ServiceScoped

用于提供对象的方法上,标识为作用于Service范围

@FragmentScoped

用于提供对象的方法上,标识为作用于Fragment范围

@ActivityScoped

用于提供对象的方法上,标识为作用于Activity范围

@ActivityRetainedScoped

用于提供对象的方法上,标识为作用于ViewModle

@ActivityContext

内置的Activity类型Context,当做参数的时候会默认提供一个ActivityContext,而不用再传参

@ApplicationContext

内置的Application类型Context,当做参数的时候会默认提供一个Application 类型的Context,而不用再传参

注解使用

@HiltAndroidApp

使用hilt首先要在Application上添加 不然会报错

Hilt Activity must be attached to an @AndroidEntryPoint Application.

    @HiltAndroidApp
    public class HiltDemoApp extends Application {
    }
@AndroidEntryPoint

@AndroidEntryPoint 添加在要注入类的对象顶部,不添加直接报null指针错误。

    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
     @Inject
     Man man;
    }
@Inject

@Inject 用的地方有两处。如下

  • 用在要注入对象里,就是告知 要注入哪个构造参数 用来实例化
    public class Man implements IPerson {
        
         @Inject
         public Man() {
    
         }
         @Override
         public void say() {
    
         }
        }
  • 在注入的页面里或者对象里 代表我要注入一个该类型对象
     @AndroidEntryPoint
        public class MainActivity extends AppCompatActivity {
         @Inject
         IPerson man;
        
        }
@Binds

官网说 标记抽象方法, 返回接口类型, 实现是方法的唯一参数。我总结如下

  • 用在modle里

  • 作用在抽象方法上

  • 返回你传入的参数类型,也就是参数括号里传啥返回啥

  • 返回值如果是接口的时候,则该接口只有一个实现。 在使用的地方可以直接用 xxx接口 对象的方法中注入如下。

    @Binds
    abstract IPerson getWoMan( Woman man);
    

    @Inject
    IPerson woman;

如果返回值是接口,且有多个实现的时候,那么需要处理。需要添加一个注解进行区分,下面注解部分会详细说。或者使用@Named(“xxx”)进行区分

    @ManTag
    @Binds
    abstract IPerson getMan( Man man);
    
    
    @WoManTag
    @Binds
    abstract IPerson getWoMan( Woman man);
    

     @ManTag
     @Inject
     IPerson man;
     @WoManTag
     @Inject
     IPerson woman;
@Module

对外提供对象

@Module 使用场景有两种

@Binds 和@ Provides

注意事项

  • @Binds和@Provides不能放在同一个module里.

  • @Provides和@Inject冲突

  • @Named和@自定义注释效果一样

  • 使用@Binds Modle 类是个抽象类,方法是抽象方法,传参是要返回的对象类型

  • 使用@Provides Modle 类不能是抽象类

  • 使用 @Module 必须 使用 @InstallIn添加使用范围

使用@Module 个人认为大部分为了解决下面几个问题

  • 对象构造带参数/多构造

  • 返回值为接口,实现对象唯一

  • 返回值为接口 但是接口实现不唯一

  • 返回对象 不能直接new,比如三方对象

@Binds 基础用法 接口单实现

IPerson 是一个接口 当前只有Man类实现,这么写注入正常。对了记得在Man 构造添加 @Inject

    //Module
    @Module
    @InstallIn(ActivityComponent.class)
    abstract class PersonModel {
     @Binds
     abstract IPerson getMan( Man man);
    }
    
    
    //注入
    @Module
    @InstallIn(ActivityComponent.class)
    abstract class PersonModel {
    
     @Binds
     abstract IPerson getMan( Man man);}
    
    public class Man implements IPerson {
    
     //记得添加@Inject
     @Inject
     public Man() {
    
     }
    
     @Override
     public void say() {
    
     }
    }

当 IPerson 多实现的时候,我们只对外提供Man,上面代码还不会有问题,但是我们添加Woman的提供时候,就有问题了。代码如下。其实想想也是,多实现,你直接接口注入,谁知道要Man还是Woman

    //Iperson 多实现的时候
    public class Woman implements IPerson {
     public Woman() {
    
     }
    
     @Override
     public void say() {
    
     }
    }

    
    
    
    // 添加对外提供woMan方法
    @Module
    @InstallIn(ActivityComponent.class)
    abstract class PersonModel {
    
     //提供Man
     @Binds
     abstract IPerson getMan( Man man);
    
    
     //提供Woman
     @Binds
     abstract IPerson getWoMan( Woman man);
    
    
    }
    
    //注入点
    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
    
    
     @Inject
     IPerson person;}

解决方案

@Named("xxx")

    //利用@Named区分
    @Module
    @InstallIn(ActivityComponent.class)
    abstract class PersonModel {
    
     @Named("Man")
     @Binds
     abstract IPerson getMan( Man man);
    
    
     @Named("Woman")
     @Binds
     abstract IPerson getWoMan( Woman man);
    
    
    }
    
    
    //注入 利用@Named区分
    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
    
     @Named("Man")
     @Inject
     IPerson man;
    
     @Named("Woman")
     @Inject
     IPerson woMan;}

@自定义注解 这里 会用到@Qualifier

定义两个注解,在注入的时候添加。

其实自定义注解和@Named 其实就是起别名操作方式。看个人需求选择吧

    //ManTag
    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @interface ManTag {
    }
    
    //WoManTag
    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @interface WoManTag {
    }
    
    
    //注入
    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
    
     @ManTag
     @Inject
     IPerson man;
    
     @WoManTag
     @Inject
     IPerson woMan;}
@Provides

适宜用情况

  • 多构造参数(无法通过构造函数注入)

  • 接口多实现

  • 某个类不归自己所有,类无法直接创建(RetrofitOkHttpClient 或Room 数据库这种)

注意:

  • 带参数的就不要带@Inject了,Inject在多构造参数的时候会报错。

  • 使用Provides @Moulde 类不能是抽象类

小tips:

  • 函数返回类型会告知 Hilt 函数提供哪个类型的实例。

  • 函数参数会告知 Hilt 相应类型的依赖项。

  • 函数主体会告知 Hilt 如何提供相应类型的实例。每当需要提供该类型的实例时,Hilt 都会执行函数主体。

    在@Provides上 也可以用@Named 区分具体注入类型, 也可以使用自定义注解

    //我们给Woman添加一个带参的构造 注意 用@Provides 构造就不用加@Inject了
    public class Woman implements IPerson {
    
     public Woman() {
     }
    
    
     public Woman(String name) {
     }
     @Override
     public void say() {
    
     }
    
    
    }
    
    
    
    
    //module 
    @Module
    @InstallIn(ActivityComponent.class)
    public class ProvideModel {
    
     //返回Man类型
     @Provides
     @ManTag
     public IPerson getMan() {
     return new Man();
     }
    
     //返回Woman无参构造
     @WoManTag
     @Provides
     public IPerson getManName() {
     return new Woman();
     }
    
    
     //返回Woman 带参构造
     @WoManNameTag
     @Provides
     public IPerson getWoManByName() {
     return new Woman("lili");
     }
    
     //返回第三方对象
     @Provides
     public static OkHttpClient getOkHttp() {
     return new OkHttpClient();
     }
    
    
    }
    
    //注入点
    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
    
     @ManTag
     @Inject
     IPerson man;
    
     @WoManTag
     @Inject
     IPerson woMan;
    
     @WoManNameTag
     @Inject
     IPerson woManName;
    
     @Inject
     OkHttpClient okHttpClient;
    
    }
@InstallIn
@InstallIn()括号里类类的范围

*   ApplicationComponent
    
*   ActivityComponent.class
    
*   ActivityRetainedComponent.class
    
*   FragmentComponent.class
    
*   ServiceComponent.class
    
*   ViewComponent.class
    
*   ViewWithFragmentComponent.class

如名字所见,当前module作用范围 可以是整个Application,也可以是某个view。ActivityRetainedComponent.class很特殊,对应是ViewModle。

如何限定提供的对象的使用范围,如下。

scopes

@ViewScoped

@ServiceScoped

@FragmentScoped

@ActivityScoped

@ActivityRetainedScoped

    //作用范围在activity 同理切换就可以了
    @ActivityScoped
    @WoManTag
    @Provides
    public IPerson getManName() {
     return new Woman();
    }

下面几张图是我截取的官网的图,可以看下作用域,和上下级绑定,生命周期等

组件的作用域注释

image.png

组件默认绑定

image.png

image.png

组默认绑定

image.png

组件生命周期

image.png

作用域

image.png

@Singleton

单例,当作用域@Module中的时候,要求@InstallIn后面跟的必须是ApplicationComponent.class。其实想想也是,单例生命周期和APP同样长。

导入Context

当需要的参数包含Contxt的时候,Hilt内部提供如下Contenxt ,作为参数传入即可。

  • @ApplicationContext

  • @ActivityContext

注意事项:如果@InstallIn 添加的是ActivityComponent.class ,

下面@Provides 里是@ApplicationContext,会报错。当前module中有@Singleton 则@InstallIn 那里肯定要是ApplicationComponent.class 。下面@Provides 写@ActivityContext 也会报错 。@InstallIn和Context 要统一级别。

给WoMan添加一个需要context的参数
    public class Woman implements IPerson {
    
    
     public Woman(Context context, String name) {
     }
    
     @Override
     public void say() {
    
     }
    }
    
    //module中 这么提供就可以了 系统会自动填充一个Context
    @Module
    @InstallIn(ActivityComponent.class)
    public class ProvideModel {
    
     @WoManContextTag
     @Provides
     public IPerson getWoManByContext(@ActivityContext Context context) {
     return new Woman(context, "lili");
     }
    
    }

viewModel

依赖
    implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
    // When using Kotlin.
    kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
    // When using Java.
    annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
代码 @ViewModelInject和@Assisted
    //使用    @ViewModelInject
    public class HiltViewModel extends ViewModel {
        @ViewModelInject
        public HiltViewModel() {
        }
    
    
    
        public void getData(){};
    }
    
    //@Assisted
     @ViewModelInject
        public HiltViewModel(@Assisted SavedStateHandle savedStateHandle) {
            
        }
    
    
    //使用
    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
    
        private HiltViewModel hiltViewModel;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
    
            hiltViewModel =new ViewModelProvider(this).get(HiltViewModel.class);
            hiltViewModel.getData();
    
        }}

WorkManger

依赖
     implementation 'androidx.hilt:hilt-work:1.0.0-alpha01'
      // When using Kotlin.
      kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
      // When using Java.
      annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
注意

在 Worker 对象的构造函数中使用 @WorkerInject 注释来注入一个 Worker。您只能在 Worker 对象中使用 @Singleton 或未限定作用域的绑定。您还必须使用 @Assisted 为 Context 和 WorkerParameters 依赖项添加注释:

    @HiltAndroidApp
    public class HiltDemoApp extends Application implements Configuration.Provider {
    
        @Inject
        HiltWorkerFactory workerFactory;
    
        @NonNull
        @NotNull
        @Override
        public Configuration getWorkManagerConfiguration() {
            return new Configuration.Builder().setWorkerFactory(workerFactory).build();
        }
      
    }
    
    
    
    //感觉work 使用率还是比较低的
    public  class HiltWorkManger  extends Worker {
        private static final String TAG = "HiltWorkManger";
        @WorkerInject
        public HiltWorkManger(@Assisted @NonNull @NotNull Context context, @Assisted @NonNull @NotNull WorkerParameters workerParams) {
            super(context, workerParams);
        }
    
        @NonNull
        @NotNull
        @Override
        public Result doWork() {
            return Result.success();
        }
    }

@EntryPoint

其实这个@EntryPoint 个人不是搞的很明白,但是感觉使用概率不高

看代码和注释

    // @InstallIn 
    //@EntryPoint 注入点 要注意是接口 返回你要注入的对象
    public class EntryModel {
        @InstallIn(ActivityComponent.class)
        @EntryPoint
        public interface IEntryPointModel {
            DemoEntry getEntry();
        }
    
    }
    
    //注入的对象 要注入的构造要有@Inject
    public class DemoEntry {
        private String name;
    
        @Inject
        public DemoEntry() {
        }
    
        public String getName() {
            return "9999";
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    //注入点 EntryPointAccessors 是个关键点 
    //EntryPointAccessors 通过接口 调用返回的注入对象
    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
    
        @Inject
        DemoEntry demoEntry;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
    
            this.demoEntry = EntryPointAccessors.fromActivity(this, IEntryPoint.class).getDemoEntry();
            
        }}

image.png

上一篇:vue中的inject


下一篇:windowsserver2008 用户组管理