Hilt: activity 注入源码分析

59 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 13 天,点击查看活动详情

image.png

其实hilt的使用在Android比较简单,在android上面有和android组件相关的几个component以及相应是scope。还有另外一个好处就是我们不需要自己再去主动做注入了,一切由hilt自己来完成。

hilt的底层最终还是靠dagger完成的,我也比较好奇hilt是怎么和android的组件去做注入的,今天我们先看看activity是如何注入的。

我们以上一讲的例子为例开始讲,看看activity的代码:

@AndroidEntryPoint
class HiltExampleActivity : AppCompatActivity() {
    @Inject
    lateinit var myFamily: MyFamily
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_hilt_example)
        Log.i("hiltExample","my family:${myFamily.familyMember()}")
    }
}

这里我们在activity中注入了一个MyFamily的类,类的内容很简单:

class MyFamily @Inject constructor(){
    fun familyMember():List<String>{
        return listOf("sophie","leo","catherine","amy")
    }
}

这个类只是普通类,所以就直接注入就好了。

首先看生成的hilt activity的名字:Hilt_HiltExampleActivity,也就是在原来名字前面加了:Hilt_xx

@Override
public final Object generatedComponent() {
  return this.componentManager().generatedComponent();
}
​
protected ActivityComponentManager createComponentManager() {
  return new ActivityComponentManager(this);
}
​
@Override
public final ActivityComponentManager componentManager() {
  if (componentManager == null) {
    synchronized (componentManagerLock) {
      if (componentManager == null) {
        componentManager = createComponentManager();
      }
    }
  }
  return componentManager;
}

再看着三个方法,这三个方法主要是产生component的,比我们自己创建component来说它是线程安全的,先生成了一个ActivityComponentManager,再根据ActivityComponentManager生成相应的component。

Hilt_HiltExampleActivity(int contentLayoutId) {
  super(contentLayoutId);
  _initHiltInternal();
}
​
private void _initHiltInternal() {
  addOnContextAvailableListener(new OnContextAvailableListener() {
    @Override
    public void onContextAvailable(Context context) {
      inject();
    }
  });
}

再看看这两个方法,一个是acitivity的构造,另外一个就是注入实例的时机了。

public final void addOnContextAvailableListener(
        @NonNull OnContextAvailableListener listener) {
    mContextAwareHelper.addOnContextAvailableListener(listener);
}

看这个应该是在监听context Available的时机了,但是这个context available的时机又是什么呢,其实你找相应的源码就可以发现,这个其实就在acitivity的oncreate方法里面:

protected void onCreate(@Nullable Bundle savedInstanceState) {
    // Restore the Saved State first so that it is available to
    // OnContextAvailableListener instances
    mSavedStateRegistryController.performRestore(savedInstanceState);
    mContextAwareHelper.dispatchOnContextAvailable(this);
    super.onCreate(savedInstanceState);
    ReportFragment.injectIfNeededIn(this);
    if (BuildCompat.isAtLeastT()) {
        mOnBackPressedDispatcher.setOnBackInvokedDispatcher(
                Api33Impl.getOnBackInvokedDispatcher(this)
        );
    }
    if (mContentLayoutId != 0) {
        setContentView(mContentLayoutId);
    }
}

dispatchOnContextAvailable方法就是在分发inject的事件。我们再返回到上面,看看inject都干了什么:

protected void inject() {
  if (!injected) {
    injected = true;
    ((HiltExampleActivity_GeneratedInjector) this.generatedComponent()).injectHiltExampleActivity(UnsafeCasts.<HiltExampleActivity>unsafeCast(this));
  }
}

这个里面其实就在做一系列的注入工作了。

@OriginatingElement(
    topLevelClass = HiltExampleActivity.class
)
@GeneratedEntryPoint
@InstallIn(ActivityComponent.class)
public interface HiltExampleActivity_GeneratedInjector {
  void injectHiltExampleActivity(HiltExampleActivity hiltExampleActivity);
}

这个就是那个最终的AcitivityComponent,虽然和dagger里面的component不是很一样,但是功能是一样的了。

除了上面这些,hilt还会针对Activity中inject的成员生成相应的MembersInjector的provider类。以上面HiltExampleActivity注入的MyFamily为例:

public final class HiltExampleActivity_MembersInjector implements MembersInjector<HiltExampleActivity> {
  private final Provider<MyFamily> myFamilyProvider;
​
  public HiltExampleActivity_MembersInjector(Provider<MyFamily> myFamilyProvider) {
    this.myFamilyProvider = myFamilyProvider;
  }
​
  public static MembersInjector<HiltExampleActivity> create(Provider<MyFamily> myFamilyProvider) {
    return new HiltExampleActivity_MembersInjector(myFamilyProvider);
  }
​
  @Override
  public void injectMembers(HiltExampleActivity instance) {
    injectMyFamily(instance, myFamilyProvider.get());
  }
​
  @InjectedFieldSignature("com.laworks.dagger2example.HiltExampleActivity.myFamily")
  public static void injectMyFamily(HiltExampleActivity instance, MyFamily myFamily) {
    instance.myFamily = myFamily;
  }
}

首先是在构造方法里面生成provider类,然后在调用injectMyFamily方法将myFamily实例赋值给HiltExampleActivity类里面。成员的依赖注入就完成了。

需要注意一点的是,在高版本的hilt里面已经不需要依赖:

androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03

依赖这个包会一直报错,告诉你找不到相应的DefaultActivityViewModelFactory。

对于dagger的module和hilt的module如果需要混合使用,那么需要在build.gradle加上一个配置:

tasks.withType(JavaCompile) {
    configure(options) {
        options.compilerArgs << "-Adagger.hilt.disableModulesHaveInstallInCheck=true"
    }
}

然后在不需要hilt注入的module里面加上:

@DisableInstallInCheck

这样就可以使用dagger的module了。