This article is part of Android Architecture Components Learning Notes
The document code is Kotlin, but the code generated by the system is still Java.
For ease of understanding, I've broken down the official examples step by step.
My level is limited. If there is something wrong with me, please don't hesitate to give me advice.
The last article analyzed Dagger's basic usage, which is still weak and explosive. How to apply it in a project? This article explores the things that Activity object injection does.
Article directory
Application
Explain the GithubApp class in Android Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" …… <application android:name=".GithubApp" ……
The android:name attribute is used to set which application all activities belong to
The GithubApp class has global members, and AppInjector.init(this) in the code executes before activity.
AppInjector.init(this) is also the beginning of all injections.
The first step, as in the previous article, is to look at GithubApp, the injector:
//HasActivity Injector needs to be implemented class GithubApp : Application(), HasActivityInjector { @Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity> override fun onCreate() { …… //Rewritten onCreate(), this sentence is the focus AppInjector.init(this) } override fun activityInjector() = dispatchingAndroidInjector }
Step 2, Component:
@Component(modules = [AndroidInjectionModule::class]) interface AppComponent { //Builder is declared here @Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder fun build(): AppComponent } fun inject(githubApp: GithubApp) }
After the build, GithubApp_Members Injector and DaggerAppComponent come out
GithubApp is Application, so HasActivity Injector is implemented here, enabling Activity injection.
Here's another important class: Dispatching Android Injector. I will elaborate on that later.
AppInjector (1)
object AppInjector { fun init(githubApp: GithubApp) { //First sentence: Complete the injection of githubApp DaggerAppComponent.builder().application(githubApp).build().inject(githubApp) //Second sentence: override on Activity Created, add handleActivity githubApp.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {handleActivity(activity)} }) } private fun handleActivity(activity: Activity) {...}//To look good, put it away here first. }
First look at the first sentence of AppInjector.init:
DaggerAppComponent.builder()//Builder is obtained by this static method .application(githubApp)//Builder with githubApp .build()//Get the DaggerAppComponent object .inject(githubApp)
The DaggerAppComponent methods used here are:
public final class DaggerAppComponent implements AppComponent { private DaggerAppComponent(Builder builder) {} public static AppComponent.Builder builder() { return new Builder();} private DispatchingAndroidInjector<Activity> getDispatchingAndroidInjectorOfActivity() { //Here a Dispatching Android Injector for an empty Map is returned return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector( Collections.<~> emptyMap()); } //Inject Dispatching Android Injector into githubApp. dispatching Android Injector @Override public void inject(GithubApp githubApp) {injectGithubApp(githubApp);} private GithubApp injectGithubApp(GithubApp instance) { GithubApp_MembersInjector.injectDispatchingAndroidInjector(instance, getDispatchingAndroidInjectorOfActivity()); return instance; } //The AppComponent.Builder implemented here is what was previously written in Component. //Rewritten application s, build s are our own definitions private static final class Builder implements AppComponent.Builder { private Application application; @Override public AppComponent build() {return new DaggerAppComponent(this);} @Override public Builder application(Application application) { this.application = Preconditions.checkNotNull(application); return this; } } }
The code is a bit complicated, so here are only two things to remember:
1. The first sentence of AppInjector.init completes githubApp. dispatching Android Injector injection
2. Through GithubApp_Members Injector. (The code is not difficult, I talked about it in the last part.)
Here comes the Dispatching Android Injector. Before continuing with the second sentence of AppInjector.init, take a look at it first.
DispatchingAndroidInjector
First look at Dispatching Android Injector
/* * Examples of core Android types (Activity, Fragment... ) Perform injection, which is implemented by the Android framework rather than Dagger * By implementing the Android Injector method, the Android Injector. Factory injected into the class is put into the Map. * By calling Object#getClass() on the instance, you can get its Android Injector. Factory. */ @Beta public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> { /*Injecting Map type of Factory, the following code omits Map type for convenience *In this Map, K is Class and V is Android Injector.Factory. */ private final Map<Class<? extends T>, Provider<AndroidInjector.Factory<? extends T>>> injectorFactories; @Inject DispatchingAndroidInjector(Map<~> injectorFactories) { this.injectorFactories = injectorFactories; } //Attempt to inject on {instance} to return success @CanIgnoreReturnValue //Can you get factory in Map? public boolean maybeInject(T instance) { Provider<AndroidInjector.Factory<? extends T>> factoryProvider = injectorFactories.get(instance.getClass()); if (factoryProvider == null) { return false; } @SuppressWarnings("unchecked") AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get(); //Post-transition Implementation Injection try { AndroidInjector<T> injector =checkNotNull(factory.create(instance),, ); injector.inject(instance); return true; } catch (ClassCastException e) {…} } //Injection of {instance} Executive Members @Override public void inject(T instance) { boolean wasInjected = maybeInject(instance); } }
By looking at the core code of Dispatching Android Injector, it is mainly through:
Android Injector. create () and Android Injector. inject () complete the injection.
It's a bit messy here, remember Dispatching Android Injector and AppInjector will be clear later.
Activity injection
Let's complete MainActivity joining Dispatching Android Injector (I'm going to do the sample code step by step)
MainActivity is like this:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) } }
Or the general rule, Module:
@Suppress("unused") @Module abstract class MainActivityModule { @ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity }
OK, build a look at Dagger App Component
public final class DaggerAppComponent implements AppComponent { //Provider of MainActivity private Provider<MainActivityModule_ContributeMainActivity.MainActivitySubcomponent.Builder> mainActivitySubcomponentBuilderProvider; //Constructor to perform initialization private DaggerAppComponent(Builder builder) {initialize(builder);} private void initialize(final Builder builder) { //Initialize Provider for MainActivity this.mainActivitySubcomponentBuilderProvider = new Provider<MainActivityModule_ContributeMainActivity.MainActivitySubcomponent.Builder>() { @Override public MainActivityModule_ContributeMainActivity.MainActivitySubcomponent.Builder get() { return new MainActivitySubcomponentBuilder(); } }; } public static AppComponent.Builder builder() {return new Builder();} //Get Map with MainActivity private Map<~> getMapOfClassOfAndProviderOfFactoryOf() { return Collections.<~> singletonMap(MainActivity.class, (Provider) mainActivitySubcomponentBuilderProvider); } //Create and return Map's Dispatching Android Injector object with MainActivity private DispatchingAndroidInjector<Activity> getDispatchingAndroidInjectorOfActivity() { return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector( getMapOfClassOfAndProviderOfFactoryOf()); } //Execution injection @Override public void inject(GithubApp githubApp) {injectGithubApp(githubApp);} private GithubApp injectGithubApp(GithubApp instance) { GithubApp_MembersInjector.injectDispatchingAndroidInjector( instance, getDispatchingAndroidInjectorOfActivity()); return instance; } //The code here is omitted, which was analyzed earlier. private static final class Builder implements AppComponent.Builder {...} private final class MainActivitySubcomponentBuilder extends MainActivityModule_ContributeMainActivity.MainActivitySubcomponent.Builder { private MainActivity seedInstance; @Override//The override here is Android Injector. Builder. build () public MainActivityModule_ContributeMainActivity.MainActivitySubcomponent build() { if (seedInstance == null) { throw new IllegalStateException(MainActivity.class.getCanonicalName() + " must be set"); } return new MainActivitySubcomponentImpl(this); } @Override//Override here is Android Injector. Builder. seedInstance () public void seedInstance(MainActivity arg0) { this.seedInstance = Preconditions.checkNotNull(arg0); } } private final class MainActivitySubcomponentImpl implements MainActivityModule_ContributeMainActivity.MainActivitySubcomponent { private MainActivitySubcomponentImpl(MainActivitySubcomponentBuilder builder) {} @Override//Here is Android Injector. inject () public void inject(MainActivity arg0) {} } }
There's a lot of code. Simply put, MainActivity is injected through Dispatching Android Injector.
Add an Activity
We need to have an activity first. It's called Activity 2.
Add:
@Suppress("unused") @Module abstract class MainActivityModule { @ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity @ContributesAndroidInjector abstract fun contributeActivity2(): Activity2 }
After build ing, look at Dagger App Component
public final class DaggerAppComponent implements AppComponent { private Provider<MainActivityModule_ContributeMainActivity.MainActivitySubcomponent.Builder> mainActivitySubcomponentBuilderProvider; //More Activity 2 private Provider<MainActivityModule_ContributeActivity2.Activity2Subcomponent.Builder> activity2SubcomponentBuilderProvider; //That's it. Two are added to the Map. private Map<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>> getMapOfClassOfAndProviderOfFactoryOf() { return MapBuilder .<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>> newMapBuilder(2) .put(MainActivity.class, (Provider) mainActivitySubcomponentBuilderProvider) .put(Activity2.class, (Provider) activity2SubcomponentBuilderProvider) .build(); } //Here are also two sets. private void initialize(final Builder builder) { this.mainActivitySubcomponentBuilderProvider =... this.activity2SubcomponentBuilderProvider =... } private final class MainActivitySubcomponentBuilder extends MainActivityModule_ContributeMainActivity.MainActivitySubcomponent.Builder {...} private final class MainActivitySubcomponentImpl implements MainActivityModule_ContributeMainActivity.MainActivitySubcomponent {...} private final class Activity2SubcomponentBuilder extends MainActivityModule_ContributeActivity2.Activity2Subcomponent.Builder {...} private final class Activity2SubcomponentImpl implements MainActivityModule_ContributeActivity2.Activity2Subcomponent {...} }
It's double...
Sum up
- Actual projects inject Activity, just modify the Module. Simple don't want it.
- By looking at the source code, we can better understand the application of builder and factory mode, and understand the three implementation methods of Map.
- Why inject Activity? Continue to find the benefits of doing so.