Hilt

   依赖注入是一种广泛用于编程的技术。

1、依赖注入的优势

   1.1、重用代码
  能够复用一部分公共逻辑,比如如下的start()里面的一些操作,比如创建Engine、创建Car的操作。
   1.2、易于重构
   1.3、易于测试

class Car {
    private final Engine engine;
    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.start();
    }
}

  对于2和3的理解,Engine可能有子类,使用的时候才注入(传入)具体的对象,这样对于扩展是开放的,方便重构和测试。反观如果在这个类中直接创建Engine对象或者子类,非常不便于扩展和测试。
  上述代码是通过手动实现依赖注入。Hilt、Dagger2是一个在自动实现依赖注入的框架,本文主要介绍Hilt注入框架。

2、Hilt使用

2.1、对象注入,通过构造函数提供注入对象。

public class PersonBean {

    String name;
    int age;

    public PersonBean(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Inject
    public PersonBean() {
    }
}

2.2、对象注入,通过@Provides和@Moudle提供注入的对象。

@Module
@InstallIn(value = FragmentComponent.class)
public class PersonModule {

    @Provides
    public static PersonBean getPerson() {
        return new PersonBean("one_fragment", 1);
    }
}

2.3、接口对象(或者抽象类对象)的注入,通过@Binds和@Moudle获取具体的注入对象。

public interface AnalyticsService {
  void analyticsMethods();
}
public class AnalyticsServiceImpl implements AnalyticsService {
  ...
  @Inject
  AnalyticsServiceImpl(...) {
    ...
  }
}

@Module
@InstallIn(ActivityComponent.class)
public abstract class AnalyticsModule {

  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

  @Binds函数返回类型会告知 Hilt 该函数提供哪个接口的实例。
  @Binds 函数参数会告知 Hilt 要提供哪种实现。

2.4、对象注入,通过@EntryPoint 注入。
  这种注入方式适合,某些类不支持hilt注入。例如ContentProvider,成员变量就不能通过hilt注入,因为整个hilt注入的起点是在Application的OnCreate,ContentProvider在此之前就初始化了。

@InstallIn(ActivityComponent.class)
@EntryPoint
public interface StudentPoint {

    public Student getStudent();
}

@AndroidEntryPoint()
class EnterPointActivity : AppCompatActivity() {

    private val TAG = "EnterPointActivity"

    @Inject
    lateinit var  student1 : Student

    @Inject
    lateinit var cpBean: CpBean

    @Inject
    lateinit var sound: Sound

    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_enter_point)
        var point = EntryPointAccessors.fromActivity(this, StudentPoint::class.java)
        var student = point.student
    }
}

2.5、Component
  注入的对象的访问入口是Component,也就是所有注入对象的容器。
  Dagger框架中可以手动定义Component和SubComponent和子的SubComponent,导致Component较多,各个Component之间的Scope、moudle的关系,难以维护。
   Hilt将Component容器进行了分类。


组件的生命周期

组件作用域
@Module
@InstallIn(ActivityComponent.class)
public abstract class HiltStudentMoudle {

    @Provides
    public static CpBean getCpBean() {
        return new CpBean("张三", 34);
    }

    @Binds
    public abstract Sound bindSound(SoundImpl sound);

    @Provides
    @ActivityScoped
    public static Student getStudent() {
        return new Student("李四", 22);
    }
}

  上述加入@ActivityScoped注解,在同一个Activity(fragment,view)中,获取的Student对象,就是个单例。


组件的层次结构

  子组件可以使用父组件的绑定作为子组件的依赖项。ViewComponent 可以使用 ActivityComponent 中定义的绑定的依赖项。

3、HiltAndroidApp

  @HiltAndroidApp注解与@AndroidEntryPoint注解类似,只不过HiltAndroidApp会触发Dagger代码的生成。@AndroidEntryPoint主要将activity、fragment、view等注入到标准的android component中。

@HiltAndroidApp
public class ExampleApplication extends Application { ... }
4、总结

   Hilt与Dagger2对比,Hilt对Component、Scope进行了细分,防止创建过多的Component和SubComponent,注入的依赖对象生命周期由Component生命周期管理,各个Component、module依赖关系更加清晰。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容