Dagger2初使用

Dagger2使用

(Dagger1就不谈了,直接开始说Dagger2)

带点夸张描述Dagger2的作用:定义一个变量,不需要实例化直接就可以使用。

Dagger2依赖注入的基本实现

其实并不是不需要实例化,只是改变了传统实例化的过程,不需要再在使用的地方进行实例化。
我们平时对一个变量实例化和使用的过程是怎样的呢?

    class A{
        B b;
        C c;

        public void test(){
            b = new B(...);
            c = new C(...);

            b.xxx();
            c.yyy();
        }
    }

而使用Dagger2依赖注入是怎么样的呢?

    class A{
        @Inject
        B b;
        @Inject
        C c;

        public void test(){
//            b = new B(...);
//            c = new C(...);

            b.xxx();
            c.yyy();
        }
    }

这里只是为了直观感受,实际还有其他代码。毕竟,不可能定义一个变量,凭空就实例化了。
Dagger2提供实例的方式有两种:

  • 一种是通过Module@Provide标注的方法直接提供实例,Module类需要用@Module注解标注
@Module
public class MainModule {
    private MainView mMainView;

    public MainModule(MainView mainView) {
        mMainView = mainView;
    }

    @Provides
    public MainView provideMainView() {
        return mMainView;
    }

}
  • 另一种是Dagger2生成的代码里会调用通过@Inject标注的构造方法,然后生成实例。一个类不能有多个带@Inject标识的构造方法。否则Dagger2就无法判断使用哪一个,会抛出异常。
public class MainPresenter {

    MainView mMainView;

    @Inject
    public MainPresenter(MainView mainView) {
        mMainView = mainView;
    }

    public void loadUserInfo() {
        //假装获取了数据- -
        UserInfo userInfo = new UserInfo("灰来灰去");

        mMainView.showName(userInfo.getName());//显示名称
    }
}

看到“这里Dagger2生成的代码”这里,就不得不说Dagger2的机制了,Dagger1使用了反射,而到了Dagger2就完全抛弃了反射,使用预编译的方式。Rebuild Project后,在build/generated/source/apt/debug下对应的包里,会生成需要的类,Dagger2就是通过这些类,来进行实例的注入。
Dagger2生成的代码
而这些关系是通过Component来建立的,Component需要@Component注解标注,可设置关联的Module(可的意思就是也可不设置),MainComponent会生成一个对应的DaggerMainComponent类。

public class MainActivity extends AppCompatActivity implements MainView {

    @Inject
    MainPresenter mMainPresenter;

    @Bind(R.id.main_txt_name)
    TextView mNameTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build()
                .inject(this);
    }

    @OnClick(R.id.main_btn_show_name)
    public void onClickShowName(View v) {
        mMainPresenter.loadUserInfo();
    }

    @Override
    public void showName(String name) {
        mNameTxt.setText(name);
    }
}

获取实例的逻辑是:
优先判断对应Module里面有没有直接提供,若没有则通过@Inject标注的构造方法生成。若构造方法里有参数则递归重复此流程。

@Inject

在定义变量处标注,代表此属性使用依赖注入,不需要通过new 来实例化。
在构造方法处标注,代表此构造方法可直接注入到目标属性。
一个类不能有多个带@Inject标识的构造方法。

@Module

相当于工厂模式的Factory,内部是@Provides标注的方法,负责提供生成类实例的方法。

@Provides

在Module里,标注负责提供生成类实例的方法。

@Qualifier

当一个类在Module中有多个@Provides标识的方法可创建实例时。Dagger2无法潘达判断使用哪一个方法来生成实例。此时就需要通过@Qualifier来区分使用哪一个方法创建实例。
@Qualifier不是用来直接标注的,他是需要新建注解,用@Qualifier来标注这个新建的注解。以下都用@MyQualifier表示

  • 一种是每一次区分都新建一个@MyQualifier标识的注解,分别标识在@Provides的位置,和@Inject需要注入的位置
  • 另一种则是新建一个@MyQualifier标识的注解,通过value的值来区分,Dagger2本身也提供了一个@Named
    @Provides
    @Named(value = "jph")
    public UserInfo provideJPHUserInfo() {
        return new UserInfo("jph");
    }

    @Provides
    @Named(value = "hui")
    public UserInfo provideHuiUserInfo() {
        return new UserInfo("灰来灰去");
    }
    @Inject
    @Named(value = "hui")
    UserInfo userInfo;

若是构造方法的参数:

    @Inject
    public MainPresenter(MainView mainView, @Named(value = "jph") UserInfo userInfo) {
        mMainView = mainView;
        mUserInfo = userInfo;
    }

@Scope

@Qualifier一样,@Scope也是用来标识新建注解的,以下用@MyScope表示

  • @MyScope标注的 Component,如果 Moudle 中的 @Provides 也被@MyScope标注,那么在这个Component的生命周期内 ,这个 provide提供的对象是单例的。具体是通过DoubleCheck这个类实现的。
  • 通过构造方法标注@Inject进行注入的,@MyScope标注在类名处。
  • Provides处标记了@MyScope,则对应的Component也必须标注,但是标注了@MyScopeComponent对应Module中的Provides不是必须标注@MyScope
  • 会判断依赖的Component之间是否都使用了@MyScope标识,未标注@Scope的Component不能依赖标注了@Scope的Component。

不同的@MyScope之间功能没有任何差别,只是定义不同的名字,方便理解。比如比较常见的定义@PerActivity,一般就是代表和Activity的生命周期对应。
Dagger2提供了一个默认的@SingeInstance,用来标注AppModule中的@Provides。因此它标注提供的对象生命周期就跟Application一致,就间接实现了单例。

@Component

通过上文基本实现可以看出Component是负责连接Inject和Module的桥梁。通过@Component标注的XXXComponent来执行注入。

Component的dependencies

Scope小节有讲到,通过在AppComponent中用@Scope(一般用@SingeInstance)标注Provides方法实现单例。但是当你想在一个MainActivity中使用这个单例对象的时候,直接对他的变量标注@Inject是没用的。因为Dagger2找不到MainActivity和AppComponet之间的关系。此时就需要用到Componentdependencies了。

因为MainActivity是通过MainComponent来进行依赖注入的,此时我们只需要让MainComponent去依赖AppComponent即可。

@PerActivity
@Component(dependencies = AppComponent.class, modules = MainModule.class)
public interface MainComponent {
    ///***
}

仅这样写,只是规定了,MainComponent对象能依赖AppComponent对象,Dagger2是并不知道MainComponent依赖的是哪个AppComponent对象的。就需要在App里面生成一个AppComponent的对象。然后Activity通过getApplication得到这个AppComponent的对象。

public class App extends Application {

    private AppComponent mAppComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        mAppComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
    }

    public AppComponent getAppComponent() {
        return mAppComponent;
    }
}
public class MainActivity extends AppCompatActivity implements MainView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ///***

        DaggerMainComponent.builder()
                .appComponent(((App) getApplication()).getAppComponent())
                .mainModule(new MainModule(this))
                .build()
                .inject(this);
    }
}

这样就建立了MainActivity和AppComponent之间的一个关系。但是如果你要使用AppModule中提供的对象。还需要在AppComponent中定义一个返回值类型与想注入的对象对应的方法。因为自动生成的代码中,DaggerAppComponent就是通过复写这个方法把需要的对象暴露给DaggerMainComponent的。

@Module
public class AppModule {
    Context mContext;

    public AppModule(Context context) {
        mContext = context;
    }

    @Provides
    @Singleton
    public Toaster provideToaster() {
        return new Toaster(mContext);
    }
}
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    Toaster getToaster();
}

SubComponent

Subcomponent其功能效果优点类似component的dependencies。但是使用@Subcomponent不需要在父component中显式添加子component需要用到的对象,只需要添加返回子Component的方法即可,子Component能自动在父Component中查找缺失的依赖。若子Component有对应的Module,需要在方法中加入Module参数。

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    MainComponent getMainComponent(MainModule mainModule);
}
@PerActivity
@Subcomponent(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity mainActivity);
}
public class MainActivity extends AppCompatActivity implements MainView {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ((App) getApplication()).getAppComponent().getMainComponent(new MainModule(this))
                .inject(this);
    }
}

Sample地址:https://github.com/happyjosh/TestDagger/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值