Android进阶之光:Dagger2原理简要分析

这篇具有很好参考价值的文章主要介绍了Android进阶之光:Dagger2原理简要分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Dagger2注入框架原理简要分析

使用Dagger2需要的依赖:

implementation 'com.google.dagger:dagger-android:2.46'
implementation 'com.google.dagger:dagger-android-support:2.46'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.46'
annotationProcessor 'com.google.dagger:dagger-compiler:2.46'

示例代码:

这里先给出我的示例代码,github上的demo点这里👈

  1. MainActivity
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    @Inject
    Gson gson;

    @Inject
    Gson gson2;

    @Inject
    SwordMan swordMan;
    //@Inject
    //Car car;


    ActivityMainBinding myBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        App.get(MainActivity.this).getActivityComponent().inject(this);
        onClick();

        if(gson.hashCode() == gson2.hashCode()){
            Toast.makeText(this, "Same", Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(this, "Different", Toast.LENGTH_SHORT).show();
        }

        myBinding.btTest2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, swordMan.fighting(), Toast.LENGTH_SHORT).show();
            }
        });

    }

    private void onClick(){
        myBinding.btTest1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}
  1. SecondActivity
public class SecondActivity extends AppCompatActivity {

    ActivitySecondBinding S_Binding;

    @Inject
    Lazy<SwordMan> swordManLazy;//实现懒加载
    SwordMan swordMan = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        S_Binding = DataBindingUtil.setContentView(this,R.layout.activity_second);
        App.get(SecondActivity.this).getActivityComponent().inject(this);
        if(swordMan == null){
            Toast.makeText(this, "暂未初始化", Toast.LENGTH_SHORT).show();
        }
        swordMan = swordManLazy.get();
        //setContentView(R.layout.activity_second);
        S_Binding.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(SecondActivity.this, swordMan.fighting(), Toast.LENGTH_SHORT).show();
            }
        });

    }
}
  1. App
    注意App类需要在manifest清单文件中声明。
public class App extends Application {
    ActivityComponent activityComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        activityComponent = 
        DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
                .build();

    }

    public static App get(Context context){
        return (App) context.getApplicationContext();
    }

    ActivityComponent getActivityComponent(){
        return activityComponent;
    }
}

  1. Component类
@ApplicationScope
@Component(modules = GsonModule.class,dependencies = SwordmanComponent.class)
public interface ActivityComponent {

    void inject(MainActivity activity);
    void inject(SecondActivity activity);
}

@Component(modules = SwordmanModule.class)
public interface SwordmanComponent {
    SwordMan getSwordman();
}


  1. Module类以及实体类
@Module
public class GsonModule {
    @ApplicationScope
    @Provides
    public Gson provideGson(){
        return new Gson();
    }
}

@Module
public class SwordmanModule {

    @Provides
    public SwordMan provideSwordman(){
        return new SwordMan();
    }
}

public class SwordMan {
    @Inject
    public SwordMan(){

    }
    public String fighting(){
        return "欲为大树,莫于草争";
    }
}

生成代码分析

Dagger2是通过注解生成中间类的方式帮我们注入依赖的,我们就来分析它生成的中间类的代码。

由于注入器是在App类中初始化的,所以我们先从App类开始看,App类中最重要的无非就是这一句:

activityComponent = 
   DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
                .build();

通过DaggerActivityComonent以及builder的配置生成了一个注入器接口的实现类,所以我们先看DaggerActivityComponent类

DaggerActivityComponent类

public final class DaggerActivityComponent {
  private DaggerActivityComponent() {
  }

  public static Builder builder() {
    return new Builder();
  }

  public static final class Builder {
    private GsonModule gsonModule;

    private SwordmanComponent swordmanComponent;

    private Builder() {
    }

    public Builder gsonModule(GsonModule gsonModule) {
      this.gsonModule = Preconditions.checkNotNull(gsonModule);
      return this;
    }

    public Builder swordmanComponent(SwordmanComponent swordmanComponent) {
      this.swordmanComponent = Preconditions.checkNotNull(swordmanComponent);
      return this;
    }

    public ActivityComponent build() {
      if (gsonModule == null) {
        this.gsonModule = new GsonModule();
      }
      Preconditions.checkBuilderRequirement(swordmanComponent, SwordmanComponent.class);
      return new ActivityComponentImpl(gsonModule, swordmanComponent);
    }
  }

  private static final class ActivityComponentImpl implements ActivityComponent {
    	...
    }
}

我们先来看前面有关Builder的方法,由于我们在Activity的Component注解中添加了modules和dependencies的值,所以在builder中就会生成响应的gsonModule(GsonModule gsonModule)和swordmanComponent(SwordmanComponent swordmanComponent)方法,这两个方法分别是用来设置生成的注入器中的gsonModule和swordmanComponent对象的。

通过App类中的调用的代码我们可以发现,对于注解中的modules,我们在创建注入器的时候是不需要手动添加的,但是对dependencies注解来说就需要手动添加:

DaggerActivityComponent.builder().swordmanComponent(DaggerSwordmanComponent.builder().build())
                .build();//手动添加了DaggerSwordmanComponent的注入器

builder中的Preconditions.checkNotNull()只是用来判空的,总的来说,builder这个内部类就是用来帮助构建注入器实例的。所以我们接下来就来看这个注入器实例:

  private static final class ActivityComponentImpl implements ActivityComponent {
    private final SwordmanComponent swordmanComponent;

    private final ActivityComponentImpl activityComponentImpl = this;

    private Provider<Gson> provideGsonProvider;

    private Provider<SwordMan> getSwordmanProvider;

    private ActivityComponentImpl(GsonModule gsonModuleParam,
        SwordmanComponent swordmanComponentParam) {
      this.swordmanComponent = swordmanComponentParam;
      initialize(gsonModuleParam, swordmanComponentParam);

    }

    @SuppressWarnings("unchecked")
    private void initialize(final GsonModule gsonModuleParam,
       final SwordmanComponent swordmanComponentParam) {
      this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam));
      this.getSwordmanProvider = new GetSwordmanProvider(swordmanComponentParam);
    }

    @Override
    public void inject(MainActivity activity) {
      injectMainActivity(activity);
    }

    @Override
    public void inject(SecondActivity activity) {
      injectSecondActivity(activity);
    }

    private MainActivity injectMainActivity(MainActivity instance) {
		...
    }

    private SecondActivity injectSecondActivity(SecondActivity instance) {
      	...
    }

    private static final class GetSwordmanProvider implements Provider<SwordMan> {
      ...
    }
  }

先不看最后一个内部类,先看注入器类ActivityComponentImpl 实现了 ActivityComponent 接口,也就是说它就是实际的注入器类,这个类的构造方法是私有的,说明只能通过构造器来构造实例。先关注它的构造方法,构造方法传入的参数正是我们在Component接口的注解中写入的值:

@Component(modules = GsonModule.class,dependencies = SwordmanComponent.class)
...
private void initialize(final GsonModule gsonModuleParam,
       final SwordmanComponent swordmanComponentParam){
       ...
       }

传入了一个GsonModule和一个SwordmanComponent,和目前这个ActivityComponent类似,这个SwordmanComponent肯定也是有一个实现类的,我们后面再看这两个类的具体内容。

接着我们接续看它的注入依赖的方法,我们在注入依赖时,显然是用到了inject方法,对应不同的注入对象,将会调用不同的inject的重载方法,我们先看MainActivity的注入方法:

private MainActivity injectMainActivity(MainActivity instance) {
      MainActivity_MembersInjector.injectGson(instance, provideGsonProvider.get());
      MainActivity_MembersInjector.injectGson2(instance, provideGsonProvider.get());
      MainActivity_MembersInjector.injectSwordMan(instance, Preconditions.checkNotNullFromComponent(swordmanComponent.getSwordman()));
      return instance;
    }

injectMainActivity中分别调用了注入的方法,很显然,就是将我们在MainActivity中标记为需要注入的变量给注入参数,我们接下来看这个MainActivity_MembersInjector中间类。

MainActivity_MembersInjector

就这个类的命名来说,它应该是具体负责成员变量注入依赖的注入器。前面说到在ActivityComponentImpl调用了它的injectGson等方法,我们来看这三个方法:

@InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.gson")
  public static void injectGson(MainActivity instance, Gson gson) {
    instance.gson = gson;
  }

  @InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.gson2")
  public static void injectGson2(MainActivity instance, Gson gson2) {
    instance.gson2 = gson2;
  }

  @InjectedFieldSignature("com.example.dagger2demo.activitys.MainActivity.swordMan")
  public static void injectSwordMan(MainActivity instance, SwordMan swordMan) {
    instance.swordMan = swordMan;
  }

看到这里,这三个方法的作用已经非常明显了,将我们需要注入依赖的对象传入这三个方法中,方法就会给需要注入依赖对象中标记为@Inject的成员变量赋值。至于这个@InjectedFieldSignature注解,@InjectedFieldSignature注解是Dagger中的一个自定义注解,用于帮助Dagger在运行时自动生成代码以实现依赖注入。它用于标记要进行依赖注入的字段,并提供了一个字符串参数,用于标识该字段所依赖的对象的类型。在运行时,Dagger会扫描这些注解并自动生成相应的代码,以实现将依赖注入到被标记的字段中。

何处真正产生了实际参数

这时候新的问题产生了,这些被注入的参数是在哪里被初始化的呢,换句话说,injectGson()方法中的第二个参数gson是在哪里被开辟空间的呢,答案就在之前的ActivityComponentImpl中:

 private MainActivity injectMainActivity(MainActivity instance) {
      MainActivity_MembersInjector.injectGson(instance, provideGsonProvider.get());
 		...
    }

从这里可以看出,这个实际被注入的参数是由provideGsonProvider的get方法提供的:

   @SuppressWarnings("unchecked")
    private void initialize(final GsonModule gsonModuleParam,
        final SwordmanComponent swordmanComponentParam) {
      this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam));
      this.getSwordmanProvider = new GetSwordmanProvider(swordmanComponentParam);
    }
	...
	public final class GsonModule_ProvideGsonFactory implements Factory<Gson> {
	  
	  private final GsonModule module;
	
	  public GsonModule_ProvideGsonFactory(GsonModule module) {
	    this.module = module;
	  }
	
	  @Override
	  public Gson get() {
	    return provideGson(module);
	  }
	
	  public static GsonModule_ProvideGsonFactory create(GsonModule module) {
	    return new GsonModule_ProvideGsonFactory(module);
	  }
	
	  public static Gson provideGson(GsonModule instance) {
	    return Preconditions.checkNotNullFromProvides(instance.provideGson());
	  }
	  
	}

这里DoubleCheck 是 Dagger2 中的一个工具类,用于确保依赖只被创建一次,具体来说,由于我们在注入器接口中标记了被注入参数的作用域,所以会调用DoubleCheck方法。紧接着我们看GsonModule_ProvideGsonFactory,很显然实现调用了create方法,但是create方法又是实际调用了GsonModule_ProvideGsonFactory的构造方法,这里传入了GsonModule类,还记得GsonModule类吗?正是我们自己写的实例提供者。

现在我们继续返回到ActivityComponentImpl中,看这个GsonModule的实例在哪里,答案在builder中。我们先一个一个往前捋:

首先在initialize方法中调用了create:

this.provideGsonProvider = DoubleCheck.provider(GsonModule_ProvideGsonFactory.create(gsonModuleParam))

所以我们需要看initialize方法中传入的GsonModule实例来自哪里,是来自ActivityComponentImpl的构造方法中:

private ActivityComponentImpl(GsonModule gsonModuleParam,
        SwordmanComponent swordmanComponentParam) {
      this.swordmanComponent = swordmanComponentParam;
      initialize(gsonModuleParam, swordmanComponentParam);

    }

那这个构造方法中的GsonModule来自哪里呢,之前我们提到过,由于这个构造方法是私有的,所以我们只能通过构造器builder来创建,所以答案显然是在builder这个内部类中:

    public ActivityComponent build() {
      if (gsonModule == null) {
        this.gsonModule = new GsonModule();
      }
      Preconditions.checkBuilderRequirement(swordmanComponent, SwordmanComponent.class);
      return new ActivityComponentImpl(gsonModule, swordmanComponent);
    }

这个GsonModule类的实例正是调用了我们写的GsonModule的构造方法,所以我们可以画出传递的流程图:

简要流程图(仅适用于本示例)

Android进阶之光:Dagger2原理简要分析

简而言之,Dagger2正是通过APT和生成的中间件代码来实现依赖注入的。文章来源地址https://www.toymoban.com/news/detail-432831.html

到了这里,关于Android进阶之光:Dagger2原理简要分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android内存泄漏分析及检测工具LeakCanary简介,Android进阶

    @Synchronized override fun expectWeaklyReachable( watchedObject: Any, description: String ) { if (!isEnabled()) { return } removeWeaklyReachableObjects() val key = UUID.randomUUID() .toString() val watchUptimeMillis = clock.uptimeMillis() val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue) SharkLog.d { \\\"Watching \\\" +

    2024年04月25日
    浏览(41)
  • JAVASE进阶:强推!源码分析——字符串拼接底层原理、StringBuilder底层原理

    👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习 🌌上期文章:JAVASE进阶:String常量池内存原理分析、字符串输入源码分析 📚订阅专栏:JAVASE进阶 希望文章对你们有所帮助 这是比较重要的内容,学习原理很重要,啃源码也很重要!!! 字符串 常量 的

    2024年02月20日
    浏览(45)
  • Android进阶宝典 —如何通过ANR日志分析问题原因

    当系统发生ANR时,会主动dump trace日志并保存在data/anr/trace.txt文件夹下,我们在拿到anr日志之后,就可以着手分析日志;或者可以通过bugreport命令来拉取日志,具体命令如下: 当然我们在解读日志的时候,肯定是需要一些去查询,判断到底是哪种类型的问题导致了ANR。

    2024年02月05日
    浏览(48)
  • Android 进阶——Binder IPC之Binder IPC架构及原理概述(九)

    前面几篇文章,为我们学习Binder IPC通信机制提供了扎实的理论基础,接下来将正式进入Binder IPC通信架构及原理的解读。 Binder 是基于 C/S 架构的,由一系列的组件组成,包括 Client进程、Server进程、Service Manager进程、Binder 驱动。其中 Client进程、Server进程、Service Manager进程运行

    2023年04月09日
    浏览(46)
  • Android APK 签名打包原理分析(二)【Android签名原理】

    说到签名,从这个词来理解,正常个人需要签名的时候,一般是用来证明这是某个人的特属认证。 大家是否有印象?还记得我们之前在学习、总结网络相关知识的时候,说到过,客户端和服务端虽然通信数据上,可以采用对称加密和非对称加密组合去进行数据的加密,但是这

    2024年01月18日
    浏览(55)
  • Android Okhttp3添加https自签名证书以及Glide4,Android高级工程师进阶学习—Android热修复原理

    二、自签名证书 什么是自签名证书(self-signed certicates)? 自签名证书就是没有通过受信任的证书颁发机构, 自己给自己颁发的证书. SSL 证书大致分三类: 由安卓认可的证书颁发机构CA(Certificate Authority)(如: VeriSign、DigiCert), 或这些机构的下属机构颁发的证书. 没有得到安卓认可的

    2024年04月17日
    浏览(41)
  • [Android 13]开机动画原理分析

    hongxi.zhu 2023-6-12 Lineageos_20(Android T) on Pixel 2XL 1.1 init.rc启动相应的进程 开机动画跑起来除了需要自身进程的启动外,还肯定以来显示系统的相关进程,即一定需要SurfaceFlinger的进程的合成和送显,所以这里需要启动SurfaceFlinger服务和bootanim服务,两者是在init.rc中启动。rc的触发阶

    2024年02月09日
    浏览(48)
  • 几种文本向量化方式原理简要介绍

    TfIdf           TfIdf向量化是基于TF-IDF算法的一种文本向量化方法;TF-IDF全称:term frequency–inverse document frequency,词频-逆向文件频率,其主要思想是:如果某个单词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适

    2024年02月13日
    浏览(42)
  • Kafka源码简要分析

    目录 一、生产者的初始化流程 二、生产者到缓冲队列的流程 三、Sender拉取数据到Kafka流程 四、消费者初始化 五、主题订阅原理 六、消费者抓取数据原理 七、消费者组初始化 八、消费者组消费流程 九、提交offset原理 首先获取事务id和客户端id(用到事物必须要事物id不然报

    2024年02月07日
    浏览(35)
  • 搜索引擎系统简要分析

    目录 一、搜索引擎简单介绍 二、搜索引擎整体架构和工作过程 (一)整体分析 (二)爬虫系统 三个基本点 爬虫系统的工作流程 关键考虑因素和挑战 (三)索引系统 网页处理阶段 预处理阶段 反作弊分析阶段 索引生成阶段 索引拆分 索引构建 索引更新 (四)检索系统 查

    2024年02月04日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包