第2章 計算機網絡體系結構

原文:https://google.github.io/dagger/androidjava

[toc]android

dagger.android

One of the central difficulties of writing an Android application using Dagger is that many Android framework classes are instantiated by the OS itself, like Activity and Fragment, but Dagger works best if it can create all the injected objects. Instead, you have to perform members injection in a lifecycle method. This means many classes end up looking like:git

使用Dagger編寫Android應用程序的主要困難之一是不少Android框架類都是由操做系統自己實例化的,例如Activity和Fragment,可是若是Dagger能夠建立全部注入的對象,則Dagger的效果最好。相反,您必須在生命週期方法中執行成員注入。這意味着許多類最終看起來像:github

public class FrombulationActivity extends Activity {
  @Inject Frombulator frombulator;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // DO THIS FIRST. Otherwise frombulator might be null!
    ((SomeApplicationBaseType) getContext().getApplicationContext())
        .getApplicationComponent()
        .newActivityComponentBuilder()
        .activity(this)
        .build()
        .inject(this);
    // ... now you can write the exciting code
  }
}

注入Activity對象

1.Install AndroidInjectionModule in your application component to ensure that all bindings necessary for these base types are available.app

1.在您的應用程序組件中安裝AndroidInjectionModule以確保這些基本類型所需的全部綁定均可用。框架

2.Start off by writing a @Subcomponent that implements AndroidInjector , with a @Subcomponent.Builder that extends AndroidInjector.Builder : less

2.首先編寫一個實現AndroidInjector<YourActivity>@Subcomponent和一個繼承AndroidInjector.Builder<YourActivity>@Subcomponent.Builderide

@Subcomponent(modules = ...)
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {
  @Subcomponent.Builder
  public abstract class Builder extends AndroidInjector.Builder<YourActivity> {}
}

3.After defining the subcomponent, add it to your component hierarchy by defining a module that binds the subcomponent builder and adding it to the component that injects your Application:函數

3.定義子組件後,經過定義一個綁定子組件層次結構並將其添加到注入應用程序的組件的模塊,將其添加到組件層次結構中。gradle

@Module(subcomponents = YourActivitySubcomponent.class)
abstract class YourActivityModule {
  @Binds
  @IntoMap
  @ActivityKey(YourActivity.class)
  abstract AndroidInjector.Factory<? extends Activity>
      bindYourActivityInjectorFactory(YourActivitySubcomponent.Builder builder);
}

@Component(modules = {..., YourActivityModule.class})
interface YourApplicationComponent {}

Pro-tip: If your subcomponent and its builder have no other methods or supertypes than the ones mentioned in step #2, you can use @ContributesAndroidInjector to generate them for you. Instead of steps 2 and 3, add an abstract module method that returns your activity, annotate it with @ContributesAndroidInjector, and specify the modules you want to install into the subcomponent. If the subcomponent needs scopes, apply the scope annotations to the method as well.

專業提示:若是您的子組件及其構建器沒有第2步中提到的其餘方法或超類型,您可使用@ContributesAndroidInjector爲您生成它們。添加一個抽象模塊方法,該方法返回您的活動,使用@ContributesAndroidInjector對其進行註釋,並指定要安裝到子組件中的模塊,而不是步驟2和3。若是子組件須要做用域,則也能夠將範圍註釋應用於該方法。

@ActivityScope
@ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();

4.Next, make your Application implement HasActivityInjector and @Inject a DispatchingAndroidInjector to return from the activityInjector() method:

4.接下來,讓您的Application實現HasActivityInjector而且@Inject一個從activityInjector()方法返回的DispatchingAndroidInjector<Activity>

public class YourApplication extends Application implements HasActivityInjector {
  @Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

  @Override
  public void onCreate() {
    super.onCreate();
    DaggerYourApplicationComponent.create()
        .inject(this);
  }

  @Override
  public AndroidInjector<Activity> activityInjector() {
    return dispatchingActivityInjector;
  }
}

5.Finally, in your Activity.onCreate() method, call AndroidInjection.inject(this) before calling super.onCreate();:

5.最終,在你的Activity.onCreate()方法中,在調用super.onCreate();以前調用AndroidInjection.inject(this)

public class YourActivity extends Activity {
  public void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
  }
}

如何工做

AndroidInjection.inject() gets a DispatchingAndroidInjector from the Application and passes your activity to inject(Activity). The DispatchingAndroidInjector looks up the AndroidInjector.Factory for your activity’s class (which is YourActivitySubcomponent.Builder), creates the AndroidInjector (which is YourActivitySubcomponent), and passes your activity to inject(YourActivity).

AndroidInjection.inject()Application中獲取一個DispatchingAndroidInjector<Activity>而且傳遞你的activityinject(this)DispatchingAndroidInjector爲您的Activity類(它是YourActivitySubcomponent.Builder)查找AndroidInjector.Factory,建立AndroidInjector(它是YourActivitySubcomponent),並將您的Activity傳遞給inject(YourActivity)

注入Fragment對象

Injecting a Fragment is just as simple as injecting an Activity. Define your subcomponent in the same way, replacing Activity type parameters with Fragment, @ActivityKey with @FragmentKey, and HasActivityInjector with HasFragmentInjector.

注入一個Fragment像注入一個Activity同樣簡單。以相同的方式定義你的subcomponent,使用Fragment替換Activity@FragmentKey替換@ActivityKey,HasFragmentInjector替換HasActivityInjector

Instead of injecting in onCreate() as is done for Activity types, inject Fragments to in onAttach().

不像在Activity類型中那樣在onCreate()中注入,而是在onAttach()中注入Fragment

Unlike the modules defined for Activitys, you have a choice of where to install modules for Fragments. You can make your Fragment component a subcomponent of another Fragment component, an Activity component, or the Application component — it all depends on which other bindings your Fragment requires. After deciding on the component location, make the corresponding type implement HasFragmentInjector. For example, if your Fragment needs bindings from YourActivitySubcomponent, your code will look something like this:

與爲Activity定義的模塊不一樣,您能夠選擇在哪裏爲Fragments安裝模塊。你可讓你的Fragment組件成爲另外一個Fragment子組件,Activity組件或Application組件的一個子組件 - 這一切都取決於你的Fragment須要的其餘綁定。肯定組件位置後,使相應的類型實現HasFragmentInjector。例如,若是您的Fragment須要來自YourActivitySubcomponent的綁定,那麼您的代碼將以下所示:

public class YourActivity extends Activity
    implements HasFragmentInjector {
  @Inject DispatchingAndroidInjector<Fragment> fragmentInjector;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
    // ...
  }

  @Override
  public AndroidInjector<Fragment> fragmentInjector() {
    return fragmentInjector;
  }
}

public class YourFragment extends Fragment {
  @Inject SomeDependency someDep;

  @Override
  public void onAttach(Activity activity) {
    AndroidInjection.inject(this);
    super.onAttach(activity);
    // ...
  }
}

@Subcomponent(modules = ...)
public interface YourFragmentSubcomponent extends AndroidInjector<YourFragment> {
  @Subcomponent.Builder
  public abstract class Builder extends AndroidInjector.Builder<YourFragment> {}
}

@Module(subcomponents = YourFragmentSubcomponent.class)
abstract class YourFragmentModule {
  @Binds
  @IntoMap
  @FragmentKey(YourFragment.class)
  abstract AndroidInjector.Factory<? extends Fragment>
      bindYourFragmentInjectorFactory(YourFragmentSubcomponent.Builder builder);
}

@Subcomponent(modules = { YourFragmentModule.class, ... }
public interface YourActivityOrYourApplicationComponent { ... }

基本框架類型

Because DispatchingAndroidInjector looks up the appropriate AndroidInjector.Factory by the class at runtime, a base class can implement HasActivityInjector/HasFragmentInjector/etc as well as call AndroidInjection.inject(). All each subclass needs to do is bind a corresponding @Subcomponent. Dagger provides a few base types that do this, such as DaggerActivity and DaggerFragment, if you don’t have a complicated class hierarchy. Dagger also provides a DaggerApplication for the same purpose — all you need to do is to extend it and override the applicationInjector() method to return the component that should inject the Application.

由於DispatchingAndroidInjector在運行時按類查找適當的AndroidInjector.Factory,因此基類能夠實現HasActivityInjectorHasFragmentInjectoretc等等以及調用AndroidInjection.inject()。每一個子類都須要作的就是綁定一個對應的@Subcomponent。若是您沒有複雜的類層次結構,Dagger會提供一些基本類型,例如DaggerActivityDaggerFragment。Dagger還爲一樣的目的提供了一個DaggerApplication你須要作的就是擴展它並覆蓋applicationInjector()方法來返回應該注入應用程序的組件。

如下類型也包括在內:

  • DaggerService和DaggerIntentService
  • DaggerBroadcastReceiver
  • DaggerContentProvider

Note: DaggerBroadcastReceiver should only be used when the BroadcastReceiver is registered in the AndroidManifest.xml. When the BroadcastReceiver is created in your own code, prefer constructor injection instead.

注意:DaggerBroadcastReceiver只能在AndroidManifest.xml中註冊BroadcastReceiver時使用。在您本身的代碼中建立BroadcastReceiver時,請改成使用構造函數注入。

支持庫

For users of the Android support library, parallel types exist in the dagger.android.support package. Note that while support Fragment users have to bind AndroidInjector.Factory<? extends android.support.v4.app.Fragment>, AppCompat users should continue to implement AndroidInjector.Factory<? extends Activity> and not <? extends AppCompatActivity> (or FragmentActivity).

對於Android支持庫的用戶,dagger.android.support包中存在並行類型。請注意,儘管支持Fragment的用戶必須綁定AndroidInjector.Factory <?extends android.support.v4.app.Fragment>AppCompat用戶應該繼續實現AndroidInjector.Factory <?extends Activity>而不是<?extends AppCompatActivity>(或FragmentActivity)。

如何獲取它

將如下內容添加到您的build.gradle中:

dependencies {
  compile 'com.google.dagger:dagger-android:2.x'
  compile 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries
  annotationProcessor 'com.google.dagger:dagger-android-processor:2.x'
}

什麼時候注入

Constructor injection is preferred whenever possible because javac will ensure that no field is referenced before it has been set, which helps avoid NullPointerExceptions. When members injection is required (as discussed above), prefer to inject as early as possible. For this reason, DaggerActivity calls AndroidInjection.inject() immediately in onCreate(), before calling super.onCreate(), and DaggerFragment does the same in onAttach(), which also prevents inconsistencies if the Fragment is reattached.

只要有可能,構造函數注入是首選,由於javac將確保沒有字段在被設置以前被引用,這有助於避免NullPointerException。 當須要成員注射(如上所述)時,傾向於儘早注射。 出於這個緣由,DaggerActivity在調用super.onCreate()以前當即在onCreate()中調用AndroidInjection.inject(),而且DaggerFragment在onAttach()中也是這樣作的,這也能夠防止在從新鏈接片斷時出現不一致。

It is crucial to call AndroidInjection.inject() before super.onCreate() in an Activity, since the call to super attaches Fragments from the previous activity instance during configuration change, which in turn injects the Fragments. In order for the Fragment injection to succeed, the Activity must already be injected. For users of ErrorProne, it is a compiler error to call AndroidInjection.inject() after super.onCreate().

在Activity中的super.onCreate()以前調用AndroidInjection.inject()是很是重要的,由於超級調用在配置更改期間將前一個活動實例的碎片鏈接到Fragments,而這又會致使碎片。 爲了使片斷注入成功,該活動必須已經被注入。 對於ErrorProne的用戶,在super.onCreate()以後調用AndroidInjection.inject()是一個編譯器錯誤。

常見問題

AndroidInjector.Factory is intended to be a stateless interface so that implementors don’t have to worry about managing state related to the object which will be injected. When DispatchingAndroidInjector requests a AndroidInjector.Factory, it does so through a Provider so that it doesn’t explicitly retain any instances of the factory. Because the AndroidInjector.Builder implementation that is generated by Dagger does retain an instance of the Activity/Fragment/etc that is being injected, it is a compile-time error to apply a scope to the methods which provide them. If you are positive that your AndroidInjector.Factory does not retain an instance to the injected object, you may suppress this error by applying @SuppressWarnings("dagger.android.ScopedInjectoryFactory") to your module method.

AndroidInjector.Factory旨在成爲無狀態接口,以便實現者沒必要擔憂管理與將被注入的對象相關的狀態。 當DispatchingAndroidInjector請求一個AndroidInjector.Factory時,它經過一個Provider來這樣作,以便它不明確地保留工廠的任何實例。 因爲由Dagger生成的AndroidInjector.Builder實現確實保留了正在被注入的Activity / Fragment /等的實例,所以將範圍應用於提供它們的方法時發生編譯時錯誤。 若是你確定你的AndroidInjector.Factory沒有爲注入對象保留一個實例,你能夠經過在模塊方法中應用@SuppressWarnings(「dagger.android.ScopedInjectoryFactory」)來消除這個錯誤。

有用連接

相關文章
相關標籤/搜索