Dagger2從入門到放棄再到恍然大悟

寫在前面:
我目前就職于阿里巴巴-菜鳥,團(tuán)隊(duì)目前缺人,招聘java和客戶端開發(fā),招聘對(duì)象為:社招和19屆畢業(yè)的校招生,有適合的人選發(fā)送簡(jiǎn)歷到我個(gè)人郵箱:hsk256@163.com,謝謝大家。

現(xiàn)在Dagger2在項(xiàng)目里用的越來(lái)越多了,最近花了些時(shí)間學(xué)習(xí)了一下Dagger2,這篇文章主要幫助理解Dagger2的注入實(shí)現(xiàn)過(guò)程,如有錯(cuò)誤,還請(qǐng)指正!

什么是Dagger2

Dagger2是Dagger的升級(jí)版,是一個(gè)依賴注入框架,現(xiàn)在由Google接手維護(hù)。 恩,這里有個(gè)關(guān)鍵字依賴注入,因此我們得先知道什么是依賴注入,才能更好的理解Dagger2。

依賴注入是面向?qū)ο缶幊痰囊环N設(shè)計(jì)模式,其目的是為了降低程序耦合,這個(gè)耦合就是類之間的依賴引起的。

舉個(gè)例子:我們?cè)趯懨嫦驅(qū)ο蟪绦驎r(shí),往往會(huì)用到組合,即在一個(gè)類中引用另一個(gè)類,從而可以調(diào)用引用的類的方法完成某些功能,就像下面這樣.

public class ClassA {
    ...
    ClassB b;
    ...
    public ClassA() {
        b = new ClassB();
    }
    
    public void do() {
        ...
        b.doSomething();
        ...
    }
}

這個(gè)時(shí)候就產(chǎn)生了依賴問(wèn)題,ClassA依賴于ClassB,必須借助ClassB的方法,才能完成一些功能。這樣看好像并沒有什么問(wèn)題,但是我們?cè)贑lassA的構(gòu)造方法里面直接創(chuàng)建了ClassB的實(shí)例,問(wèn)題就出現(xiàn)在這,在ClassA里直接創(chuàng)建ClassB實(shí)例,違背了單一職責(zé)原則,ClassB實(shí)例的創(chuàng)建不應(yīng)由ClassA來(lái)完成;其次耦合度增加,擴(kuò)展性差,如果我們想在實(shí)例化ClassB的時(shí)候傳入?yún)?shù),那么不得不改動(dòng)ClassA的構(gòu)造方法,不符合開閉原則

因此我們需要一種注入方式,將依賴注入到宿主類(或者叫目標(biāo)類)中,從而解決上面所述的問(wèn)題。依賴注入有一下幾種方式:

  • 通過(guò)接口注入

    interface ClassBInterface {
        void setB(ClassB b);
    }
    
    public class ClassA implements ClassBInterface {
        ClassB classB;
        
        @override
        void setB(ClassB b) {
            classB = b;
        }
    }
    
  • 通過(guò)set方法注入

    public class ClassA {
        ClassB classB;
        
        public void setClassB(ClassB b) {
            classB = b;
        }
    }
    
  • 通過(guò)構(gòu)造方法注入

    public class ClassA {
        ClassB classB;
        
        public void ClassA(ClassB b) {
            classB = b;
        }
    
  • 通過(guò)Java注解

    public class ClassA {
        //此時(shí)并不會(huì)完成注入,還需要依賴注入框架的支持,如RoboGuice,Dagger2
        @inject ClassB classB;
        
        ...
        public ClassA() {}
    

在Dagger2中用的就是最后一種注入方式,通過(guò)注解的方式,將依賴注入到宿主類中。

如何引入Dagger2

  • 配置apt插件(在build.gradle(Project:xxx)中添加如下代碼)

    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0'
        //添加apt插件
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
       
    }
    
  • 添加依賴(在build.gradle(Module:app)中添加如下代碼)

    apply plugin: 'com.android.application'
    //添加如下代碼,應(yīng)用apt插件
    apply plugin: 'com.neenbedankt.android-apt'
    ...
    dependencies {
        ...
        compile 'com.google.dagger:dagger:2.4'
        apt 'com.google.dagger:dagger-compiler:2.4'
        //java注解
        compile 'org.glassfish:javax.annotation:10.0-b28'
        ...
    }
    

使用Dagger2

下面用一個(gè)栗子來(lái)說(shuō)明,如何使用Dagger2,需要說(shuō)明的是,這個(gè)栗子是基于mvp模式的,所以如果還不了解mvp的話,可以先去了解mvp,再繼續(xù)看下面的內(nèi)容。

在mvp中,最常見的一種依賴關(guān)系,就是Activity持有presenter的引用,并在Activity中實(shí)例化這個(gè)presenter,即Activity依賴presenter,presenter又需要依賴View接口,從而更新UI,就像下面這樣:

public class MainActivity extends AppCompatActivity implements MainContract.View {
    private MainPresenter mainPresenter;
    ...
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //實(shí)例化presenter 將view傳遞給presenter
        mainPresenter = new MainPresenter(this);
        //調(diào)用Presenter方法加載數(shù)據(jù)
         mainPresenter.loadData();
         
         ...
    }

}

public class MainPresenter {
    //MainContract是個(gè)接口,View是他的內(nèi)部接口,這里看做View接口即可
    private MainContract.View mView;
    
    MainPresenter(MainContract.View view) {
        mView = view;
    }
    
    public void loadData() {
        //調(diào)用model層方法,加載數(shù)據(jù)
        ...
        //回調(diào)方法成功時(shí)
        mView.updateUI();
    }

這樣Activity與presenter僅僅耦合在了一起,當(dāng)需要改變presenter的構(gòu)造方式時(shí),需要修改這里的代碼。如果用依賴注入的話,是這樣的:


public class MainActivity extends AppCompatActivity implements MainContract.View {
    @Inject
    MainPresenter mainPresenter;
    ...
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         
         DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build()
                .inject(this);
        //調(diào)用Presenter方法加載數(shù)據(jù)
         mainPresenter.loadData();
         
         ...
    }

}

public class MainPresenter {
    //MainContract是個(gè)接口,View是他的內(nèi)部接口,這里看做View接口即可
    private MainContract.View mView;
    
    @Inject
    MainPresenter(MainContract.View view) {
        mView = view;
    }    
    public void loadData() {
        //調(diào)用model層方法,加載數(shù)據(jù)
        ...
        //回調(diào)方法成功時(shí)
        mView.updateUI();
    }

@Module
public class MainModule {
    private final MainContract.View mView;

    public MainModule(MainContract.View view) {
        mView = view;
    }

    @Provides
    MainView provideMainView() {
        return mView;
    }
}

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

額,貌似變得更復(fù)雜了,還不如不用Dagger2呢。不過(guò)仔細(xì)想想也是可以理解的,直接組合方式雖然簡(jiǎn)單,但是具有耦合性,為了解決這種耦合,可能就會(huì)多產(chǎn)生一些輔助類,讓這種直接的依賴關(guān)系,變?yōu)殚g接,降低耦合。跟大多數(shù)設(shè)計(jì)模式一樣,為了達(dá)到高內(nèi)聚低耦合,往往會(huì)有很多接口與類,Daager2也是如此,雖然看似復(fù)雜了些,不過(guò)這在軟件工程中是值得的。下面,就來(lái)分析下上面代碼是什么意思。

我們先看MainActivity里的代碼,之前是直接聲明MainPresenter,現(xiàn)在在聲明的基礎(chǔ)上加了一個(gè)注解@Inject,表明MainPresenter是需要注入到MainActivity中,即MainActivity依賴于MainPresenter,這里要注意的是,使用@Inject時(shí),不能用private修飾符修飾類的成員屬性。

然后我們?cè)贛ainPresenter的構(gòu)造函數(shù)上同樣加了@Inject注解。這樣MainActivity里的mainPresenter與他的構(gòu)造函數(shù)建立了某種聯(lián)系。這種聯(lián)系我們可以這樣理解,當(dāng)看到某個(gè)類被@Inject標(biāo)記時(shí),就會(huì)到他的構(gòu)造方法中,如果這個(gè)構(gòu)造方法也被@Inject標(biāo)記的話,就會(huì)自動(dòng)初始化這個(gè)類,從而完成依賴注入。

然后,他們之間并不會(huì)憑空建立起聯(lián)系,因此我們想到,肯定需要一個(gè)橋梁,將他們連接起來(lái),也就是下面要介紹的Component。

Component是一個(gè)接口或者抽象類,用@Component注解標(biāo)注(這里先不管括號(hào)里的modules),我們?cè)谶@個(gè)接口中定義了一個(gè)inject()方法,參數(shù)是Mainactivity。然后rebuild一下項(xiàng)目,會(huì)生成一個(gè)以Dagger為前綴的Component類,這里是DaggerMainComponent,然后在MainActivity里完成下面代碼.

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

此時(shí)Component就將@Inject注解的mainPresenter與其構(gòu)造函數(shù)聯(lián)系了起來(lái)。此時(shí),看到這里,如果是初學(xué)者的話,一定會(huì)非常迷惑,究竟是怎么建立起聯(lián)系的,實(shí)例化過(guò)程在哪?別急,后面會(huì)講解這個(gè)過(guò)程原理的。

此時(shí)我們已經(jīng)完成了presenter的注入過(guò)程,但是我們發(fā)現(xiàn)還有一個(gè)MainModule類,這個(gè)類是做什么的?MainModlue是一個(gè)注解類,用@Module注解標(biāo)注,主要用來(lái)提供依賴。等等,剛才通過(guò)@Inject就可以完成依賴,為什么這里還要用到Module類來(lái)提供依賴?之所以有Module類主要是為了提供那些沒有構(gòu)造函數(shù)的類的依賴,這些類無(wú)法用@Inject標(biāo)注,比如第三方類庫(kù),系統(tǒng)類,以及上面示例的View接口。

我們?cè)贛ainModule類里聲明了MainContract.View成員屬性,在構(gòu)造方法里將外界傳進(jìn)來(lái)的view賦值給mView,并通過(guò)一個(gè)@Provides標(biāo)注的以provide開頭的方法,將這個(gè)view返回,這個(gè)以provide開頭的方法就是提供依賴的,我們可以創(chuàng)建多個(gè)方法來(lái)提供不同的依賴。那么這個(gè)類究竟是怎么作用的?可以想到上面提到的@Component注解括號(hào)里的東西了。就是下面這個(gè)

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

所以Module要發(fā)揮作用,還是要依靠于Component類,一個(gè)Component類可以包含多個(gè)Module類,用來(lái)提供依賴。我們接著看下面這段代碼:

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

這里通過(guò)new MainModule(this)將view傳遞到MainModule里,然后MainModule里的provideMainView()方法返回這個(gè)View,當(dāng)去實(shí)例化MainPresenter時(shí),發(fā)現(xiàn)構(gòu)造函數(shù)有個(gè)參數(shù),此時(shí)會(huì)在Module里查找提供這個(gè)依賴的方法,將該View傳遞進(jìn)去,這樣就完成了presenter里View的注入。

我們來(lái)重新理一遍上面的注入過(guò)程,首先弄清楚以下幾個(gè)概念:

  • @Inject 帶有此注解的屬性或構(gòu)造方法將參與到依賴注入中,Dagger2會(huì)實(shí)例化有此注解的類
  • @Module 帶有此注解的類,用來(lái)提供依賴,里面定義一些用@Provides注解的以provide開頭的方法,這些方法就是所提供的依賴,Dagger2會(huì)在該類中尋找實(shí)例化某個(gè)類所需要的依賴。
  • @Component 用來(lái)將@Inject和@Module聯(lián)系起來(lái)的橋梁,從@Module中獲取依賴并將依賴注入給@Inject

接著我們重新回顧一下上面的注入過(guò)程:首先MainActivity需要依賴MainPresenter,因此,我們?cè)诶锩嬗聾Inject對(duì)MainPresenter進(jìn)行標(biāo)注,表明這是要注入的類。然后,我們對(duì)MainPresenter的構(gòu)造函數(shù)也添加注解@Inject,此時(shí)構(gòu)造函數(shù)里有一個(gè)參數(shù)MainContract.View,因?yàn)镸ainPresenter需要依賴MainContract.View,所以我們定義了一個(gè)類,叫做MainModule,提供一個(gè)方法provideMainView,用來(lái)提供這個(gè)依賴,這個(gè)MainView是通過(guò)MainModule的構(gòu)造函數(shù)注入進(jìn)來(lái)的,接著我們需要定義Component接口類,并將Module包含進(jìn)來(lái),即

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

同時(shí)里面聲明了一個(gè)inject方法,方法參數(shù)為ManActivity,用來(lái)獲取MainActivity實(shí)例,以初始化在里面聲明的MainPresenter

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

此時(shí),注入過(guò)程就完成了,或許到此時(shí),還是會(huì)有一些疑惑,因?yàn)槲覀兛床坏綄?shí)例化的過(guò)程在哪里,為什么要這樣去寫代碼,所以下面,就基于這個(gè)實(shí)例,分析Dagger2內(nèi)部究竟做了什么。

Dagger2注入原理

Dagger2與其他依賴注入框架不同,它是通過(guò)apt插件在編譯階段生成相應(yīng)的注入代碼,下面我們就具體看看Dagger2生成了哪些注入代碼?

我們先看MainPresenter這個(gè)類,在這個(gè)類中我們對(duì)構(gòu)造方法用了@Inject標(biāo)注,然后Rebuild Project,Dagger2會(huì)在/app/build/generated/apt/debug/目錄下生成一個(gè)對(duì)應(yīng)的工廠類MainPresenter_Factory,我們看下面具體代碼(為了方便理解,我把MainPresenter也貼了出來(lái))

public class MainPresenter {
    MainContract.View mView;
    @Inject
    MainPresenter(MainContract.View view) {
        mView = view;
    }
 }


public final class MainPresenter_Factory implements Factory<MainPresenter> {
  private final Provider<MainContract.View> viewProvider;

  public MainPresenter_Factory(Provider<MainContract.View> viewProvider) {
    assert viewProvider != null;
    this.viewProvider = viewProvider;
  }

  @Override
  public MainPresenter get() {
    return new MainPresenter(viewProvider.get());
  }

  public static Factory<MainPresenter> create(Provider<MainContract.View> viewProvider) {
    return new MainPresenter_Factory(viewProvider);
  }
}

對(duì)比MainPresenter,我們發(fā)現(xiàn)在MainPre_Factory里也生成了對(duì)應(yīng)的代碼。首先是viewProvide,這是一個(gè)Provider類型,泛型參數(shù)就是我們的MainContract.View,接著通過(guò)構(gòu)造方法,對(duì)viewProvider進(jìn)行實(shí)例化。其實(shí)這里有個(gè)疑惑,上面的成員屬性為什么不直接是MainContract.View,而是Provider類型?看到provider我們應(yīng)該想到這個(gè)MainContract.View是一個(gè)依賴,而依賴的提供者是MainModule,因此這個(gè)viewProvider一定是由MainModul提供的。我們接著看下面的get()方法,看到這個(gè)方法,我想我們有點(diǎn)恍然大悟的感覺,原來(lái)MainPresenter的實(shí)例化就在這里,構(gòu)造函數(shù)里的參數(shù)就是我們依賴的MainContract.View,它是由viewProvider通過(guò)get()提供。接著是一個(gè)create()方法,并且有一個(gè)參數(shù)viewProvider,用來(lái)創(chuàng)建這個(gè)MainPresenter_Factory類。

上面我們得出,viewProvider是由MainModule提供的,所以我們接著看MainModule所對(duì)應(yīng)的注入類。

@Module
public class MainModule {
    private final MainContract.View mView;

    public MainModule(MainContract.View view) {
        mView = view;
    }

    @Provides
    MainContract.View provideMainView() {
        return mView;
   }   
}


public final class MainModule_ProvideMainViewFactory implements Factory<MainContract.View> {
  private final MainModule module;

  public MainModule_ProvideMainViewFactory(MainModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public MainContract.View get() {
    return Preconditions.checkNotNull(
        module.provideMainView(), "Cannot return null from a non-@Nullable @Provides method");
  }

  public static Factory<MainContract.View> create(MainModule module) {
    return new MainModule_ProvideMainViewFactory(module);
  }
}

看到上面的類名,我們發(fā)現(xiàn)了一種對(duì)應(yīng)關(guān)系,在MainModule中定義的@Provides修飾的方法會(huì)對(duì)應(yīng)的生成一個(gè)工廠類,這里是MainModule_ProvideMainViewFactory。我們看到這個(gè)類里有一個(gè)get()方法,其中調(diào)用了MainModule里的provideMainView()方法來(lái)返回我們所需要的依賴MainContract.View。還記得在MainPresenter_Factory里的get()方法中,實(shí)例化MainPresenter時(shí)候的參數(shù)viewProvider.get()嗎?到這里我們就明白了,原來(lái)那個(gè)viewProvider就是生成的MainModule_ProvideMainViewFactory,然后調(diào)用了其get()方法,將我們需要的MainContract.View注入到MainPresenter里。

看到這里我們應(yīng)該明白了MainPresenter的實(shí)例化過(guò)程。MainPresenter會(huì)對(duì)應(yīng)的有一個(gè)工廠類,在這個(gè)類的get()方法中進(jìn)行MainPresenter創(chuàng)建,而MainPresenter所需要的View依賴,是由MainModule里定義的以provide開頭的方法所對(duì)應(yīng)的工廠類提供的。

雖然我們明白了實(shí)例化的創(chuàng)建過(guò)程,但是此時(shí)還是有點(diǎn)疑惑,MainPresenter_Factory的創(chuàng)建是由create()完成的,那么crate是在哪調(diào)用的,此時(shí)創(chuàng)建的MainPresenter實(shí)例是怎么跟@Inject注解的MainPresenter關(guān)聯(lián)起來(lái)的,我想你已經(jīng)知道了答案,沒錯(cuò)就是Component。前面說(shuō)過(guò)Component是連接@Module和@Inject的橋梁,所以上面的疑惑就要到編譯后Component所對(duì)應(yīng)的類中尋找答案。

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

public final class DaggerMainComponent implements MainComponent {
  private Provider<MainContract.View> provideMainViewProvider;

  private Provider<MainPresenter> mainPresenterProvider;

  private MembersInjector<MainActivity> mainActivityMembersInjector;

  private DaggerMainComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

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

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);

    this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
  }

  @Override
  public void inject(MainActivity activity) {
    mainActivityMembersInjector.injectMembers(activity);
  }

  public static final class Builder {
    private MainModule mainModule;

    private Builder() {}

    public MainComponent build() {
      if (mainModule == null) {
        throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerMainComponent(this);
    }

    public Builder mainModule(MainModule mainModule) {
      this.mainModule = Preconditions.checkNotNull(mainModule);
      return this;
    }
  }
}

從上面代碼看到定義的MainComponent會(huì)生成一個(gè)對(duì)應(yīng)的DaggerMainComponent,并且實(shí)現(xiàn)了MainComponent里的方法。我們看到代碼中又出現(xiàn)了Provide類型的成員屬性,前面說(shuō)過(guò)這個(gè)Provide類型就是所提供的依賴,我們?cè)诳此鼈兪窃谀膶?shí)例化的。我們看到有一個(gè)initialize()方法


@SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);

    this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
  }
  

看到這估計(jì)就明白了剛才的疑惑。首先創(chuàng)建了MainModule_ProvideMainViewFactory實(shí)例,用來(lái)提供MainContract.View依賴。這里可能有個(gè)小疑惑,create()方法返回的是Factory類型,而provideMainViewProvider是個(gè)Provider類型,其實(shí)看源碼就明白了,F(xiàn)actory繼承自Provider。

public interface Factory<T> extends Provider<T> {
}

然后將provideMainViewProvider傳遞到MainPresenter_Factory里,即就是前面講到的viewProvider。接著將這個(gè)mainPresenterProvider又傳遞到MainActivity_MembersInjector中進(jìn)行實(shí)例化,我們看到這個(gè)類前面是MainActivity開頭,因此可以想到是MainActivity對(duì)應(yīng)得注入類,我們后面再分析這個(gè)類。

接著是我們?cè)贛ainComponent里定義的Inject方法的實(shí)現(xiàn),這里調(diào)用了mainActivityMembersInjector.injectMembers(activity)方法,將我們的MainActivity注入到該類中。

接著就是Builder內(nèi)部類,用來(lái)創(chuàng)建我們的module以及自身實(shí)例。所以在DaggerMainComponent里主要用來(lái)初始化依賴,而真正的將這些依賴于Inject關(guān)聯(lián)起來(lái)的就是剛才的MainActivity_MembersInjector類,我們看看這個(gè)類里做了什么。

public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<MainPresenter> mainPresenterProvider;

  public MainActivity_MembersInjector(Provider<MainPresenter> mainPresenterProvider) {
    assert mainPresenterProvider != null;
    this.mainPresenterProvider = mainPresenterProvider;
  }

  public static MembersInjector<MainActivity> create(
      Provider<MainPresenter> mainPresenterProvider) {
    return new MainActivity_MembersInjector(mainPresenterProvider);
  }

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mainPresenter = mainPresenterProvider.get();
  }

  public static void injectMainPresenter(
      MainActivity instance, Provider<MainPresenter> mainPresenterProvider) {
    instance.mainPresenter = mainPresenterProvider.get();
  }
}

這個(gè)類的關(guān)鍵就是injectMembers()方法,還記得這個(gè)方法在哪調(diào)用嗎?我想你肯定記得,就在剛才提到的DaggerMainComponent類中的inject()方法里,所以這里的instance實(shí)例是由DaggerMainComponent提供的,然后我們看到了最關(guān)鍵的一句代碼

instance.mainPresenter = mainPresenterProvider.get();

看到這,我想應(yīng)該一切都明白了,將mainPresenterProvider中創(chuàng)建好的MainPresenter實(shí)例賦值給instance(MainActivity)的成員mainPresenter,這樣我們用@Inject標(biāo)注的mainPresenter就得到了實(shí)例化,接著就可以在代碼中使用了。

到這里,就分析完了Dagger2的注入過(guò)程,如果不去看這些生成的類,就很難理解整個(gè)過(guò)程究竟是怎么發(fā)生的,從而導(dǎo)致還是不知道怎么去使用這個(gè)依賴注入框架。所以重點(diǎn)去理解這個(gè)內(nèi)部實(shí)現(xiàn)原理是非常重要的,剛開始學(xué)的時(shí)候也是一臉懵逼,總搞不太清之間的關(guān)系,不知道究竟怎么寫,弄懂了整個(gè)來(lái)龍去脈后,發(fā)現(xiàn)就知道怎么去運(yùn)用了。

關(guān)于Dagger2的其他使用就不多講了,可以看其他的優(yōu)秀博客,我會(huì)再后面附上鏈接,方便學(xué)習(xí)。Dagger2就是一個(gè)依賴注入工具,至于怎么使用完全在個(gè)人,所以不必糾結(jié)到底怎么去寫才是正確的,只要弄懂原理,靈活運(yùn)用,能夠做到盡可能解耦,適合自己的業(yè)務(wù)就是最好的寫法。

感謝:

http://www.lxweimin.com/p/cd2c1c9f68d4

http://alighters.com/blog/2016/04/15/dagger2-indepth-understanding/

http://chriszou.com/2016/05/10/android-unit-testing-di-dagger.html

http://blog.nimbledroid.com/2016/03/07/performance-of-dependency-injection-libraries-zh.html

http://google.github.io/dagger/

招聘:
我目前就職于阿里巴巴-菜鳥,團(tuán)隊(duì)目前缺人,招聘java和客戶端開發(fā),招聘對(duì)象為:社招和19屆畢業(yè)的校招生,有適合的人選發(fā)送簡(jiǎn)歷到我個(gè)人郵箱:hsk256@163.com,謝謝大家。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,273評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,527評(píng)論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,010評(píng)論 1 322
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,250評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,769評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,656評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,853評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,103評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,487評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,815評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容