<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 為什么網上這么多dagger2教程,我還寫了這篇文章。 1. 找了很多Dagger2相關的博客,我看的腦漿炸裂…… 2. Dagger2給我們帶來了什么,大多數博文也沒有說明 3. 手動寫寫,加深印象,騙騙粉絲 (手動滑稽) 4. 部分Dagger2的運作機制是我個人的臆測,比如Dagger2編譯入口,不過應該八九不離十吧,測試了挺多次的,沒有@Component的話是不會編譯的=。= ## 一、Dagger2使用Q&A **Q1:dagger2是什么,有什么用?** A1:dagger2是一個基于JSR-330標準的依賴注入框架,在編譯期間自動生成代碼,負責依賴對象的創建。 **Q2:什么是JSR-330** A2:JSR即Java Specification Requests,意思是java規范提要。 而JSR-330則是 Java依賴注入標準 關于JSR-330可以閱讀這篇文章[Java 依賴注入標準(JSR-330)簡介](http://blog.csdn.net/dl88250/article/details/4838803),隨便看下就好了,不是重點。 **Q3:用dagger2提供依賴有什么好處** A:3:為了進一步解耦和方便測試,我們會使用依賴注入的方式構建對象。(可以看這篇文章[使用Dagger2前你必須了解的一些設計原則](http://www.jianshu.com/p/cc1427e385b5)) 但是,在Activity中有可能出現這樣的情況。 ~~~ public class LoginActivity extends AppCompatActivity { LoginActivityPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); OkHttpClient okHttpClient = new OkHttpClient(); RestAdapter.Builder builder = new RestAdapter.Builder(); builder.setClient(new OkClient(okHttpClient)); RestAdapter restAdapter = builder.build(); ApiService apiService = restAdapter.create(ApiService.class); UserManager userManager = UserManager.getInstance(apiService); UserDataStore userDataStore = UserDataStore.getInstance( getSharedPreferences("prefs", MODE_PRIVATE) ); //Presenter is initialized here presenter = new LoginActivityPresenter(this, userManager, userDataStore); } } ~~~ 其實我們需要的只是`LoginActivityPresenter`對象,但是因為使用依賴注入的原因,我們不得不在LoginActivity中初始化一大堆Presenter所需要的依賴。 現在不僅依賴于`LoginActivityPresenter`,還依賴`OkHttpClient ,UserManager ,RestAdapter`等。它們之中任何一個的構造改變了,或者Presenter構造改變了,我們都需要反復修改LoginActivity中的代碼。 而dagger框架就解決了這種問題,使用dagger2框架后相同代碼如下: ~~~ public class LoginActivity extends AppCompatActivity { @Inject LoginActivityPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Satisfy all dependencies requested by @Inject annotation getDependenciesGraph().inject(this); } } ~~~ LoginActivity瞬間清爽了。dagger2框架可以讓依賴注入獨立于組件之外,不管Presenter的依賴怎么改,都不會對LoginActivity的代碼照成任何影響,**這就是dagger2框架的好處了** ## 二、Dagger2 API ~~~ public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies() default {}; } public @interface Subcomponent { Class<?>[] modules() default {}; } public @interface Module { Class<?>[] includes() default {}; } public @interface Provides { } public @interface MapKey { boolean unwrapValue() default true; } public interface Lazy<T> { T get(); } ~~~ 還有在Dagger 2中用到的定義在 [JSR-330](https://jcp.org/en/jsr/detail?id=330) (Java中依賴注入的標準)中的其它元素: ~~~ public @interface Inject { } public @interface Scope { } public @interface Qualifier { } ~~~ ## 三、@Inject和@Component 先來看一段沒有使用dagger的依賴注入Demo MainActivity依賴Pot, Pot依賴Rose ~~~ public class Rose { public String whisper() { return "熱戀"; } } ~~~ ~~~ public class Pot { private Rose rose; @Inject public Pot(Rose rose) { this.rose = rose; } public String show() { return rose.whisper(); } } ~~~ ~~~ public class MainActivity extends AppCompatActivity { private Pot pot; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Rose rose = new Rose(); pot = new Pot(rose); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); } } ~~~ 使用Dagger2進行依賴注入如下: ~~~ public class Rose { @Inject public Rose() {} public String whisper() { return "熱戀"; } } ~~~ ~~~ public class Pot { private Rose rose; @Inject public Pot(Rose rose) { this.rose = rose; } public String show() { return rose.whisper(); } } ~~~ ~~~ @Component public interface MainActivityComponent { void inject(MainActivity activity); } ~~~ ~~~ public class MainActivity extends AppCompatActivity { @Inject Pot pot; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 這個類是重新編譯后Dagger2自動生成的,所以寫這行代碼之前要先編譯一次 // Build --> Rebuild Project DaggerMainActivityComponent.create().inject(this); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); } } ~~~ Dagger2生成的代碼保存在這里: ![](http://upload-images.jianshu.io/upload_images/2202079-cdf20511b8e40939.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) Dagger2 apt.png 源碼待會分析,現在先來了解下`@Inject`和`@Component`兩個API,想要使用Dagger2進行依賴注入,至少要使用到這兩個注解。 `@Inject`用于標記需要注入的依賴,或者標記用于提供依賴的方法。 `@Component`則可以理解為注入器,在注入依賴的目標類`MainActivity`使用Component完成注入。 ### @Inject 依賴注入中第一個并且是最重要的就是`@Inject`注解。JSR-330標準中的一部分,標記那些應該被依賴注入框架提供的依賴。在Dagger 2中有3種不同的方式來提供依賴: 1. **構造器注入,@Inject標注在構造器上其實有兩層意思。** ①告訴Dagger2可以使用這個構造器構建對象。如`Rose`類 ②注入構造器所需要的參數的依賴。 如`Pot`類,構造上的Rose會被注入。 構造器注入的局限:如果有多個構造器,我們只能標注其中一個,無法標注多個。 2. **屬性注入** 如`MainActivity`類,標注在屬性上。被標注的屬性不能使用`private`修飾,否則無法注入。 屬性注入也是Dagger2中使用最多的一個注入方式。 3. **方法注入** ~~~ public class MainActivity extends AppCompatActivity { private Pot pot; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerMainActivityComponent.create().inject(this); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); } @Inject public void setPot(Pot pot) { this.pot = pot; } } ~~~ 標注在public方法上,Dagger2會在構造器執行之后立即調用這個方法。 方法注入和屬性注入基本上沒有區別, 那么什么時候應該使用方法注入呢? 比如該依賴需要this對象的時候,使用方法注入可以提供安全的this對象,因為方法注入是在構造器之后執行的。 比如google mvp dagger2中,給View設置Presenter的時候可以這樣使用方法注入。 ~~~ /** * Method injection is used here to safely reference {@code this} after the object is created. * For more information, see Java Concurrency in Practice. */ @Inject void setupListeners() { mTasksView.setPresenter(this); } ~~~ ### @Component `@Inject`注解只是JSR-330中定義的注解,在`javax.inject`包中。 這個注解本身并沒有作用,它需要依賴于注入框架才具有意義,用來標記需要被注入框架注入的方法,屬性,構造。 而Dagger2則是用`Component`來完成依賴注入的,`@Component`可以說是Dagger2中最重要的一個注解。 ~~~ @Component public interface MainActivityComponent { void inject(MainActivity activity); } ~~~ 以上是定義一個Component的方式。使用接口定義,并且`@Component`注解。 命名方式推薦為:`目標類名+Component`,在編譯后Dagger2就會為我們生成`DaggerXXXComponent`這個類,它是我們定義的`xxxComponent`的實現,在目標類中使用它就可以實現依賴注入了。 **Component中一般使用兩種方式定義方法。** 1. `void inject(目標類 obj);`Dagger2會從目標類開始查找@Inject注解,自動生成依賴注入的代碼,調用inject可完成依賴的注入。 2. `Object getObj();` 如:`Pot getPot();` Dagger2會到Pot類中找被@Inject注解標注的構造器,自動生成提供Pot依賴的代碼,這種方式一般為其他Component提供依賴。(一個Component可以依賴另一個Component,后面會說) **Component和Inject的關系如下:** ![](http://upload-images.jianshu.io/upload_images/2202079-51b78542dd3c8575.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) Jsr330和Dagger2.png Dagger2框架以Component中定義的方法作為入口,到目標類中尋找JSR-330定義的@Inject標注,生成一系列提供依賴的Factory類和注入依賴的Injector類。 而Component則是聯系Factory和Injector,最終完成依賴的注入。 **我們看下源碼(請對應上面的Dagger2 apt圖一起看):** **Rose_Factory和Pot_Factory分別對應Rose類和Pot類的構造器上的@Inject注解。** 而Factory其實是個Provider對象 ~~~ public interface Provider<T> { /** * Provides a fully-constructed and injected instance of {@code T}. * * @throws RuntimeException if the injector encounters an error while * providing an instance. For example, if an injectable member on * {@code T} throws an exception, the injector may wrap the exception * and throw it to the caller of {@code get()}. Callers should not try * to handle such exceptions as the behavior may vary across injector * implementations and even different configurations of the same injector. */ T get(); } ~~~ ~~~ public interface Factory<T> extends Provider<T> {} ~~~ 為什么這里要使用枚舉作為提供Rose對象的Provide我也不太清楚,反正能提供就對了=。= ~~~ public enum Rose_Factory implements Factory<Rose> { INSTANCE; @Override public Rose get() { return new Rose(); } public static Factory<Rose> create() { return INSTANCE; } } ~~~ Pot對象依賴Rose,所以直接將RoseProvide作為參數傳入了。 ~~~ public final class Pot_Factory implements Factory<Pot> { private final Provider<Rose> roseProvider; public Pot_Factory(Provider<Rose> roseProvider) { assert roseProvider != null; this.roseProvider = roseProvider; } @Override public Pot get() { return new Pot(roseProvider.get()); } public static Factory<Pot> create(Provider<Rose> roseProvider) { return new Pot_Factory(roseProvider); } } ~~~ **MainActivity上的@Inject屬性或方法注解,則對應MainActivity_MembersInjector類** ~~~ public interface MembersInjector<T> { /** * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or * absence of an injectable constructor. * * <p>Whenever the object graph creates an instance, it performs this injection automatically * (after first performing constructor injection), so if you're able to let the object graph * create all your objects for you, you'll never need to use this method. * * @param instance into which members are to be injected * @throws NullPointerException if {@code instance} is {@code null} */ void injectMembers(T instance); } ~~~ ~~~ public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> { private final Provider<Pot> potProvider; public MainActivity_MembersInjector(Provider<Pot> potProvider) { assert potProvider != null; this.potProvider = potProvider; } public static MembersInjector<MainActivity> create(Provider<Pot> potProvider) { return new MainActivity_MembersInjector(potProvider); } @Override public void injectMembers(MainActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.pot = potProvider.get(); } public static void injectPot(MainActivity instance, Provider<Pot> potProvider) { instance.pot = potProvider.get(); } } ~~~ 最后是DaggerMainActivityComponent類,對應@Component注解就不多說了。這是Dagger2解析JSR-330的入口。 它聯系Factory和MainActivity兩個類完成注入。 ~~~ public final class DaggerMainActivityComponent implements MainActivityComponent { private Provider<Pot> potProvider; private MembersInjector<MainActivity> mainActivityMembersInjector; private DaggerMainActivityComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static MainActivityComponent create() { return builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.potProvider = Pot_Factory.create(Rose_Factory.create()); this.mainActivityMembersInjector = MainActivity_MembersInjector.create(potProvider); } @Override public void inject(MainActivity activity) { mainActivityMembersInjector.injectMembers(activity); } public static final class Builder { private Builder() {} public MainActivityComponent build() { return new DaggerMainActivityComponent(this); } } } ~~~ 只使用幾個注解,Dagger2就默默中為我們做了這么多事情,太感動了…… 看完這個,相信大家已經完全理解了@Inject和@Component兩個注解的作用了,要區分的是,@Inject是JSR330定義的,而@Component是Dagger2框架自己定義的。 ## 四、@Module和@Provides 使用@Inject標記構造器提供依賴是有局限性的,比如說我們需要注入的對象是第三方庫提供的,我們無法在第三方庫的構造器上加上@Inject注解。 或者,我們使用依賴倒置的時候,因為需要注入的對象是抽象的,@Inject也無法使用,因為抽象的類并不能實例化,比如: ~~~ public abstract class Flower { public abstract String whisper(); } ~~~ ~~~ public class Lily extends Flower { @Inject Lily() {} @Override public String whisper() { return "純潔"; } } ~~~ ~~~ public class Rose extends Flower { @Inject public Rose() {} public String whisper() { return "熱戀"; } } ~~~ ~~~ public class Pot { private Flower flower; @Inject public Pot(Flower flower) { this.flower = flower; } public String show() { return flower.whisper(); } } ~~~ 修改下Demo,遵循依賴倒置規則。但是這時候Dagger就報錯了,因為Pot對象需要Flower,而Flower是抽象的,無法使用@Inject提供實例。 ![](http://upload-images.jianshu.io/upload_images/2202079-798acb053f54eb7d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 抽象的依賴.png 這時候就需要用到Module了。 清除Lily和Rose的@Inject ~~~ public class Lily extends Flower { @Override public String whisper() { return "純潔"; } } ~~~ ~~~ public class Rose extends Flower { public String whisper() { return "熱戀"; } } ~~~ @Module標記在類上面,@Provodes標記在方法上,表示可以通過這個方法獲取依賴。 ~~~ @Module public class FlowerModule { @Provides Flower provideFlower() { return new Rose(); } } ~~~ 在@Component中指定Module ~~~ @Component(modules = FlowerModule.class) public interface MainActivityComponent { void inject(MainActivity activity); } ~~~ 其他類不需要更改,這樣就完成了。 那么Module是干嘛的,我們來看看生成的類。 ![](http://upload-images.jianshu.io/upload_images/2202079-60ef03623d0d85c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) Module.png 可以看到,被@Module注解的類生成的也是Factory。 ~~~ public final class FlowerModule_FlowerFactory implements Factory<Flower> { private final FlowerModule module; public FlowerModule_FlowerFactory(FlowerModule module) { assert module != null; this.module = module; } @Override public Flower get() { return Preconditions.checkNotNull( module.provideFlower(), "Cannot return null from a non-@Nullable @Provides method"); } public static Factory<Flower> create(FlowerModule module) { return new FlowerModule_FlowerFactory(module); } } ~~~ @Module需要和@Provide是需要一起使用的時候才具有作用的,并且@Component也需要指定了該Module的時候。 @Module是告訴Component,可以從這里獲取依賴對象。Component就會去找被@Provide標注的方法,相當于構造器的@Inject,可以提供依賴。 還有一點要說的是,@Component可以指定多個@Module的,如果需要提供多個依賴的話。 并且Component也可以依賴其它Component存在。 ## 五、@Qualifier和@Named @Qualifier是限定符,而@Named則是基于String的限定符。 當我有兩個相同的依賴(都繼承某一個父類或者都是先某一個接口)可以提供給高層時,那么程序就不知道我們到底要提供哪一個依賴,因為它找到了兩個。 這時候我們就可以通過限定符為兩個依賴分別打上標記,指定提供某個依賴。 接著上一個Demo,例如:Module可以提供的依賴有兩個。 ~~~ @Module public class FlowerModule { @Provides Flower provideRose() { return new Rose(); } @Provides Flower provideLily() { return new Lily(); } } ~~~ ![](http://upload-images.jianshu.io/upload_images/2202079-1c4a2b616d4e8781.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 多個Provider 這時候就可以用到限定符來指定依賴了,我這里用@Named來演示。 ~~~ @Module public class FlowerModule { @Provides @Named("Rose") Flower provideRose() { return new Rose(); } @Provides @Named("Lily") Flower provideLily() { return new Lily(); } } ~~~ 我們是通過@Inject Pot的構造器注入Flower依賴的,在這里可以用到限定符。 ~~~ public class Pot { private Flower flower; @Inject public Pot(@Named("Rose") Flower flower) { this.flower = flower; } public String show() { return flower.whisper(); } } ~~~ 而@Qualifier的作用和@Named是完全一樣的,不過更推薦使用@Qualifier,因為@Named需要手寫字符串,容易出錯。 @Qualifier不是直接注解在屬性上的,而是用來自定義注解的。 ~~~ @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface RoseFlower {} ~~~ ~~~ @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface LilyFlower {} ~~~ ~~~ @Module public class FlowerModule { @Provides @RoseFlower Flower provideRose() { return new Rose(); } @Provides @LilyFlower Flower provideLily() { return new Lily(); } } ~~~ ~~~ public class Pot { private Flower flower; @Inject public Pot(@RoseFlower Flower flower) { this.flower = flower; } public String show() { return flower.whisper(); } } ~~~ * * * 我們也可以使用Module來管理Pot依賴,當然還是需要@Qualifier指定提供哪一個依賴 ~~~ @Module public class PotModule { @Provides Pot providePot(@RoseFlower Flower flower) { return new Pot(flower); } } ~~~ 然后MainAcitivtyComponent需要增加一個Module ~~~ @Component(modules = {FlowerModule.class, PotModule.class}) public interface MainActivityComponent { void inject(MainActivity activity); } ~~~ ## 六、@Component的dependence和@SubComponent [參考:SubComponent和Dependence區別](http://stackoverflow.com/questions/29587130/dagger-2-subcomponents-vs-component-dependencies) 上面也說過,Component可以依賴于其他Component,可以使用@Component的dependence,也可以使用@SubComponent,這樣就可以獲取其他Component的依賴了。 如:我們也用Component來管理FlowerModule和PotModule,并且使用dependence聯系各個Component。 這次我就將代碼貼完整點吧。 ~~~ public abstract class Flower { public abstract String whisper(); } ~~~ ~~~ public class Lily extends Flower { @Override public String whisper() { return "純潔"; } } ~~~ ~~~ public class Rose extends Flower { public String whisper() { return "熱戀"; } } ~~~ ~~~ @Module public class FlowerModule { @Provides @RoseFlower Flower provideRose() { return new Rose(); } @Provides @LilyFlower Flower provideLily() { return new Lily(); } } ~~~ Component上也需要指定@Qualifier ~~~ @Component(modules = FlowerModule.class) public interface FlowerComponent { @RoseFlower Flower getRoseFlower(); @LilyFlower Flower getLilyFlower(); } ~~~ ~~~ public class Pot { private Flower flower; public Pot(Flower flower) { this.flower = flower; } public String show() { return flower.whisper(); } } ~~~ PotModule需要依賴Flower,需要指定其中一個子類實現,這里使用RoseFlower ~~~ @Module public class PotModule { @Provides Pot providePot(@RoseFlower Flower flower) { return new Pot(flower); } } ~~~ ~~~ @Component(modules = PotModule.class,dependencies = FlowerComponent.class) public interface PotComponent { Pot getPot(); } ~~~ ~~~ @Component(dependencies = PotComponent.class) public interface MainActivityComponent { void inject(MainActivity activity); } ~~~ 而在MainActivity則需要創建其依賴的Component ~~~ public class MainActivity extends AppCompatActivity { @Inject Pot pot; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerMainActivityComponent.builder() .potComponent(DaggerPotComponent.builder() .flowerComponent(DaggerFlowerComponent.create()) .build()) .build().inject(this); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); } } ~~~ 這就是Component的dependencies的用法了,我們Component不需要重復的指定Module,可以直接依賴其它Component獲得。 分析下源碼,看下Component的dependencies做了什么事情。 ~~~ public final class DaggerPotComponent implements PotComponent { private Provider<Flower> getRoseFlowerProvider; private Provider<Pot> providePotProvider; private DaggerPotComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.getRoseFlowerProvider = new Factory<Flower>() { private final FlowerComponent flowerComponent = builder.flowerComponent; @Override public Flower get() { return Preconditions.checkNotNull( flowerComponent.getRoseFlower(), "Cannot return null from a non-@Nullable component method"); } }; this.providePotProvider = PotModule_ProvidePotFactory.create(builder.potModule, getRoseFlowerProvider); } @Override public Pot getPot() { return providePotProvider.get(); } public static final class Builder { private PotModule potModule; private FlowerComponent flowerComponent; private Builder() {} public PotComponent build() { if (potModule == null) { this.potModule = new PotModule(); } if (flowerComponent == null) { throw new IllegalStateException(FlowerComponent.class.getCanonicalName() + " must be set"); } return new DaggerPotComponent(this); } public Builder potModule(PotModule potModule) { this.potModule = Preconditions.checkNotNull(potModule); return this; } public Builder flowerComponent(FlowerComponent flowerComponent) { this.flowerComponent = Preconditions.checkNotNull(flowerComponent); return this; } } } ~~~ PotComponent依賴FlowerComponent,其實就是將FlowerComponent的引用傳遞給PotComponent,這樣PotComponent就可以使用FlowerComponent中的方法了。 注意看getRoseFlowerProvider這個Provider,是從 `flowerComponent.getRoseFlower()`獲取到的 * * * 如果使用Subcomponent的話則是這么寫, 其他類不需要改變,只修改Component即可 ~~~ @Component(modules = FlowerModule.class) public interface FlowerComponent { PotComponent plus(PotModule potModule); } ~~~ ~~~ @Subcomponent(modules = PotModule.class) public interface PotComponent { MainActivityComponent plus(); } ~~~ ~~~ @Subcomponent public interface MainActivityComponent { void inject(MainActivity activity); } ~~~ ~~~ public class MainActivity extends AppCompatActivity { @Inject Pot pot; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerFlowerComponent.create() .plus(new PotModule()) // 這個方法返回PotComponent .plus() // 這個方法返回MainActivityComponent .inject(this); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); } } ~~~ FlowerComponent管理了PotComponent和MainActivityComponent,看起來不符合常理。 先來說說Component中的方法的第三種定義方式(上面說了兩種)。 ~~~ @Component class AComponpent { XxxComponent plus(Module... modules) } ~~~ ~~~ @Subcomponent(modules = xxxxx) class XxxComponent { } ~~~ xxxComponent是該AComponpent的依賴,被@Subcomponent標注。 而modules參數則是xxxComponent指定的Module。 在重新編譯后,Dagger2生成的代碼中,Subcomponent標記的類是Componpent的內部類。 像上面的Demo,MainActivityComponent是PotComponent的內部類,而PotComponent又是FlowerComponent的內部類。 * * * 但是用Subcomponent怎么看怎么別扭,各個Component之間聯系太緊密,不太適合我們Demo的使用場景。 **那什么時候該用@Subcomponent呢?** Subcomponent是作為Component的拓展的時候。 像我寫的Demo中,Pot和Flower還有MainActivity只是單純的依賴關系。就算有,也只能是Flower作為Pot的Subcomponent,而不是Demo中所示,因為我需要給大家展示Dagger的API,強行使用。 **比較適合使用Subcomponent的幾個場景:** 很多工具類都需要使用到Application的Context對象,此時就可以用一個Component負責提供,我們可以命名為AppComponent。 需要用到的context對象的SharePreferenceComponent,ToastComponent就可以它作為Subcomponent存在了。 而且在AppComponent中,我們可以很清晰的看到有哪些子Component,因為在里面我們定義了很多`XxxComponent plus(Module... modules)` 每個ActivityComponent也是可以作為AppComponent的Subcomponent,這樣可以更方便的進行依賴注入,減少重復代碼。 **Component dependencies和Subcomponent區別** 1. Component dependencies 能單獨使用,而Subcomponent必須由Component調用方法獲取。 2. Component dependencies 可以很清楚的得知他依賴哪個Component, 而Subcomponent不知道它自己的誰的孩子……真可憐 3. 使用上的區別,Subcomponent就像這樣`DaggerAppComponent.plus(new SharePreferenceModule());` 使用Dependence可能是這樣`DaggerAppComponent.sharePreferenceComponent(SharePreferenceComponent.create())` **Component dependencies和Subcomponent使用上的總結** Component Dependencies: 1. 你想保留獨立的想個組件(Flower可以單獨使用注入,Pot也可以) 2. 要明確的顯示該組件所使用的其他依賴 Subcomponent: 1. 兩個組件之間的關系緊密 2. 你只關心Component,而Subcomponent只是作為Component的拓展,可以通過Component.xxx調用。 [Dagger 2 subcomponents vs component dependencies](http://stackoverflow.com/questions/29587130/dagger-2-subcomponents-vs-component-dependencies) ## 七、@Scope和@Singleton @Scope是用來管理依賴的生命周期的。它和@Qualifier一樣是用來自定義注解的,而@Singleton則是@Scope的默認實現。 ~~~ /** * Identifies a type that the injector only instantiates once. Not inherited. * * @see javax.inject.Scope @Scope */ @Scope @Documented @Retention(RUNTIME) public @interface Singleton {} ~~~ Component會幫我們注入被@Inject標記的依賴,并且可以注入多個。 但是每次注入都是重新new了一個依賴。如 ~~~ public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Pot pot; @Inject Pot pot2; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerMainActivityComponent.builder() .potComponent(DaggerPotComponent.builder() .flowerComponent(DaggerFlowerComponent.create()).build()) .build().inject(this); Log.d(TAG, "pot = " + pot.hashCode() +", pot2 = " + pot2.hashCode()); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); } } ~~~ 打印的地址值不一樣,是兩個對象。 `D/MainActivity: pot = com.aitsuki.architecture.pot.Pot@240f3ff5, pot2 = com.aitsuki.architecture.pot.Pot@2c79118a` 假設我們需要Pot對象的生命周期和app相同,也就是單例,我們需要怎么做?這時候就可以用到@Scope注解了。 我們來使用默認的@Scope實現——@Singleton 需要在@Provide和@Component中同時使用才起作用,為什么呢,待會會說明。 ~~~ @Module public class PotModule { @Provides @Singleton Pot providePot(@RoseFlower Flower flower) { return new Pot(flower); } } ~~~ ~~~ @Singleton @Component(modules = PotModule.class, dependencies = FlowerComponent.class) public interface PotComponent { Pot getPot(); } ~~~ 然后我們再運行下項目,報錯了 ![](http://upload-images.jianshu.io/upload_images/2202079-b60d581820901e83.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) @Scope報錯 那是因為我們的MainActivityComponent依賴PotComponent,而dagger2規定子Component也必須標注@Scope。 但是我們不能給MainActivityComponent也標注@Singleton,并且dagger2也不允許。因為單例依賴單例是不符合設計原則的,我們需要自定義一個@Scope注解。 定義Scope是名字要起得有意義,能一眼就讓你看出這個Scope所規定的生命周期。 比如ActivityScope 或者PerActivity,生命周期和Activity相同。 ~~~ @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope {} ~~~ ~~~ @ActivityScope @Component(dependencies = PotComponent.class) public interface MainActivityComponent { void inject(MainActivity activity); } ~~~ `D/MainActivity: pot = com.aitsuki.architecture.pot.Pot@240f3ff5, pot2 = com.aitsuki.architecture.pot.Pot@240f3ff5` 這時候我們看到兩個pot對象的地址值是一樣的,@Scope注解起作用了。 那么我再新建一個Activity,再次注入pot打印地址值。 ~~~ public class SecondActivity extends AppCompatActivity { private static final String TAG = "SecondActivity"; @Inject Pot pot3; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerSecondActivityComponent.builder() .potComponent(DaggerPotComponent.builder().flowerComponent(DaggerFlowerComponent.create()).build()) .build().inject(this); Log.d(TAG, "pot3 = " + pot3); } } ~~~ ~~~ @ActivityScope @Component(dependencies = PotComponent.class) public interface SecondActivityComponent { void inject(SecondActivity activity); } ~~~ 在MainActivity初始化時直接跳轉到SecondActivity ~~~ public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Pot pot; @Inject Pot pot2; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerMainActivityComponent.builder() .potComponent(DaggerPotComponent.builder() .flowerComponent(DaggerFlowerComponent.create()).build()) .build().inject(this); Log.d(TAG, "pot = " + pot +", pot2 = " + pot2); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); startActivity(new Intent(this, SecondActivity.class)); } } ~~~ `D/MainActivity: pot = com.aitsuki.architecture.pot.Pot@240f3ff5, pot2 = com.aitsuki.architecture.pot.Pot@240f3ff5` `D/SecondActivity: pot3 = com.aitsuki.architecture.pot.Pot@1b7661c7` 可以看到,在SecondActivity中,Pot對象地址和MainActivity中的不一樣了。 為什么呢?不是叫@Singleton么,為什么使用了它Pot還不是單例的,Dagger2你逗我! * * * 那么現在我可以說說@Scope的作用了,它的作用只是保證依賴在@Component中是唯一的,可以理解為“局部單例”。 **@Scope是需要成對存在的,在Module的Provide方法中使用了@Scope,那么對應的Component中也必須使用@Scope注解,當兩邊的@Scope名字一樣時(比如同為@Singleton), 那么該Provide方法提供的依賴將會在Component中保持“局部單例”。 而在Component中標注@Scope,provide方法沒有標注,那么這個Scope就不會起作用,而Component上的Scope的作用也只是為了能順利通過編譯,就像我剛剛定義的ActivityScope一樣。** @Singleton也是一個自定義@Scope,它的作用就像上面說的一樣。但由于它是Dagger2中默認定義的,所以它比我們自定義Scope對了一個功能,就是編譯檢測,防止我們不規范的使用Scope注解,僅此而已。 在上面的Demo中,Pot對象在PotComponent中是“局部單例”的。 而到了SecondActivity,因為是重新Build了一個PotComponent,所以Pot對象的地址值也就改變了。 **那么,我們如何使用Dagger2實現單例呢?** 很簡單,做到以下兩點即可。 1. 依賴在Component中是單例的(供該依賴的provide方法和對應的Component類使用同一個Scope注解。) 2. 對應的Component在App中只初始化一次,每次注入依賴都使用這個Component對象。(在Application中創建該Component) 如: ~~~ public class App extends Application { private PotComponent potComponent; @Override public void onCreate() { super.onCreate(); potComponent = DaggerPotComponent.builder() .flowerComponent(DaggerFlowerComponent.create()) .build(); } public PotComponent getPotComponent() { return potComponent; } } ~~~ 然后修改MainActivity和SecondActivity的Dagger代碼如下 ~~~ public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Pot pot; @Inject Pot pot2; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerMainActivityComponent.builder() .potComponent(((App) getApplication()).getPotComponent()) .build().inject(this); Log.d(TAG, "pot = " + pot +", pot2 = " + pot2); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); startActivity(new Intent(this, SecondActivity.class)); } } ~~~ ~~~ public class SecondActivity extends AppCompatActivity { private static final String TAG = "SecondActivity"; @Inject Pot pot3; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerSecondActivityComponent.builder() .potComponent(((App) getApplication()).getPotComponent()) .build().inject(this); Log.d(TAG, "pot3 = " + pot3); } } ~~~ 運行后的log輸出 `D/MainActivity: pot = com.aitsuki.architecture.pot.Pot@240f3ff5, pot2 = com.aitsuki.architecture.pot.Pot@240f3ff5` `D/SecondActivity: pot3 = com.aitsuki.architecture.pot.Pot@240f3ff5` 現在Pot的生命周期就和app相同了。 你也可以試試自定義一個@ApplicationScope,替換掉@Singleton,結果是一樣的,這里就不演示了。 稍微總結下@Scope注解: **Scope是用來給開發者管理依賴的生命周期的,它可以讓某個依賴在Component中保持 “局部單例”(唯一),如果將Component保存在Application中復用,則可以讓該依賴在app中保持單例。 我們可以通過自定義不同的Scope注解來標記這個依賴的生命周期,所以命名是需要慎重考慮的。** @Singleton告訴我們這個依賴時單例的 @ActivityScope告訴我們這個依賴的生命周期和Activity相同 @FragmentScope告訴我們這個依賴的生命周期和Fragment相同 @xxxxScope …… ## 八、MapKey和Lazy ### @MapKey 這個注解用在定義一些依賴集合(目前為止,Maps和Sets)。讓例子代碼自己來解釋吧: 定義: ~~~ @MapKey(unwrapValue = true) @interface TestKey { String value(); } ~~~ 提供依賴: ~~~ @Provides(type = Type.MAP) @TestKey("foo") String provideFooKey() { return "foo value"; } @Provides(type = Type.MAP) @TestKey("bar") String provideBarKey() { return "bar value"; } ~~~ 使用: ~~~ @Inject Map<String, String> map; map.toString() // => ?{foo=foo value, bar=bar value}” ~~~ @MapKey注解目前只提供兩種類型 - String和Enum。 ### Lazy Dagger2還支持Lazy模式,通過Lazy模擬提供的實例,在@Inject的時候并不初始化,而是等到你要使用的時候,主動調用其.get方法來獲取實例。 比如: ~~~ public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Inject Lazy<Pot> potLazy; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerMainActivityComponent.builder() .potComponent(((App) getApplication()).getPotComponent()) .build().inject(this); Pot pot = potLazy.get(); String show = pot.show(); Toast.makeText(MainActivity.this, show, Toast.LENGTH_SHORT).show(); } } ~~~ ## 九、項目實戰 略…… 233333333,直接去看Google的MVP模式吧,上面有例子,也可以去看看其他博客。 我也不知道寫不寫哈,有點小忙,就算寫也可能是國慶過后了。 ## 十、完結 看完這篇博文之后,感覺如何?博主表示寫的算是很詳細,很清晰易懂了。不懂的可以跟著思路敲一下哦,不動手,永遠不會知道Dagger2其實并沒有想象的那么難用…… 作者:AItsuki 鏈接:http://www.jianshu.com/p/24af4c102f62 來源:簡書 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看