ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

android_框架_hilt

2021-11-13 09:33:18  阅读:285  来源: 互联网

标签:Woman 框架 hilt public IPerson android class Inject


转载自: 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

标签:Woman,框架,hilt,public,IPerson,android,class,Inject
来源: https://blog.csdn.net/qq_42420293/article/details/121300028

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有