Migrate projects developed based on Dagger-1 to Dagger-2, dagger-1dagger-2

Source: Internet
Author: User
Tags sonatype

Migrate projects developed based on Dagger-1 to Dagger-2, dagger-1dagger-2

  • Original article: Dagger 1 to 2 migration process
  • Author: Miroslaw Stanek
  • Source: Development Technology Front Line www.devtf.cn
  • Translator: chaossss
  • Proofreader: tiiime
  • Status: complete

I believe that every Android developer has heard of the dependency injection framework. In fact, almost all Android official meetings have discussed software design patterns. Although I am a brain fan of dependency injection, I have to admit that some people do not like dependency injection. The main reasons are as follows:

  • The dependency injection framework is slow.-Well, in the era of RoboGuice, the entire dependency chart will be created and verified at runtime, so that the dependency injection framework does have such problems. But now, Dagger has changed everything. In the Dagger 1 framework, a lot of work (Chart verification) is completed during compilation, and the object creation does not need to be completed through the reflection mechanism (it is worth mentioning that: recently released Roboguice 3 also completed a lot of work during compilation ). Although the Dagger 1 framework is less efficient than the code written by engineers, it is acceptable in most apps.

  • The dependency injection framework requires a large number of templates.-It can be said that it is right or not. Indeed, we need to add additional code for the classes and injections that provide dependencies, but because we have done this, so that we don't have to process them through the constructor every time we need them. I do not deny that the dependency injection framework affects the performance of small apps. However, as the internal structure of the App becomes more complex, the advantages of dependency injection become more and more obvious.

  • Other disadvantages are poor traceability, poor readability of generated code, etc ......

But I have already said: I am the brainchild of the dependency injection framework. The shortcomings I just mentioned won't let me stop using it in the project. Until recently I used Dagger 1, there was no problem, but when we decided to completely rewrite Azimo (my new project) and run it on the dependency injection framework, some Problems in Dagger 1 gradually become apparent. What are these problems? Let me hear you again.

However, the good news is that although Dagger 2 has not yet released the official version, Dagger 2 already has a stable and complete feature version.

Dagger 2

To be honest, I am not very familiar with the Implementation Details of Dagger 2, I just looked at some instructions on The official website, such as Dagger 2 website and The Future of Dependency Injection with Dagger 2.

After all, the most important thing for me is that Dagger 2 automatically solves a large number of long-time tasks in Dagger 1.

Use Proguard for projects

I have to admit that the number of Azimo methods has exceeded 65536 (Android Dex's 64 k limit ). At the beginning of Azimo development, we used MultiDex solution, but with the iteration of the application, we found that MultiDex solution has some defects, so we must consider using Proguard. Why do we have to make such a decision?

Note: ProGuard is a free tool for compressing, optimizing, and confusing Java bytecode files. It can delete useless classes, fields, methods, and attributes. You can delete unused comments to maximize the optimization of bytecode files. It can also use a brief meaningless name to rename existing classes, fields, methods, and attributes. It is often used for Android development to confuse final projects and increase the difficulty of Project decompilation.

Only MultiDex called in the onCreate () method of the MultiDexApplication class. install (this) takes about 4.4 ms to use the Android 4000 Nexus 7 device (Lollipop's support for MultDex is kernel-based, therefore, only 1 ms is required for the same device ). In addition, the building time of the application is dramatic without downgrading (even if we modify only one line of code, it will take about two minutes for each Gradel assembleDebug ). Why does it take so long? To put it simply, each time we modify the code to decide which code is put into the first. dex file and which code can be moved to other. dex files, the MultiDex plug-in needs to scan the resource file.

So we decided to use Proguard, And then it exploded ...... In the Proguard specification, there is no simple method to process the automatically generated code of Dagger. So we have to use the @ Keep annotation of Squad leader to simplify this problem, but we still need to spend some time updating the Code and marking this specification in the annotation.

Dagger 2 response: Proguard does not have the single principle required by Dagger 2. Everything happens naturally. Because Dagger 2 generates completely traceable code and does not require reflection-this is a big bang for Proguard friendliness.

Other items

There are still some less important (but useful) things that make us convinced that the code developed based on the Dagger 1 framework is transferred to Dagger 2:

  • It is very difficult for Dagger 1 to automatically generate code. Although Dagger 1 is trustworthy, it is also good for us to understand what Dagger 1 leaves at the bottom layer. Because the code is not completely traceable, it means that we cannot use functions similar to "find usages" in IDE.

Dagger 2 generates an entire stack that is almost the same as the dependency injection Code implemented by programmers. Make the code completely traceable, so that we can better understand the code running mechanism.

  • The scalability of Dagger 2 may be slightly reduced, but the APIs of Dagger 2 are much clearer and easier to use than that of Dagger 1. Our team is still developing. When we rewrite an application, it is important to understand the entire application architecture process as quickly as possible and to minimize bugs. Fortunately, the learning curve of Dagger 2 is not steep, which saves us learning costs.

  • The build time of the dependency graph. Maybe it is not a big problem for us now-because it takes about 80 ms to construct an application dependency graph on Nexus 7 (Android 4.4. However, if Dagger 2 is used, it takes only 40 ms to build the dependency graph.

Migrate a project developed based on Dagger 1 to Dagger 2

Antonio Leiva wrote a series of blog posts (post 1, post 2, post 3) about how to use dependency injection in Android MVP-based projects a few months ago ). I think this project is quite good, so I downloaded it and updated its dependency injection framework to Dagger 2.

Dependency Graph

To better understand how Dagger 1 runs in an example, I used the DaggerExample project to create a dependency graph:

Now let's look at the dependency graph created using Dagger 2 in the same project:

Can you see the similarities?

The most notable difference between Dagger 1 and Dagger 2 is Compontents. Simply put, they enumerate all types that the caller may request. However, the component interface only declares that it provides some things for the caller, and these things are provided by the Module, so the Module is still responsible for creating objects. A component is only a public API that depends on graphs.

Create dependency during migration

First, we need to update the build. gradle file to add new dependencies. When I write this blog post, only one snapshot version is available. This is why we must add the Sonatype snapshot Library:

Build. gradle:

    buildscript {        repositories {            mavenCentral()            maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }        }        dependencies {            classpath 'com.android.tools.build:gradle:1.1.3'            classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'        }    }    allprojects {        repositories {            mavenCentral()            maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }        }    }

The Android-ADT plug-in works with the annotation processor, and allows you to configure the compilation time only when the annotation processor is dependent without adding artifact to the final APK. Of course, it also generates the corresponding original path for the automatically generated code, which is visible and traceable in Android Studio.

Dagger's app/build. gradle file and Android-ADT information should be roughly as follows:

    apply plugin: 'com.android.application'    apply plugin: 'com.neenbedankt.android-apt'    android {        compileSdkVersion 22        buildToolsVersion "22.0.1"        defaultConfig {            minSdkVersion 14            targetSdkVersion 22            versionCode 1            versionName "1.0"        }        compileOptions {            sourceCompatibility JavaVersion.VERSION_1_7            targetCompatibility JavaVersion.VERSION_1_7        }        buildTypes {            release {                minifyEnabled false                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'            }        }    }    dependencies {        compile fileTree(dir: 'libs', include: ['*.jar'])        compile 'com.google.dagger:dagger:2.0-SNAPSHOT'        apt 'com.google.dagger:dagger-compiler:2.0-SNAPSHOT'        provided 'org.glassfish:javax.annotation:10.0-b28'    }
Modules

The next step is the simplest step in the migration process. Modules will be as simple as possible. They only need to add @ Module (no additional parameters required) and @ Provides annotations to the objects to be provided.

This is the AppModule class:

Dagger 1:

    @Module(            injects = {                    App.class            },            includes = {                    DomainModule.class,                    InteractorsModule.class            }    )    public class AppModule {        private App app;        public AppModule(App app) {            this.app = app;        }        @Provides public Application provideApplication() {            return app;        }    }

Dagger 2:

    @Module    public class AppModule {        private App app;        public AppModule(App app) {            this.app = app;        }        @Provides public Application provideApplication() {            return app;        }    }

What are the differences between the two? The difference is that injection parameters are moved to components, just like using include. All Module parameters should be expired/removed as soon as possible.

Components

As I just said, some new features are added to Dagger 2. Simply put, some public APIs of the dependency graph are called. Let's take a look at the dependency diagram of Dagger 2. This is the implementation of every @ Componentclass:

AppComponent:

    @Singleton    @Component(            modules = {                    AppModule.class,                    DomainModule.class,                    InteractorsModule.class            }    )    public interface AppComponent {        void inject(App app);        AnalyticsManager getAnalyticsManager();        LoginInteractor getLoginInteractor();        FindItemsInteractor getFindItemsInteractor();    }

LoginComponent:

    @ActivityScope    @Component(            dependencies = AppComponent.class,            modules = LoginModule.class    )    public interface LoginComponent {        void inject(LoginActivity activity);        LoginPresenter getLoginPresenter();    }

MainComponent:

    @ActivityScope    @Component(            dependencies = AppComponent.class,            modules = MainModule.class    )    public interface MainComponent {        void inject(MainActivity activity);        MainPresenter getLoginPresenter();    }

You can see that I used the @ AcivityScope annotation. Simply put, it is a substitute for @ Singleton annotation in a local subgraph. In Dagger 1, assume that we have a LoginPresenter class singleton object, although this object is indeed a Singleton, but to some extent, it is always like a local Singleton-because it only exists in the graph scope (in the sample code, the Singleton is in onDestory () method ).

@ ActivityScope is used just for semantic clarity and it's defined in our code:

@ ActivtiyScope is only used in environments with clear context. Its definition in code is as follows:

    @Scope    @Retention(RetentionPolicy.RUNTIME)    public @interface ActivityScope {    }
Object Graph

Dagger 2 no longer contains object graphs, because object graphs are replaced by components. Specifically, the Dagger 2 Framework will automatically generate code prefixed with DaggerComponent. This means that the generated code must be processed now (but only here ).

We must remember that the DaggerComponent _ class is generated only when all code is valid, so you will not see it before resolving all errors.

What does it look like?

    public class App extends Application {        private AppComponent component;        @Inject        AnalyticsManager analyticsManager;        @Override        public void onCreate() {            super.onCreate();            setupGraph();            analyticsManager.registerAppEnter();        }        private void setupGraph() {            component = Dagger_AppComponent.builder()                    .appModule(new AppModule(this))                    .build();            component.inject(this);        }        public AppComponent component() {            return component;        }        public static App get(Context context) {            return (App) context.getApplicationContext();        }    }

Our graph will be generated through 16-18 lines of code, replacing the ObjectGraph. create (getModules () Code of Dagger 1.

Line 3 of code injects the App object into the way (and all @ Inject annotations in the class are credible at this time)

This is an example of this map (MainActivity:

    protected void setupComponent(AppComponent appComponent) {        Dagger_MainComponent.builder()                .appComponent(appComponent)                .mainModule(new MainModule(this))                .build()                .inject(this);    }

MainComponent depends on AppComponent, so that we must provide this object accurately. If the Module does not have a default constructor, you must provide (like MainModule ).

The migration is completed here. Submitting a complete pull request for the migration process prevents us from missing something. Everyone must remember: This article does not explain more complex solutions and all the features and functions of Dagger 2. Below are some links that help you better understand the running mechanism of Dagger 2 and the dependency injection framework:

The Future of Dependency Injection with Dagger 2
Dagger 2 doc by Gregory Kick
Dagger 2 official website

So far, thank you for your patience in reading this article. I hope to explore the technical details of Dagger 2 more deeply. I believe you will soon see my new blog! ��

Source code

Github has the source code of the entire project.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.