Android:Dagger2系列2 實例解析(更新完畢)

上一篇:Android:Dagger2系列1 初識
下一篇:Android:Dagger2系列3 深入探究(更新ing)

這篇文章會分享一下實際應(yīng)用中的Dagger2如何使用,以及Dagger2通過apt插件如何給我們生成代碼照弥,以及生成的代碼之間的關(guān)聯(lián)键痛。

下面說一下模擬的業(yè)務(wù)場景:

主界面MainActivity通過MainPresenter去請求一個接口伶氢,并返回數(shù)據(jù)滑蚯。這里用的是MVP+Retrofit2+RxJava,如果不熟悉可以先不管,因為不會涉及太多克握,而這篇內(nèi)容主要分享的是Dagger2但校。
如果mvp不清楚的可以點擊 mvp google 寫法螃诅;RxJava和Retrofit后期我也會分享出來(知道的略過),歡迎關(guān)注W创选J趼恪!

先看下關(guān)于Dagger部分的包目錄結(jié)構(gòu):

google官方demo 是按照業(yè)務(wù)來分包的亭枷,個人比較喜歡按照組件來分袭艺。

目錄結(jié)構(gòu).png

首先我需要一個全局的網(wǎng)絡(luò)請求對象IRetrofitRequest放在Application,并且是單例的。所以寫了一個RetrofitModule提供IRetrofitRequest實例叨粘。

代碼塊1:

@Singleton
@Component(modules = {AppModule.class, RetrofitModule.class})
public interface AppComponent {
    IRetrofitRequest request();
    Context getContext();
}

其中request();方法返回的IRetrofitRequest對象需要上面代碼塊1:依賴的RetrofitModule類中進(jìn)行實例化:如下代碼

代碼塊2:

@Module
public class RetrofitModule {
    @Provides
    @Singleton
    public IRetrofitRequest getService() {
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)//設(shè)置請求超時時間
                .retryOnConnectionFailure(true)//設(shè)置出現(xiàn)錯誤進(jìn)行重新連接
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(UrlConst.URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(httpClient)
                .build();
        return retrofit.create(IRetrofitRequest.class);
    }
}

代碼塊2:中提供的IRetrofitRequest 實例對象必須要用@Provides標(biāo)注猾编,該對象是單例的所以用@Singleton標(biāo)注,這里為什么用這兩個注解標(biāo)注之后就能實現(xiàn)為AppComponent提供單例的實例宣鄙,稍后會進(jìn)行Dagger2生成的代碼解析袍镀。
當(dāng)然一個Component類可以依賴多個Module默蚌,如代碼塊1:中還依賴了AppModule冻晤,AppModule中提供了在Component方法名是getContext()的實例對象,如下代碼:

代碼塊3:

@Module
public class AppModule {
    private Context context;
    public AppModule(Context context) {
        this.context = context;
    }
    @Provides
    public Context getContext() {
        return context;
    }
}

如代碼塊2和3所示绸吸,所有的被Component依賴的Module都必須用@Module注解標(biāo)注鼻弧。因為Dagger2需要這些標(biāo)注通過apt插件自動生成代碼。
在AppComponent中提供的IRetrofitRequest單例對象如何在Application中使用呢锦茁?

代碼塊4:

public class App extends Application {
    private static AppComponent appComponent;
    @Override
    public void onCreate() {
        super.onCreate();
        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(getApplicationContext()))
                .retrofitModule(new RetrofitModule())
                .build();
    }
    public static AppComponent getComponent() {
        return appComponent;
    }
}

代碼塊4:中的DaggerAppComponent是Dagger2幫我們自動生成的攘轩,只要編譯一下就可以自動生成:


編譯.png

AppComponent需要初始化依賴的兩個Module(AppModule和RetrofitModule),這里生成的DaggerAppComponent是通過構(gòu)建者模式進(jìn)行初始化的。

.appModule(new AppModule(getApplicationContext()))
.retrofitModule(new RetrofitModule())

最后創(chuàng)建的AppComponent就提供了IRetrofitRequest全局單例對象码俩,整個app的網(wǎng)絡(luò)訪問都可以通過該對象進(jìn)行調(diào)用度帮。

AppComponent后期拓展:

一個全局的變量現(xiàn)在統(tǒng)一都可以放在AppComponent中進(jìn)行管理,這個demo中有網(wǎng)絡(luò)請求的一個單例接口對象,一個是全局的Context對象笨篷。后期肯定會有其他的都可以放在AppModule中進(jìn)行實例化瞳秽,或者單獨再寫一個Module依賴到AppComponent中。

在MainActivity中如何進(jìn)行使用:

這里用的是mvp開發(fā)模式率翅,所以需要一個Presenter:MainActivityPresenter练俐,需要傳遞一個參數(shù),用于操作MainActivity界面:MainActivityContract.View冕臭,而這個MainActivityPresenter誰來提供呢腺晾?當(dāng)然是Component通過依賴的Module來提供,看看MainActivity的Component和Module辜贵。

代碼塊5:

@ActivityScope
@Component(dependencies = AppComponent.class, modules = {MainActivityModule.class})
public interface MainActivityComponent {
    void inject(MainActivity mainActivity);
}
代碼塊6:

@Module
public class MainActivityModule {
    private MainActivityContract.View view;
    public MainActivityModule(MainActivityContract.View view) {
        this.view = view;
    }
    @ActivityScope
    @Provides
    public MainActivityPresenter getMainActivityPresenter() {
        return new MainActivityPresenter(view);
    }
}
這里的代碼塊5和6,你會發(fā)現(xiàn)我們在MainActivityModule 里提供了MainActivityPresenter實例悯蝉,但是在MainActivityComponent接口里并沒有寫上提供MainActivityPresenter的方法,另外還多了一個void inject(MainActivity mainactivity),這里跟AppComponent中的(代碼塊1)有區(qū)別是咋回事念颈?等會解釋泉粉。

再看MainActivity代碼:

代碼塊6:

public class MainActivity extends BaseActivity implements MainActivityContract.View {
    @Inject
    MainActivityPresenter presenter;
    @Inject
    SecondActivityPresenter secondActivityPresenter;
    @Bind(R.id.textView)
    TextView textView;
    @Bind(R.id.textView2)
    TextView textView2;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        presenter.start();
        secondActivityPresenter.set();
    }
    @Override
    public void providers() {//該方法是BaseActivity中onCreate()中調(diào)用的抽象方法
        DaggerMainActivityComponent.builder()
                .mainActivityModule(new MainActivityModule(this))
                .appComponent(App.getComponent())
                .build()
                .inject(this);
    }
    @OnClick({R.id.textView, R.id.textView2})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.textView:
                startActivity(new Intent(this, SecondActivity.class));
                break;
            case R.id.textView2:
                break;
            default:
                break;
        }
    }
    @Override
    public void showSuccess() {
        T.show(this, "成功");
    }
    @Override
    public void showFailed() {
        T.show(this, "失敗");
    }
}
先解釋一下providers()方法:該方法是BaseActivity中onCreate()中調(diào)用的抽象方法。

注意看代碼中的

@Inject
MainActivityPresenter presenter;

注意1:但是在整個MainActivity中卻找不到初始化的過程榴芳,再看providers()方法中的代碼嗡靡,跟App中有區(qū)別的是,我這里并沒有寫成

  MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
                .mainActivityModule(new MainActivityModule(this))
                .appComponent(App.getComponent())
                .build();

注意2:還有的區(qū)別是多了一個

.inject(this);

原因:

1:因為在App中我并沒有哪個對象的聲明用了@Inject注解進(jìn)行標(biāo)注窟感,而且App中的AppComponent實例對象需要給其他Activity或者類使用讨彼。
2:在該demo中的MainActivity,我們不需要其他地方用到MainActivityComponent對象柿祈,我們只是在MainActivity用到MainPresenter對象哈误,我們可以不用通過MainActivityComponent中的某一個方法獲得MainPresenter對象,我們在用@Inject標(biāo)注MainActivityPresenter presenter的時候需要把在哪里聲明的外部類(這里是MainActivity)注入到MainComponent中躏嚎,就是上面(代碼塊5)說過的沒有提供返回MainPresenter的方法卻多了一個void inject(MainActivity mainactivity)蜜自;這里的返回值是void的inject方法名可以是任意的,但是最好寫成inject(官方寫法)卢佣。

最后只要調(diào)用了providers()方法重荠,我們的MainPresenter presenter對象就已經(jīng)被初始化了,這個時候就可以通過presenter.start()去調(diào)用網(wǎng)絡(luò)接口請求數(shù)據(jù)了虚茶;

只要我們配置了以上的Component,Module戈鲁,編譯之后Dagger2就會通過apt插件生成一系列代碼。

那么一系列代碼到底是怎樣的嘹叫?到底是怎樣工作的呢婆殿?

先看下生成的代碼目錄結(jié)構(gòu):

Dagger2通過apt生成的代碼目錄結(jié)構(gòu).png

可以看到生成的代碼包名還是跟自己代碼中的一樣,生成的代碼的類名也有一定的規(guī)則罩扇。

看看這些代碼是根據(jù)什么注解生成的:

  • 用@Component注解標(biāo)注的xxxComponent類會生成DaggerxxxComponent類
  • 用@Module注解標(biāo)注的xxxModule中用@Provides注解標(biāo)注的每個方法都會生成一個類婆芦,這個類是一個工廠模式,提供對象實例,比如:
@Module
public class AAModule{
    @ActivityScope
    @Providespublic 
    BB getBB() {
        return new BB();
    }
}

getBB()方法就會生成AAModule_GetBBFactory類消约。

  • 如果一個類的構(gòu)造函數(shù)用了@Inject注解標(biāo)注:例如:
public class CC{
    @Inject
    public CC() {
    }
}

就會生成CC_Factory類癌压。

  • 如果一個類中有用@Inject注解標(biāo)注對象聲明他就會生成:比如demo中的MainActivity;
public class MainActivity extends BaseActivity implements MainActivityContract.View {   
     @Inject
     MainActivityPresenter presenter;
}

Dagger2就會自動生成MainActivity_MembersInjector。

看看這些代碼之間的關(guān)聯(lián)

Dagger2 自動生成的代碼關(guān)聯(lián)分析圖.jpg

分析圖箭頭的結(jié)尾是DaggerMainActivityComponent荆陆,也就是最后暴露給我們的就是DaggerMainActivityComponent這個類滩届,其它幫助我們生成的代碼都可以不用關(guān)心。

分析圖或許會有疏漏和不對被啼,基本情況應(yīng)該就是這樣帜消,更多細(xì)節(jié)性的代碼可以查看項目gitlab: demo

上一篇:Android:Dagger2系列1 初識
下一篇:Android:Dagger2系列3 深入探究(更新ing)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浓体,隨后出現(xiàn)的幾起案子泡挺,更是在濱河造成了極大的恐慌,老刑警劉巖命浴,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娄猫,死亡現(xiàn)場離奇詭異,居然都是意外死亡生闲,警方通過查閱死者的電腦和手機(jī)媳溺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碍讯,“玉大人悬蔽,你說我怎么就攤上這事∽叫耍” “怎么了蝎困?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長倍啥。 經(jīng)常有香客問我禾乘,道長,這世上最難降的妖魔是什么虽缕? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任始藕,我火速辦了婚禮,結(jié)果婚禮上彼宠,老公的妹妹穿的比我還像新娘鳄虱。我一直安慰自己弟塞,他們只是感情好凭峡,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著决记,像睡著了一般摧冀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天索昂,我揣著相機(jī)與錄音建车,去河邊找鬼。 笑死椒惨,一個胖子當(dāng)著我的面吹牛缤至,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播康谆,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼领斥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沃暗?” 一聲冷哼從身側(cè)響起月洛,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎孽锥,沒想到半個月后嚼黔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡惜辑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年唬涧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盛撑。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡爵卒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撵彻,到底是詐尸還是另有隱情钓株,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布陌僵,位于F島的核電站轴合,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏碗短。R本人自食惡果不足惜受葛,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望偎谁。 院中可真熱鬧总滩,春花似錦、人聲如沸巡雨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铐望。三九已至冈涧,卻和暖如春茂附,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背督弓。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工营曼, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人愚隧。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓蒂阱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狂塘。 傳聞我的和親對象是個殘疾皇子蒜危,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 部分內(nèi)容參考自:[Android]使用Dagger 2依賴注入 - DI介紹(翻譯)[Android]使用Dagg...
    AItsuki閱讀 47,351評論 66 356
  • 寫在前面:我目前就職于阿里巴巴-菜鳥,團(tuán)隊目前缺人睹耐,招聘java和客戶端開發(fā)辐赞,招聘對象為:社招和19屆畢業(yè)的校招生...
    littleKang閱讀 115,379評論 93 745
  • 不知道你們的身邊有沒有這么一種人,莫名其妙的他就給你吊臉子硝训,好像突然之間你欠了他五百萬响委。你剛畢業(yè),他總是嘲笑你...
    伊筱葵閱讀 431評論 0 1
  • (一)樹歸樹 林歸林 也不知道怎么了窖梁,這幾天的天氣異常得很赘风。整日里,天都是灰蒙蒙的纵刘,好像被一個大悶蓋兒蓋住了似的邀窃,...
    落在枝頭閱讀 528評論 0 0
  • 每天1000字瞬捕,把它分解開來,如果一句話十個字的話平均舵抹,也就是肪虎,每天說100句話,然后把它寫下來惧蛹,1000字的任務(wù)...
    倔強(qiáng)的挑夫閱讀 359評論 0 0