Dagger2 入门实战

看了网上很多篇关于Dagger2的入门文章,说真的对新手而言很难看懂,由于自己也是刚学习Dagger2,所以这篇文章站在初学者的角度编写完成。

参考如下文章:https://www.jianshu.com/p/c7caadaf28af

简单依赖

首先,先来看看为引入Dagger2之前,我们是在怎么构造一个对象依赖的。

定义SimpleA、SimpleB对象

public class SimpleA {

    private String name;

    public SimpleA(){

    }

    public void print(){
        System.out.println("Simple A 被调用了");
    }
}
public class SimpleB {

    SimpleA simpleA;

    public SimpleB(){
    }

    public SimpleB(SimpleA a){
        this.simpleA = a;
    }

    public SimpleA getSimpleA() {
        return simpleA;
    }
}

Simple在其它类中被依赖

public class ExSimpleAActivity extends AppCompatActivity {

    SimpleA simpleA;

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

        simpleA = new SimpleA();
    }
}

使用dagger2之后

先在需要调用的注入的类(container)中,使用@Inject 代替new SimpleA()

public class ExSimpleAActivity extends AppCompatActivity {

    @Inject 
    SimpleA simpleA;

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

        simpleA.print();
    }
}

将new 对象替换成了@inject注解,当然这样还是不行的,在Spring中用注解也是需要在bean.xml中配置的对吧,这里也一样。有两种解决方案

方案一:在类中的构造函数上加注解@Inject

public class SimpleA {

    private String name;
    
    @Inject		// 注意这儿
    public SimpleA(){

    }

    public void print(){
        System.out.println("Simple A 被调用了");
    }
}
@Component
public interface SimpleAComponent {
    SimpleA getSimpleA();
}
public class ExSimpleAActivity extends AppCompatActivity {

    @Inject
    SimpleA simpleA;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ex_simplea_activity);
        simpleA = DaggerSimpleAComponent.create().getSimpleA();
        simpleA.print();
    }
}

方案二:添加一个Module

public class SimpleA {

    private String name;
    
    // @Inject	注意这儿可以没有
    public SimpleA(){

    }

    public void print(){
        System.out.println("Simple A 被调用了");
    }
}
@Module
public class SimpleAModule {
    
    @Provides
    SimpleA providerSimpleA(){
        return new SimpleA();
    }
}
@Component(modules = SimpleAModule.class)	// 注意传入的是Module
public interface SimpleAComponent {
//    SimpleA getSimpleA();

    void injectSimpleAActivity(ExSimpleAActivity simpleAActivity);
}
public class ExSimpleAActivity extends AppCompatActivity {

    @Inject
    SimpleA simpleA;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ex_simplea_activity);
        DaggerSimpleAComponent.create().injectSimpleAActivity(this);
        simpleA.print();
    }
}

这部分表示了一个类可以通过在构造方法上加注解@Inject或在Module中提供实例的方式来注入到另一个类中,并通过对应的Dagger**Component来获取。第二种方案主要用于引入第三方库时无法修改源代码,故需要在Module中提供实例。


多层依赖

当需要依赖SimpleB的时候,它可能又依赖SimpleA,在以前的代码中就是下面这样

public class MainActivity extends AppCompatActivity {
    ...
	SimpleA a = new SimpleA();
	SimpleB b = new SimpleB(a)
    ...
}

所以这时候在A Module中也需要提供B 的实例。也有两种方案:

方案一:如果已经有定义了依赖SimpleA的Module直接include即可,没有则也需要在这里提供

@Module(includes = SimpleAModule.class)
public class SimpleBModule {


    @Provides
    public SimpleB provideSimpleB(SimpleA a){
        return new SimpleB(a);
    }

//	  如果没有提供SimpleA()的module
//    @Provides
//    public SimpleA providerSimpleA(){
//        return new SimpleA();
//    }
}

对应Activity

public class ExSimpleActivity extends AppCompatActivity {

    @Inject
    SimpleA simpleA;

    @Inject
    SimpleB simpleB;

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

        DaggerSimpleComponent.builder()
                .simpleAModule(new SimpleAModule())
                .simpleBModule(new SimpleBModule())
                .build()
                .injectSimpleACtivity(this);

//        DaggerSimpleComponent.create().injectSimpleACtivity(this);
        
        Log.v("simpleA", String.valueOf(simpleA.hashCode()));
        Log.v("simpleB", String.valueOf(simpleB.hashCode()));
        Log.v("simpleB.A", String.valueOf(simpleB.getSimpleA().hashCode()));
    }
}

这里插一句,会发现DaggerSimpleComponent的写法怎么不一样的,其实create方法中的实现就是builder,所以两种是一样的。同时,如果需要依赖两个类的话,在component中需要加载他们的module。

@Component(modules = {SimpleAModule.class, SimpleBModule.class})
public interface SimpleComponent {

    void injectSimpleACtivity(ExSimpleActivity simpleActivity);
}

方案二

@Module
public class SimpleBModule {

    public SimpleA simpleA;

    public SimpleBModule(SimpleA A){	// 构造传参
        this.simpleA = A;
    }

    @Provides
    public SimpleB provideSimpleB(){
        return new SimpleB(simpleA);
    }
}
public class ExSimpleActivity extends AppCompatActivity {

    @Inject
    SimpleA simpleA;

    @Inject
    SimpleB simpleB;

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

        DaggerSimpleComponent.builder()
                .simpleAModule(new SimpleAModule())
                .simpleBModule(new SimpleBModule(simpleA))
                .build()
                .injectSimpleACtivity(this);

//        DaggerSimpleComponent.create().injectSimpleACtivity(this);

        Log.v("simpleA", String.valueOf(simpleA.hashCode()));
        Log.v("simpleB", String.valueOf(simpleB.hashCode()));
        Log.v("simpleB.A", String.valueOf(simpleB.getSimpleA().hashCode()));
    }
}


Singleton问题

局部单例

通过打印它们的hashcode发现即使在SimpleBModule中include了SimpleAModule,但还是产生了两个SimpleA

修改下SimpleBModule、SimpleAModule。由于我们的目的是B中的A是要成为单例的,所以将SimpleAModule注解为Singleton即可,注意@Module上不要加!

@Module
public class SimpleAModule {

    @Singleton
    @Provides
    public SimpleA providerSimpleA(){
        return new SimpleA();
    }
}
@Module(includes = SimpleAModule.class)
public class SimpleBModule {

    @Provides
    public SimpleB provideSimpleB(SimpleA a){
        return new SimpleB(a);
    }
}

在对应component中也需要添加上@Singleton

@Singleton
@Component(modules = {SimpleAModule.class, SimpleBModule.class})
public interface SimpleComponent {

    void injectSimpleACtivity(ExSimpleActivity simpleActivity);
}

可以看到,传入B的A也是同一个对象。这是因为B中的A本质上也是由SimpleAModule提供的。

那局部单例和全局单例又是怎么回事呢?我们创建一个新的活动来看看。

在SimpleAComponent注入两个活动,分别在两个活动中@Inject一个SimpleA实例,启动活动A的时候跳转到活动B,打印出各自SimpleA的hashcode

@Singleton
@Component(modules = SimpleAModule.class)
public interface SimpleAComponent {
//    SimpleA getSimpleA();

    void injectSimpleAActivity(ExSimpleAActivity simpleAActivity);

    void injectSimpleAActivity(ExSimpleBActivity simpleBActivity);
}

可以看到,两个活动中的SimpleA不一样(一个活动中多次Inject是一样的)。那么这就是局部单例,当Component中注入了不同的类,他们产生的实例也不相同

Dagger2 入门实战_第1张图片

全局单例

那么如何做到全局单例?

先来看看SimpleBActivity中的代码,create是可以用Builder替代的,也就是说在这个类中其实会生成一个SimpleAComponent对象,然后再注入。

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ex_simpleb_activity);

        DaggerSimpleAComponent.create().injectSimpleBActivity(this);
        //SimpleAComponent build = DaggerSimpleAComponent.builder().simpleAModule(new SimpleAModule()).build();
        //build.injectSimpleBActivity(this);
        
        Log.v("simpleA 1", String.valueOf(a1.hashCode()));
    }

所以由于Component在两个activity中被各自被实例化一次,,导致产生了两个不同的对象,所以我们需要做到让Component能够实现单例。Android中,我们知道在整个App生命周期中都只有一个Appclication实例,所以在Application中获得一个唯一的component实例,用它来提供我们需要的单例。

新建一个MyApplication

public class MyApplication extends Application {

    private SimpleAComponent singleSimpleAComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();

        singleSimpleAComponent = DaggerSimpleAComponent.builder()
                .simpleAModule(new SimpleAModule())
                .build();
    }

    public SimpleAComponent getSingleSimpleAComponent(){
        return singleSimpleAComponent;
    }
}

修改A、B两个活动的代码,Component从Application中获取。

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ex_simplea_activity);
//        DaggerSimpleAComponent.create().injectSimpleAActivity(this);
        SimpleAComponent singleSimpleAComponent = ((MyApplication) getApplication()).getSingleSimpleAComponent();
        singleSimpleAComponent.injectSimpleAActivity(this);

        Log.v("simpleA", String.valueOf(simpleA.hashCode()));

        Intent intent = new Intent(this, ExSimpleBActivity.class);
        startActivity(intent);
    }
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ex_simpleb_activity);

//        DaggerSimpleAComponent.create().injectSimpleBActivity(this);
        //SimpleAComponent build = DaggerSimpleAComponent.builder().simpleAModule(new SimpleAModule()).build();
        //build.injectSimpleBActivity(this);
        SimpleAComponent singleSimpleAComponent = ((MyApplication) getApplication()).getSingleSimpleAComponent();
        singleSimpleAComponent.injectSimpleBActivity(this);

        Log.v("simpleA 1", String.valueOf(a1.hashCode()));
    }

这时候句可以看到全局单例了

Dagger2 入门实战_第2张图片


区分@Provides 方法

当有Context需要注入时,Dagger2就会在Module中查找返回类型为Context的方法。但是,当Container需要依赖两种不同的Context时,你就需要写两个@Provides方法,而且这两个@Provides方法都是返回Context类型,靠判别返回值的做法就行不通了。这就可以使用@Named注解来区分

//定义Module
@Module
public class ActivityModule{
	private Context mContext    ;
	private Context mAppContext = App.getAppContext();	// 另一种Context
    
    public ActivityModule(Context context) {
        mContext = context;		// 通过传参来构造
    }
    
    @Named("Activity")		//@ContextLife("Activity")
    @Provides
    public Context provideContext(){  
        return mContext;
    }
    
    @Named("Application")	//@ContextLife ("Application")
    @Provides
    public Context provideApplicationContext (){
        return mAppContext;
    }
}
//定义Component
@Component(modules={ActivityModule.class}) 
interface ActivityComponent{   
    void inject(Container container);   
}
//定义Container
class Container extends Fragment{
    @Named("Activity") 		//@ContextLife("Activity")
    @Inject
    Context mContext; 

    @Named("Application") 	//@ContextLife ("Application")
    @Inject
    Context mAppContext; 
    ...
    public void init(){
         DaggerActivityComponent.
     .activityModule(new ActivityModule(getActivity()))
     .inject(this);
     }
}

你可能感兴趣的:(#安卓)