原文:https://google.github.io/dagger/androidjava
[toc]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 } }
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.Builder
。ide
@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>
而且傳遞你的activity
到inject(this)
。DispatchingAndroidInjector
爲您的Activity類(它是YourActivitySubcomponent.Builder)查找AndroidInjector.Factory
,建立AndroidInjector(它是YourActivitySubcomponent)
,並將您的Activity傳遞給inject(YourActivity)
。
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
,因此基類能夠實現HasActivityInjector
、HasFragmentInjectoretc
等等以及調用AndroidInjection.inject()
。每一個子類都須要作的就是綁定一個對應的@Subcomponent
。若是您沒有複雜的類層次結構,Dagger
會提供一些基本類型,例如DaggerActivity
和DaggerFragment
。Dagger還爲一樣的目的提供了一個DaggerApplication你須要作的就是擴展它並覆蓋applicationInjector()方法來返回應該注入應用程序的組件。
如下類型也包括在內:
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」)來消除這個錯誤。