原文連接:www.jianshu.com/p/2cd491f0d…java
是一個依賴注入框架,butterknife也是一個依賴注入框架。不過butterknife,最多叫奶油刀,Dagger2被叫作利器啊,他的主要做用,就是對象的管理,其目的是爲了下降程序耦合。android
下面我就手寫了git
public class A {
public void eat() {
System.out.print("吃飯了");
}
}
複製代碼
使用的時候咱們就要github
A a = new A();
a.eat();
複製代碼
若是如今改了,早A的構造方法中必須傳入B對象api
public class A {
private B b;
public A(B b) {
this.b = b;
}
public void eat() {
System.out.print("吃飯了");
}
}
複製代碼
那麼使用的時候bash
A a = new A(new B());
a.eat();
複製代碼
可能就有人說了,不就加一個對象麼,這裏只是我舉的一個很簡單的例子,看的感受很簡單,可是在實際開發中,若是如今改了一個這個構造方法。是否是意味着,整個項目中的都的改,一不當心, 就是BUG 啊架構
上來給你說,怎麼玩,確定懵逼,這裏我簡單說一下幾個概念,想有個認知,在往下看,會好不少,Dagger 是經過@Inject
使用具體的某個對象,這個對象呢,是由@Provides
註解提供,可是呢,這個@Provides
只能在固定的模塊中,也就是@Module
註解,咱們查找的時候,不是直接去找模塊,而是去找@Component
app
咱們反向推導,當咱們使用框架
@Inject
A a
複製代碼
想要獲取a對象的示例的時候,Dagger2 會先去找,當前Activity或者Fragment所鏈接的橋樑,例如上圖中,鏈接的只有一個橋樑,實際上能夠有多個,這個橋樑,會去尋找他所依賴的模塊,如圖中,依賴了模塊A,和模塊B,而後在模塊中,會去尋找@Providers
註解,去尋找A的實例化對象。ide
compile 'com.google.dagger:dagger:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
複製代碼
//第一步 添加@Module 註解
@Module
public class MainModule {
}
複製代碼
//第一步 添加@Module 註解
@Module
public class MainModule {
//第二步 使用Provider 註解 實例化對象
@Provides
A providerA() {
return new A();
}
}
複製代碼
//第一步 添加@Component
//第二步 添加module
@Component(modules = {MainModule.class})
public interface MainComponent {
//第三步 寫一個方法 綁定Activity /Fragment
void inject(MainActivity activity);
}
複製代碼
而後AS 會自動幫咱們生成一個
開頭都是以Dagger開始的
package com.allens.daggerdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.allens.daggerdemo.Bean.A;
import com.allens.daggerdemo.component.DaggerMainConponent;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
/***
* 第二步 使用Inject 註解,獲取到A 對象的實例
*/
@Inject
A a;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/***
* 第一步 添加依賴關係
*/
//第一種方式
DaggerMainConponent.create().inject(this);
//第二種方式
DaggerMainConponent.builder().build().inject(this);
/***
* 第三步 調用A 對象的方法
*/
a.eat();
}
}
複製代碼
確定有小夥伴說了,爲了拿到一個對象,這麼大個彎,太麻煩了。別急慢慢看,路要一步一步走嘛
怎麼說呢,就和最來時的意思同樣,
A a = new A(new B());
a.eat();
複製代碼
這種狀況,如何使用Dagger2呢 確定有小夥伴這麼想
@Provides
A providerA() {
return new A(new B());
}
複製代碼
直接 new 一個B ,這樣的使用方法,是不對的!!!!!!,不對的!!!!!!!,不對的!!!!!!!!!
正確的打開方式
這時候,咱們什麼都不用改,只須要在moudule中添加一個依賴就能夠了
@Module
public class MainModule {
/***
* 構造方法須要其餘參數時候
*
* @return
*/
@Provides
B providerB() {
return new B();
}
@Provides
A providerA(B b) {
return new A(b);
}
}
複製代碼
模塊與模塊之間的聯繫
@Module (includes = {BModule.class})// includes 引入)
public class AModule {
@Provides
A providerA() {
return new A();
}
}
複製代碼
這樣的話,Dagger會如今A moudule 中尋找對象,若是沒找到,會去找module B 中是否有被Inject
註解的對象,若是仍是沒有,那麼GG,拋出異常
@Component(modules = {AModule.class,BModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
複製代碼
@Component(modules = {MainModule.class}, dependencies = AppConponent.class)
public interface MainConponent {
void inject(MainActivity activity);
}
複製代碼
注意這裏有坑,一下會講解
至關於有個表示,雖然你們都是同一個對象,可是實例化對象不一樣就不如
A a1 = new A();
A a2 = new A();
// a1 a2 能同樣嘛
複製代碼
@Named
註解@Module
public class MainModule {
private MainActivity activity;
public MainModule(MainActivity activity) {
this.activity = activity;
}
@Named("dev")
@Provides
MainApi provideMainApiDev(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,"dev");
}
@Named("release")
@Provides
MainApi provideMainApiRelease(MainChildApi mainChildApi, String url) {
return new MainApi(mainChildApi, activity,"release");
}
}
複製代碼
public class MainActivity extends AppCompatActivity {
@Named("dev")
@Inject
MainApi apiDev;
@Named("release")
@Inject
MainApi apiRelease;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.mainChildModule(new MainChildModule())
.build()
.inject(this);
apiDev.eat();
apiRelease.eat();
Log.i("TAG","apiDev--->" + apiDev);
Log.i("TAG","apiRelease--->" + apiRelease);
}
}
複製代碼
07-14 01:46:01.170 2006-2006/? I/TAG: apiDev--->com.allen.rxjava.MainApi@477928f
07-14 01:46:01.170 2006-2006/? I/TAG: apiRelease--->com.allen.rxjava.MainApi@f2b291c
複製代碼
單例模式,是否是超級方便,你想然哪一個對象單例化,直接在他的Provider上添加@Singleton
就好了
例如
@Singleton
@Provides
A providerA(B b) {
return new A(b);
}
複製代碼
注意: 第一個坑!!! 若是 moudule所依賴的Comonent 中有被單例的對象,那麼Conponnent也必須是單例的
@Singleton
@Component(modules = {MainModule.class})
public interface MainConponent {
}
複製代碼
而後 在Activity中使用,直接打印a1 a2 的地址,
@Inject
A a2;
@Inject
A a1;
複製代碼
能夠看到Log
12-30 01:32:58.420 3987-3987/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
12-30 01:32:58.420 3987-3987/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
複製代碼
不相信的小夥伴能夠吧@Singleton
去掉試試
如今咱們完成了單例,而後作了一個事情,就是點擊某個按鈕,跳轉到一個新的Activiry,兩邊都引用一樣一個A 對象,打印A 的地址,
說一下,一個Conponent 能夠被對個Activity/Fragment 引用,如
@Singleton
@Component(modules = {MainModule.class})
public interface MainConponent {
void inject(MainActivity activity);
void inject(TestAct activity);
}
複製代碼
上面與兩個Activity, MainActivity 和 TestAct ,都引用相同的對象,答應地址看看
12-30 00:48:17.477 2788-2788/com.allens.daggerdemo E/TAG: A1---->com.allens.daggerdemo.Bean.A@11fa1ba
12-30 00:48:17.517 2788-2788/com.allens.daggerdemo E/TAG: A2---->com.allens.daggerdemo.Bean.A@4f81861
複製代碼
居然不一樣,說好的單例呢
注意: 第二個坑,單例對象只能在同一個Activity中有效。不一樣的Activity 持有的對象不一樣
那有人就要問了,沒什麼辦法麼,我就想全局只要一個實例化對象啊? 辦法確定是有的,
/**
* @做者 : Android-SuperMan
* @建立日期 :2017/7/14 下午3:04
* @方法做用:
* 參考Singleton 的寫法
* Scope 標註是Scope
* Documented 標記在文檔
* @Retention(RUNTIME) 運行時級別
*/
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScoped {
}
複製代碼
首先想一下,什麼樣的對象,可以作到全局單例,生命週期確定和APP 綁定嘛,這裏我作演示,一個AppAip 咱們要對這個對象,全局單例,因此二話不說,先給Application 來個全家桶,
@Module
public class AppModule {
@Singleton
@Provides
AppApi providerAppApi() {
return new AppApi();
}
}
複製代碼
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
AppApi getAppApi();
}
複製代碼
public class MyApp extends Application {
private AppConponent appComponent;
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppConpoment.create();
}
public AppConponent getAppComponent() {
return appConponent;
}
}
複製代碼
首先,這個是個橋樑,依賴方式,上文已經說過了
@ActivityScoped
@Component(modules = {MainModule.class}, dependencies = AppConponent.class)
public interface MainComponent {
void inject(MainActivity activity);
void inject(TestAct activity);
}
複製代碼
細心的小夥伴可能已經發現了,只有在上面一個MainComponent
添加了一個@ActivityScoped
,這裏說明一下,@Singleton
是Application 的單例
注意,第三個坑,子類component 依賴父類的component ,子類component的Scoped 要小於父類的Scoped,Singleton的級別是Application
因此,咱們這裏的@Singleton
級別大於咱們自定義的@ActivityScoped
,同時,對應module 所依賴的component ,也要放上相應的Scope
好吧,上面的例子,打印Log.
12-30 02:16:30.899 4717-4717/? E/TAG: A1---->com.allens.daggerdemo.Bean.AppApi@70bfc2
12-30 02:16:31.009 4717-4717/? E/TAG: A2---->com.allens.daggerdemo.Bean.AppApi@70bfc2
複製代碼
同樣啦
爬坑指南(極度重要)
這個是系統提供的一個Component,當使用Subcomponent
,那麼默認會依賴Component
例如
@Subcomponent(modules = TestSubModule.class)
public interface TestSubComponent {
void inject(MainActivity activity);
}
複製代碼
@Component(modules = {MainModule.class})
public interface MainConponent {
TestSubComponent add(TestSubModule module);
}
複製代碼
在TestSubComponent
中 我void inject(MainActivity activity);
,即是這個橋樑,我是要注入到MainActivity
,可是dagger 並不會給我生成一個Dagger開頭的DaggerTestSubComponent 這個類,若是我想使用TestSubModule.class
裏面提供的對象,依然仍是使用DaggerMainConponent
例如
DaggerMainConponent
.builder()
.mainModule(new MainModule())
.build()
.add(new TestSubModule())
.inject(this);
複製代碼
能夠看到這裏有一個add的方法,真是我在MainConponent
添加的TestSubComponent add(TestSubModule module);
public class Main3Activity extends AppCompatActivity {
@PresentForContext
@Inject
Lazy<Present> lazy;
@PresentForName
@Inject
Provider<Present> provider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
ActivityComponent activityComponent = DaggerActivityComponent.builder()
.appComponent(appComponent)
.activityModule(new ActivityModule())
.build();
activityComponent.injectActivity(this);
Present present = lazy.get();
Present present1 = provider.get();
}
}
複製代碼
其中Lazy(懶加載)的做用比如component初始化了一個present對象,而後放到一個池子裏,須要的時候就get它,因此你每次get的時候拿到的對象都是同一個;而且當你第一次去get時,它纔會去初始化這個實例.
procider(強制加載)的做用: 1:同上當你第一次去get時,它纔會去初始化這個實例 2:後面當你去get這個實例時,是否爲同一個,取決於他Module裏實現的方式
這是如今主流的設計架構
MVP,這個我會在後面的文章介紹,這裏不作太多解釋
當你瞭解MVP 的時候,你就知道,全部的業務邏輯全在Presenter
, 換句話, presenter 持有的對象,控制着你程序的所有邏輯,這在dagger 中,講白了 咱們只要將全部的presetner 對象控制就能夠了
下面附上目錄結構,固然僅僅做爲參考。dagger 強大的用法仍是須要各位本身去體會,下面的項目是我剛剛學會dagger 時候 寫的一個項目
能夠看到,我是將全部的activity 或者 fragment 所有添加在同一個Component中,固然如今的話不推薦,好比Utils 你能夠專門作一個Component,
首先放上個人Module,公司項目,不少東西沒敢放上來,體諒,能夠看到我這裏提供了一個SplashPresenter,也就是啓動頁的Presneter,業務邏輯
@Module
public class ApiModule {
public ApiModule() {
}
@Provides
@Singleton
Handler provideHandler() {
return new Handler();
}
@Provides
@Singleton
SQLiteDatabase provideSQLiteDatabase() {
return new DataBaseHelper(MyApp.context, Config.SqlName, null, Config.SqlVersion).getWritableDatabase();
}
/**
* @ User : Android-SuperMan
* @ 建立日期 : 2017/7/13 下午3:24
* @模塊做用 :
* <p>
* ====================================================================================================================================
* ====================================================================================================================================
*/
private SplashPresenter splashPresenter;
public ApiModule(SplashAct splashAct) {
splashPresenter = new SplashPresenter(splashAct, new SplashModel());
}
@Provides
@Singleton
SplashPresenter provideSplashPresenter() {
return splashPresenter;
}
.....
}
複製代碼
當我使用的時候,只須要注入便可,以下代碼
public class SplashAct extends BaseActivity implements SplashContract.View {
@Inject
SplashPresenter presenter;
@Inject
Handler handler;
@Inject
ApiService apiService;
@Override
protected void onCreate() {
setContentView(R.layout.activity_splash);
}
@Override
protected void initInject() {
DaggerApiComponent.builder()
.apiModule(new ApiModule(this))
.build()
.inject(this);
}
@Override
protected void initListener() {
presenter.getWordsInfo(true, apiService);
}
@Override
public void gotoLogInAct() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
startActivity(new Intent(SplashAct.this, LogInAct.class));
finish();
}
}, 1500);
}
}
複製代碼
————————分割線————————
若是你看到了這裏,以爲文章寫得不錯就給個贊唄?若是你以爲那裏值得改進的,請給我留言。必定會認真查詢,修正不足。謝謝。
爲何某些人會一直比你優秀,是由於他自己就很優秀還一直在持續努力變得更優秀,而你是否是還在知足於現狀心裏在竊喜!但願讀到這的您能點個小贊和關注下我,之後還會更新技術乾貨,謝謝您的支持!
轉發分享+關注,天天獲取更多資料
Android架構師之路很漫長,一塊兒共勉吧!