王学岗 Dagger2的使用从简单到复杂

第一部分

dagger2是一个依赖注入的框架,举个例子如果我们不适用dagger注入,我们调用一个对象必须使用构造方法,这样就会造成了类与类的组合,但dagger的使用解决了这一问题。
这是dagger的官网

我们看一下跟dagger相关的概念,
@Inject
通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。 官方点说就是带有此注解的属性或构造方法将参与到依赖注入中,Dagger2会实例化有此注解的类。
@Module
Modules类里面的方法专门用来提供依赖,他就像一个工厂一样去生产需要添加依赖的实例。所以我们定义一个类,用@Module来注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的依赖。modules的一个重要特性是它们设计为分区并组合在一起(例如,我们的app中可以有多个组成在一起的modules)。它里面定义一些用@Provides注解的以provide开头的方法,这些方法就是所提供的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖。
@Provides
上面引入了这个概念了。在modules中,我们定义的方法是用@Provides这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
@Component
Components从根本上来说他就是一个注入器,也可以说是用来将@Inject和@Module联系起来的桥梁,它的主要作用就是连接这两个部分。Components可以提供所有定义了的类型的实例(inject需要),比如:我们必须用@Component注解一个接口然后列出所有的 。功能是从@Module中获取依赖并将依赖注入给@Inject

dagger必不可少的三个元素:Module,Component,Container
这里有张图来说明它们之间的关系。

《王学岗 Dagger2的使用从简单到复杂》 dagger2222222222.png

第二部分 Dagger2的基本使用(上)

下面我们看下具体怎么使用
首先要导入依赖

dependencies {
    implementation 'com.google.dagger:dagger:2.16'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.16'}

这里有个ApiService的类,我们需要在MainActivity中使用它的实例,如果我们不用dagger,我们就只能new ApiService(),但是我们现在使用dagger,就不需要new了。

先看下ApiService这个没用的类

package com.example.dagger2test;

import android.util.Log;
public class ApiService {
    public void register() {
        Log.i("zhang_xin","register成功");
    }
}

等下我们要使用dagger获取它的实例。

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject     
    ApiService   mApiService;

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

在MainActivity里我们使用@inject注解,告诉dagger,我需要ApiService的实例。dagger就会从@Component注释的接口中寻找ApiService的实例,那好,我们下面创建这个接口。

package com.example.dagger2test;

import dagger.Component;

@Component(modules = {?.class})//关联到module
public interface UserComponet {
 
}

大家看下Component的源码

public @interface Component {
  /**
   * A list of classes annotated with {@link Module} whose bindings are used to generate the
   * component implementation. Note that through the use of {@link Module#includes} the full set of
   * modules used to implement the component may include more modules that just those listed here.
   */
  Class<?>[] modules() default {};

  /**
   * A list of types that are to be used as <a href="#component-dependencies">component
   * dependencies</a>.
   */
  Class<?>[] dependencies() default {};

可以发现,Component需要module,我们需要在?处传入我们的module
下面我们创建module

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;
 
public class UseModule {
    @Provides//提供依赖
    public ApiService provideApiService(){
        return new ApiService();
    }
}

在module里我们真正创建ApiService的实例,这个提供ApiService实例的方法,我们需要标注为@provides
我们现在重新捋一下我们的思路
在MainActivity(就是图中Container)中,我们需要ApiService的实例,我们在ApiService上加上@inject注解,这样dagger就知道我们需要ApiService的实例,dagger就会去@Component注解下的类去找该实例,commponent是一个桥梁,它关联了很多modules。我们看下@Component的代码

package com.example.dagger2test;

import dagger.Component;

@Component(modules = {UseModule.class}) 
public interface UserComponet {
    
}

注意,以上只是Module与Component进行了关联,我说过Component是一个桥梁,所我们还需要把Component与MainActivity进行关联,

package com.example.dagger2test;

import dagger.Component;

@Component(modules = {UseModule.class})//关联到module
public interface UserComponet {
    void inject(MainActivity activity);//关联到Activity
}

从这行注释@Component(modules = {UseModule.class}) ,dagger就知道要去UseModule里获取ApiService的实例。
我们在看下UseModele类,在这个类里获取ApiService的实例,注意,该类需要添加@module注解。提供对象的方法添加@Prividers,方法的返回值为ApiService且有@Provides注释,那么dagger就会从这个方法里获取ApiService对象

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;
@Module
public class UseModule {
    @Provides//提供依赖
    public ApiService provideApiService(){
        return new ApiService();
    }
}

到这里我们在MainActivity(Container)里调用ApiService实例的代码就全部完成了。然后我们rebuild我们的工程
这个时候dagger会自动生成DaggerUserComponet类,该类有个create(),会生成UserComponet的实例,然后通过该实例我们调用UserComponet的inject方法。完整代码如下

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

/**
 * 依赖注入框架,解决繁琐的依赖关系
 * 必不可少的三种元素:Module,Component,Container,module提供依赖的集合,里面有很多方法是提供依赖的
 * ,component
 */
public class MainActivity extends AppCompatActivity {
    @Inject//dagger会从commponent里去找ApiService的实例。使用依赖
    ApiService mApiService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//生成UserComponet的实例,调用inject()
        DaggerUserComponet.create().inject(this);
        mApiService.register();
    }
}

运行会输出
10-20 15:22:10.585 22065-22065/com.example.dagger2test I/zhang_xin: register成功
为了方便大家看,我把所有相关的类在贴一遍。

package com.example.dagger2test;

import android.util.Log;
public class ApiService {
    public void register() {
        Log.i("zhang_xin","register成功");
    }
}

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject//dagger会从commponent里去找ApiService的实例。使用依赖
    ApiService mApiService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.create().inject(this);
        mApiService.register();
    }
}
package com.example.dagger2test;

import dagger.Component;

@Component(modules = {UseModule.class})//关联到module
public interface UserComponet {
    void inject(MainActivity activity);//关联到Activity
}

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;
@Module
public class UseModule {
    @Provides//提供依赖
    public ApiService provideApiService(){
        return new ApiService();
    }
}

第三部分 Dagger2的基本使用(下)

我们再来看一下复杂的例子。
我们需要MainActivity类里获取UserManager实例,UserManager的构造方法需要传入另外两个类的实例。我们看下UserManager类

package com.example.dagger2test;

public class UserManager {
    private ApiService apiService;
    private UserStore userStore;

    public UserManager(ApiService apiService, UserStore userStore) {
        this.apiService = apiService;
        this.userStore = userStore;
    }
    public void register(){
        apiService.register();
        userStore.register();
    }
}

这是UserStore类

package com.example.dagger2test;

import android.util.Log;

public class UserStore {
    public void register(){
        Log.i("zhang_xin","UserStore注册成功");
    }
}

我们有两种方法
第一种,修改UseModule文件

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Provides
    public ApiService getApiService() {
        return new ApiService();
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore();
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

然后在MainActivity中调用用

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.create().inject(this);
        userManager.register();
    }
}

看下打印输出结果
10-20 17:03:03.092 27717-27717/com.example.dagger2test I/zhang_xin: ApiService register成功 UserStore注册成功
第二种方法,使用构造方法。
我们先把UseModule中方法注释掉

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
//    @Provides
//    public ApiService getApiService() {
//        return new ApiService();
//    }
//
//    @Provides
//    public UserStore getUserStore() {
//        return new UserStore();
//    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

然后修改ApiService和UseModule两个类,添加@Inject注释的方法。

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Inject;

public class UserStore {
    @Inject
    public UserStore(){

    }
    public void register(){
        Log.i("zhang_xin","UserStore注册成功");
    }
}

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Inject;

public class ApiService {
    @Inject
    public ApiService() {
    }

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
    }
}

运行MainActivity
10-20 17:14:14.795 28228-28228/com.example.dagger2test I/zhang_xin: ApiService register成功 UserStore注册成功
由以上两种方法我们可以得出结论。
如果Module中没有提供@Providers注释的方法,Dagger会去调用@Inject注释的方法。

第四部分

我们现在有这么个需求,那就是UseModule的构造方法需要传入参数。我们修改下UseModule类

package com.example.dagger2test;

import android.content.Context;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    private Context context;
    public UseModule (Context context){
        this.context=context;
    }
    @Provides
    public ApiService getApiService() {
        return new ApiService();
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore(this.context);
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

现在大家看下,我们怎么在MainActivity类里调用
DaggerUserComponet.create().inject(this);肯定是行不通了

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule(this)).build().inject(this);
        userManager.register();
    }
}

第五部分

假设我们现在有这么一个需求,ApiService里需要传入一个参数(实际开发中可能是OkHttpClient等,我们这里只简单的使用Dog),我们可以这么做
,先看下Dog类

package com.example.dagger2test;

public class Dog {
}

看下UserManager类

package com.example.dagger2test;

public class UserManager {
    private ApiService apiService;
    private UserStore userStore;

    public UserManager(ApiService apiService, UserStore userStore) {
        this.apiService = apiService;
        this.userStore = userStore;
    }

    public void register(){
        apiService.register();
        userStore.register();
    }
}

看下ApiService类

package com.example.dagger2test;

import android.util.Log;

public class ApiService {
   private Dog dog;
//注意 dog是单例对象
    public ApiService(Dog dog) {
        this.dog = dog;
    }

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
    }
}

我们可以单独写一个针对Dog类的DogModule

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class DogModule {
    @Singleton//增加单例注释
    @Provides
    public Dog getUser(){
        return new Dog();
    }
}

然后在UseModule中引用DogMoudle

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
//includes引入另外一个module
@Module(includes = {DogModule.class})
public class UseModule {
    @Provides
    public ApiService getApiService(Dog dog) {
        Log.i("zhang_xin", "dog是否是单例:" + dog.toString());
        return new ApiService(dog);
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore();
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

同时UserComponet也需要修改

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;
//增加单例注释
@Singleton
@Component(modules = {UseModule.class})//关联到module
public interface UserComponet {
    void inject(MainActivity activity);//关联到Activity
}

下面我们在MainActivity中调用

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      DaggerUserComponet.builder().useModule(new UseModule()).dogModule(new DogModule()).build().inject(this);
        userManager.register();
    }
}

最后我们看一下打印输出
10-20 20:23:15.805 31622-31622/com.example.dagger2test I/zhang_xin: dog是否是单例:com.example.dagger2test.Dog@b45757d 10-20 20:23:15.809 31622-31622/com.example.dagger2test I/zhang_xin: ApiService register成功 UserStore注册成功
多次打印都是这个值:com.example.dagger2test.Dog@b45757d;
说明Dog确实是单例模式

除此之外还有一种方法,我们首先把UseModule恢复原来的样子

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
//这里删除includes
@Module
public class UseModule {
    @Provides
    public ApiService getApiService(Dog dog) {
        Log.i("zhang_xin", "dog是否是单例:" + dog.toString());
        return new ApiService(dog);
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore();
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

然后修改我们的UserComponet类

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
//增加DogModule.class
@Component(modules = {UseModule.class,DogModule.class})//关联到module
public interface UserComponet {
    void inject(MainActivity activity);//关联到Activity
}

其余的代码不变,效果一样

第六部分 创建和区分不同实例(上)

我们现在有新的需求了,我们在MainActivity里需要两个ApiService对象,该怎么操作呢?其实也很简单,只需要在UseModule中提供两个@Provides注释的方法,同时在MainActivity和UseModule中添加@Named注释,注意MainActivity中的@Named和UseModule中的@Named字段要一一对应。看下代码更一目了然
ApiService类

package com.example.dagger2test;

import android.util.Log;

public class ApiService {

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
        Log.i("zhang_xin",this.toString());
    }
}

MainActivity需要两个ApiService类,每个对象前添加@Named注释

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    @Named("1")
    @Inject
    ApiService apiService1;
    @Inject
    @Named("2")
    ApiService apiService2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule()).build().inject(this);
        apiService1.register();
        apiService2.register();
    }
}

UseNodule类,添加@Named注释与MainActivity一一对应

package com.example.dagger2test;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Provides
    @Named("1")
    public ApiService getApiService1(Dog dog) {
        return new ApiService();
    }
    @Provides
    @Named("2")
    public ApiService getApiService2(Dog dog) {
        return new ApiService();
    }
}

看下打印输出
10-22 19:44:09.799 31505-31505/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@b45757d 10-22 19:44:09.800 31505-31505/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@20d4c72
可以看出两个ApiService的内存地址不一样,是两个不同的对象。
注意,如果我们不添加@Named注释,dagger会根据返回值类型进行匹配。

第七部分 dagger创建和区分不同实例(下)

上接第六部分,第六部分的功能我们还可以这样实现,自定义@Interface
我们首先自定义两个@Interface文件,一个叫@First,一个叫@Second

package com.example.dagger2test;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Qualifier;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface First {
}
package com.example.dagger2test;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Qualifier;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Second {
}

在UseModule和MainActivity中,我们需要把@Named注释分别改为@First和@Second,我们看下代码

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    @First
    @Inject
    ApiService apiService1;
    @Second
    @Inject
    ApiService apiService2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule()).build().inject(this);
        apiService1.register();
        apiService2.register();
    }
}

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Provides
    @First
    public ApiService getApiService1() {
        return new ApiService();
    }
    @Provides
    @Second
    public ApiService getApiService2() {
        return new ApiService();
    }
}

看下运行效果
10-22 19:59:50.668 32434-32434/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@b45757d ApiService register成功 10-22 19:59:50.669 32434-32434/com.example.dagger2test I/zhang_xin: com.example.dagger2test.ApiService@20d4c72

第八部分:Singleton 单例讲解(上)

我们需要ApiService是单例模式
首先我们看下ApiService类

package com.example.dagger2test;

import android.util.Log;

public class ApiService {

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
        Log.i("zhang_xin",this.toString());
    }
}

这个时候我们需要在Module类的方法中添加@Singleton注释,代码如下

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Singleton
    @Provides
    public ApiService getApiService() {
        return new ApiService();
    }
}

注意我们现在需要修改UserComponent类,他的类也需要添加@Singleton注释

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;
@Singleton//因为UseModule添加了该注释,所以这里也需要添加注释
@Component(modules = {UseModule.class,DogModule.class})//关联到module
public interface UserComponet {
    void inject(MainActivity activity);//关联到Activity
}

然后我们看下MainActivity

 package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    @Inject
    ApiService apiService1;
    @Inject
    ApiService apiService2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule()).build().inject(this);
        apiService1.register();
        apiService2.register();

    }
}

我们多次运行都会打印这个结果
10-22 20:33:15.896 3145-3145/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@b45757d ApiService register成功 com.example.dagger2test.ApiService@b45757d
apiService1和apiService2内存地址一样,说明它们是同一个对象。

第八部分:Singleton 单例讲解(下)

我们第七部分实现了单例模式,但是这种方法实现的单例模式是有问题的,如果我们现在在创建一个MainActivity2和与之相关的@Component注释的类,那么这个时候我们无法保证两个Activity中的ApiService是同一个。其实大家翻翻Dagger的源码就会发现,Dagger的单例模式必须要保证是同一个@Component注释的类。
我们先看这样的一个例子,我们把访问网络的类CallNets设置为单例模式
这个是ApiService类,他里面有一个CallNets类,这个类是单例模式。

package com.example.daggertest2;

import android.util.Log;

public class ApiService {
    private CallNets callNets;

    public ApiService(CallNets callNets) {
        this.callNets = callNets;
    }

    public void register() {
        Log.i("zhang_xin", "apiService注册成功");
    }
}

CallNets类,实际开发中可能是OkhttpClient等。

package com.example.daggertest2;

public class CallNets {
//访问网络的逻辑
}

CallNetsModule类,方法我们注解成单例模式

package com.example.daggertest2;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class CallNetsModule {
    @Singleton
    @Provides
    public CallNets getCallNets(){
        CallNets callNets=new CallNets();
        Log.i("zhang_xin",callNets.toString());
        return callNets;
    }

}

接下来我们创建了两个@Component注解的类

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules=UserModule.class)
public interface LoginComponet {
    void inject(LoginActivity activity);
}

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules = UserModule.class)
public interface UserComponet {
    void inject(MainActivity activity);
}

UserModule和UserManager

package com.example.daggertest2;

public class UserManager {
    private ApiService apiService;
    public UserManager(ApiService apiService){
        this.apiService=apiService;
    }
    public void register(){
        apiService.register();
    }
}

package com.example.daggertest2;

import dagger.Module;
import dagger.Provides;

@Module(includes = {CallNetsModule.class})
public class UserModule {

    @Provides
    public ApiService getApiService(CallNets callNets){
        return new ApiService(callNets);
    }
    @Provides
    public UserManager getUserManager(ApiService apiService){
        return new UserManager(apiService);
    }
}

两个Activity

package com.example.daggertest2;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().userModule(new UserModule()).callNetsModule(new CallNetsModule()).build().inject(this);
        userManager.register();
        startActivity(new Intent(this,LoginActivity.class));
    }
}

package com.example.daggertest2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class LoginActivity extends AppCompatActivity {
   @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        DaggerLoginComponet.builder().userModule(new UserModule()).callNetsModule(new CallNetsModule()).build().inject(this);
        userManager.register();
    }
}

我们看下打印输出
/zhang_xin: com.example.daggertest2.CallNets@b45757d /zhang_xin: apiService注册成功 /zhang_xin: com.example.daggertest2.CallNets@eea8d0f /zhang_xin: apiService注册成功
很明显,两个CallNets不是同一个对象,我们虽然标注了@Singleton,但因为创建了两个Componet,所以得到的是两个不同的CallNets对象。
接下来我们就解决这个问题。
我们需要创建一个最高级别的Component
首先我们把CallNetsModule中无法提供单例的方法注释掉

package com.example.daggertest2;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class CallNetsModule {
//    @Singleton
//    @Provides
//    public CallNets getCallNets(){
//        CallNets callNets=new CallNets();
//        Log.i("zhang_xin",callNets.toString());
//        return callNets;
//    }

}

然后我们创建AppComponet和AppModule

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules = AppModule.class)
public interface AppComponet {
    //这里不需要提供inject方法,因为我们不需要注入,是依附于其它的Conmponent
}

我们在AppModule类中提供CallNets的单例


import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class AppModule {
    @Singleton
    @Provides
    public CallNets getCallNets(){
        CallNets callNets=new CallNets();
        Log.i("zhang_xin",callNets.toString());
        return callNets;
    }
}

然后修改LoginComponent UserComponent

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 1,在这里我解释下,我们的UserModule并没有提供CallNets实例,如果Dagger在UserModule中没有发现CallNets实例
 * 他就会去依赖既AppComponet.class里面去找.
 * 2,这里不能有@Singleton注释,因为Component的dependencies与Component
 * 自身的scope不能相同
 */

@Component(modules=UserModule.class,dependencies = AppComponet.class)
public interface LoginComponet {
    void inject(LoginActivity activity);

}

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 2,这里不能有@Singleton注释,因为Component的dependencies与Component
 * 自身的scope不能相同
 */
@Component(modules = UserModule.class,dependencies = AppComponet.class)
public interface UserComponet {
    void inject(MainActivity activity);
}

这里我做下说明

《王学岗 Dagger2的使用从简单到复杂》 dagger1.ng.png

注意第五点,所以我们没办法给LoginComponent和AppComponent添加@Singleton注释,既然没办法添加@Singleton注释,那么我们该怎么给LoginComponent和AppComponent添加注释呢?因为Dagger给我们提供的注释只有@Singleton,所以需要我们自己定义注释。

package com.example.daggertest2;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Scope;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {
}

@scope注明是Scope
@documented标记在文档
@Retention 级别,有source class runtime

然后我们修改LoginComponent和UserComponent文件,添加@ActivityScope 注释。

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 1,在这里我解释下,我们的UserModule并没有提供CallNets实例,如果Dagger在UserModule中没有发现CallNets实例
 * 他就会去依赖既AppComponet.class里面去找.
 * 2,这里不能有@Singleton注释,因为Component的dependencies与Component
 * 自身的scope不能相同
 */
@ActivityScope//添加该注释
@Component(modules=UserModule.class,dependencies = AppComponet.class)
public interface LoginComponet {
    void inject(LoginActivity activity);

}

package com.example.daggertest2;

import dagger.Component;

/**
 * 2,这里不能有@Singleton注释,因为Component的dependencies与Component
 * 自身的scope不能相同
 */
@ActivityScope//添加该注释
@Component(modules = UserModule.class,dependencies = AppComponet.class)
public interface UserComponet {
    void inject(MainActivity activity);
}

然后修改AppComponent类

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules = AppModule.class)
public interface AppComponet {
 Conmponent
    CallNets getCallNets();
}

在这里我们做一个桥接,这里的CallNets对象就是由AppModule提供的。
我们现在reBuild工程,已经可以了没有报错
可是我们现在又面临一个问题,接下来我们该怎样在LoginActivity和MainActivity中使用AppComponent呢?
DaggerUserComponet.builder().userModule(new UserModule()).appComponet();
我们可以看到appComponent()需要传入AppComponet类型的对象,在这里我们怎么给appComponent()传入参数呢?
因为Singleton是application级别的,所以我们需要在Application中将AppComponent实例化。创建MyApplication继承Application。

package com.example.daggertest2;

import android.app.Application;
import android.util.Log;

public class MyApplication extends Application {
    private AppComponet appComponet;
    @Override
    public void onCreate() {
        super.onCreate();
       appComponet= DaggerAppComponet.create();
    }

    public AppComponet getAppComponet() {
        return appComponet;
    }
}

然后我们就可以在MainActivity 和LoginActivity里调用了

package com.example.daggertest2;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().userModule(new UserModule())
                .appComponet(((MyApplication) getApplication())
                        .getAppComponet()).build().inject(this);
        userManager.register();
        startActivity(new Intent(this, LoginActivity.class));
    }
}

package com.example.daggertest2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class LoginActivity extends AppCompatActivity {
   @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        DaggerLoginComponet.builder().userModule(new UserModule())
                .appComponet(((MyApplication) getApplication())
                        .getAppComponet()).build().inject(this);
         userManager.register();
    }
}

这样我们就实现了单例模式
我们在ApiService中添加打印数据,测试下是不是单例模式

package com.example.daggertest2;

import android.util.Log;

public class ApiService {
    private CallNets callNets;

    public ApiService(CallNets callNets) {
        this.callNets = callNets;
    }

    public void register() {
        Log.i("zhang_xin", "apiService注册成功"+this.callNets.toString());
    }
}

看下打印结果

10-24 16:22:59.691 2967-2967/com.example.daggertest2 I/zhang_xin: apiService注册成功com.example.daggertest2.CallNets@4a7ac880
10-24 16:22:59.701 2967-2967/com.example.daggertest2 I/zhang_xin: apiService注册成功com.example.daggertest2.CallNets@4a7ac880

OK,大功告成!

第九部分:SubComponent

这里我就强调两点
1,SubComponent同时具备两种不同生命周期的scope,Subcomponent具备了父Component的scope,也具备自己的Scope
2,subComponent的Scope范围小于父Component

第十部份:Lazy与Provider

    原文作者:王学岗
    原文地址: https://www.jianshu.com/p/9466e13e63aa
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞