1. 程式人生 > >Dagger: dependency injection on Android (Part 2)

Dagger: dependency injection on Android (Part 2)

If you read first post about dependency injection, you will probably be looking for some real code. There are some beautiful examples about coffee makers at Dagger page, and an awesome model project by Jake Wharton for more experienced users. But we need something easier and coffee is not our main business model, so this article will provide an example where we are injecting some simple components to let us understand the basics

.

Include Dagger into your project

There are two libraries that must be added if you want to use Dagger:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.squareup.dagger:dagger:1.2.+'
    provided 'com.squareup.dagger:dagger-compiler:1.2.+'
}

First one is Dagger library

. Second library is the dagger compiler. It will create required classes in order to be able to inject dependencies. That’s the way it can avoid most reflection, by creating precompiled classes. As we only need it to compile the project, and won’t be used by application, we mark it as provided so that it isn’t included in final apk.

Creating your first module

Modules will be your daily job with dagger, so you need to feel comfortable with them. Modules are classes that provide instances of the objects we will need to inject. They are defined by annotating the class with @Module. There are some extra parameters that may be configured, but I’ll explain when we use them.

Create a class called AppModule, that will provide, for example, the Application Context. It’s usually interesting to have an easy access to it. I created App, which extends from Application, and added to the manifest.

@Module(
        injects = {
                App.class
        }
)
public class AppModule {

    private App app;

    public AppModule(App app) {
        this.app = app;
    }

    @Provides @Singleton public Context provideApplicationContext() {
        return app;
    }
}

What is new here?

@Module : identify this class as a Dagger module.
injects : Classes where this module is going to inject any of its dependencies. We need to specify those classes that are directly injected into object graph. This will be covered soon.
@Provides: Identify method as an injection provider. The name of the method doesn’t matter, it only relies on what class type is provided.
@Singleton : if it’s present, the method will return always the same instance of the object, which is far better than regular singletons. If not, everytime this type is injected, we’ll get a new instance. In this case, as we are not creating a new instance, but returning an existing one, it would be the same if we don’t annotate as singleton, but it explains better what the provider is doing. Application instance is unique.

Want to learn Kotlin?

Check my free guide to create your first project in 15 minutes!

Why regular singletons are evil

Singletons are probably the most dangerous dependencies a project can have. First of all, because due to the fact that we are not creating an instance, it’s really hard to know where we are using it, so these are “hidden dependencies”. On the other way, we have no way to mock them for testing or to substitute it with another module, so our code becomes hard to maintain, to test and to evolve. Injected singletons, on the other way, have the benefits of a singleton (a unique instance) and, as we can create new instances at any moment, it’s easier to mock and to substitute with another piece of code, by subclassing or making them implement a common interface.

We will be creating another module in a new package called domain. It’s quite useful to have (at least) a module in every architecture layer. This module will provide an analytics manager, that will throw an event when the app starts, only by showing a Toast. In a real project, this manager could call any analytics service such as Google Analytics.

@Module(
        complete = false,
        library = true
)
public class DomainModule {

    @Provides @Singleton public AnalyticsManager provideAnalyticsManager(Application app){
        return new AnalyticsManager(app);
    }

}

By identifying this module as not complete, we say that some of the dependencies in this module need to be provided by another module. That’s the case of Application, which comes from AppModule. When we require this AnalyticsManager from a dependency injection, dagger will use this method, and will detect that it needs another dependency, Application, which will be requested to the object graph (almost there!). We also need to specify this module as a library, because dagger compiler will detect that AnalyticsManager is not been used by itself or its injected classes. It’s acting as a library module for AppModule.

We will specify that AppModule will include this one, so back to previous class:

@Module(
        injects = {
                App.class
        },
        includes = {
                DomainModule.class
        }
)
public class AppModule {
...
}

includes attribute is there for that purpose.

Creating the Object Graph

The object graph is the place where all these dependencies live. The object graph contains the created instances and is able to inject them to the objects we add to it.

In previous examples (AnalyticsManager) we have seen the “classic” dependency injection, where injections are passed via constructor. But we have some classes in Android (Application, Activity) where we don’t have control over constructor, so we simply need another way to inject its dependencies.

The combination of ObjectGraph creation and this direct injection is represented in App class. The main object graph is created in the Application class and it is injected in order to get its dependencies.

public class App extends Application {

    private ObjectGraph objectGraph;
    @Inject AnalyticsManager analyticsManager;

    @Override public void onCreate() {
        super.onCreate();
        objectGraph = ObjectGraph.create(getModules().toArray());
        objectGraph.inject(this);
        analyticsManager.registerAppEnter();
    }

    private List<Object> getModules() {
        return Arrays.<Object>asList(new AppModule(this));
    }
}

We specify dependencies by annotating them with @Inject. These fields must be public or default scoped, so that dagger can assign them. We create an array with our modules (we have only one, DomainModule is included in AppModule), and create an ObjectGraph with it. After it, we inject App instance manually. After that call, dependencies are injected, so we can call AnalyticsManager method.

Conclusion

Now you know the basics about Dagger. ObjectGraph and Modules are the most interesting components that must be mastered to use Dagger efficiently. There are some more tools such as lazy injections or provider injections that are explained at Dagger site, but I don’t recommend dive into them until you are fluent using what we saw here.

Next (and probably last) post about Dagger will be focused on scoped object graphs. It basically consists of creating new object graphs that lives only where its creator does. It’s common to create scoped graphs for activities.

I’m in love with Kotlin. I’ve been learning about it for a couple of years, applying it to Android and digesting all this knowledge so that you can learn it with no effort.

Shares

Like this:

Like Loading...

相關推薦

Dagger: dependency injection on Android (Part 2)

If you read first post about dependency injection, you will probably be looking for some real code. There are some beautiful examples about coffee ma

Dependency injection on Android: Dagger (Part 1)

On this new series I will explain what dependency injection is, what its main purpose is and how to use it on an Android project by using Dagger, the

Experimenting with TensorFlow on Android Part 1

Let us start by installing TensorFlow, I tried a couple methods of installing it and ended up using dockerdocker run -it gcr.io/tensorflow/tensorflow:lates

How to use Dagger 2 on Android with Kotlin (KAD 20)

Virtually everyone who wants to create code on Android in a decoupled and easy-to-test way, resorts to Dagger sooner or later. Although there is some

A tutorial on binary descriptors – part 2 – The BRIEF descriptor(轉)

A tutorial on binary descriptors – part 2 – The BRIEF descriptor Following the previous posts that provided both an introduction to patch

Marginally Interesting: Command Line Interactive Machine Learning on the JVM. Part 2: JRuby and Scala

Tweet This is Part 2 of a series. Previous post is here. In order to b

Our Findings on Localization Accuracy of Vehicle Detection Models (Part 2)

Editor’s note: This is the second in a series of three posts outlining the findings of research our in-house computer vision team conducted regarding the a

Android Architecture Patterns Part 2: Model

Android Architecture Patterns Part 2:Model-View-PresenterIt’s about time we developers start thinking about how we can apply good architecture patterns in

arcgis-android-100.2 bug:Can only call this method on a loaded table

剛剛接觸arcgis android,在儲存地圖要素的時候出現bug,導致應用閃退。異常日誌: this = {[email protected]} t = {[email protected]} "Thread[main,5,main]" e = {

[Android Exercise]Fragment新聞客戶端例子拆解PART.2—帶你記憶Fragment的使用

上一部分已經完成了 將標題和詳情頁佈局的繫結。現在進入到下一階段。 ********************************************************* 繼續看看我們的圖示: 從圖上看,我們已經完成了左右兩側的佈局繫結Fragment了,

<Android基礎>(三) Activity Part 2

不可 不可靠 spa 進行 ima 應用程序 屬性 second android 1.活動生命周期 1)返回棧 2)活動狀態 3)活動的生存期 2.活動的啟動模式 1)standard 2)singleTop 3)singleTask 4)singleIns

<Android基礎>(五) UI開發 Part 2

每一個 itemclick new imageview str his () 取出 out ListView 1)ListView的簡單用法 2)定制ListView界面 3)提升ListView的運行效率 4)ListView的點擊事件 3.5 ListV

<Android基礎>(四) Fragment Part 2

提交 horizon 回調方法 銷毀 inf 分享 臨界點 使用 不可 4.3 Fragment的生命周期 4.3.1 Fragment的狀態和回調 1.運行狀態 當一個Fragment是可見的,並且它關聯的活動正處於運行狀態是,該Fragment也處於運行狀態 2

Lesson 2 Building your first web page: Part 2

examples pear reads port example eth span contain animation Tag Diagram You may have noticed that HTML tags come in pairs; HTML has bot

Android——4.2 - 3G移植之路之 reference-ril .pppd 撥號上網 (三)

而且 init.rc nal null ann 源代碼分析 suggest cdma 初始化 Android的RIL機制中的 reference-ril.c 即為廠商提供的驅動接口。這個驅動源代碼各個廠商都是有提供的,網上也有下載。我如今用的就是huawe

Android studio 2.2新特性介紹,ConstraintLayout完全解析

穩定 iss 項目 ide 了解 需要 應用 let 左右 轉載郭霖大神的文章,轉載請註明出處:http://blog.csdn.net/guolin_blog/article/details/53122387 我正常寫隨筆,都是看了別人的文章,自己使用,把自己的體驗心得,

泛泰A820L (高通MSM8660 cpu) 3.4內核的CM10.1(Android 4.2.2) 測試版第二版

卸載 反饋 span lin clas wan 系統分區 漢化 sof 歡迎關註泛泰非盈利專業第三方開發團隊 VegaDevTeam (本team 由 syhost suky zhaochengw(z大) xuefy(大星星) tenfar(R大師) loogeo

Android Studio2.2.3 使用教程-入門篇

android最近學習下Android APK的內容,保持學習的一些文章:Android Studio 2.2.3工具使用:http://blog.csdn.net/qq_16313365/article/details/52537397待續本文出自 “專註嵌入式多媒體技術” 博客,請務必保留此出處http:

Android Studio2.2.3 通過JNI引用ffmpeg庫小結

android studio;ffmpeg;ndk;jni修改步驟:首先通過NDK14編譯出libffmpeg.so ,將include目錄取出通過AS建立基於jni的工程項目,將include目錄放到cpp下;創建jniLibs/armeabi目錄,將libffmpeg.so放到裏邊 3.配置CMak

Android Studio 2.0 正式版公布啦 (首次中文翻譯)

2.0 play user attribute ast 調試 iou osi watermark Android Studio 2.0 公布了,添加了一些新特性: 1. 更加完好的 Instant Run 2. 更快的 A