依賴注入庫(kù)Dagger2的使用方法

歡迎Follow我的GitHub, 關(guān)注我的簡(jiǎn)書. 其余參考Android目錄.

Dagger2

本文的合集已經(jīng)編著成書,高級(jí)Android開發(fā)強(qiáng)化實(shí)戰(zhàn)笙以,歡迎各位讀友的建議和指導(dǎo)匙瘪。在京東即可購(gòu)買:https://item.jd.com/12385680.html

Android

Dagger已經(jīng)加入Google I/O, 是Square開發(fā)的依賴注入庫(kù), 發(fā)布2.0版本. Dagger表示有向非循環(huán)圖(Directed Acyclic Graph, DAGger). 好處和優(yōu)點(diǎn)有很多, 參考, 所有優(yōu)秀的開源庫(kù), 本質(zhì)上都是讓程序更加清晰, 編寫更加容易. 讓我們來看看怎么使用?

主要內(nèi)容:
(1) 項(xiàng)目的配置環(huán)境.
(2) Inject\Module\Component的使用方法.
(3) 結(jié)合Retrofit和RxAndroid.

本文源碼的GitHub下載地址

1. 配置

從一個(gè)最簡(jiǎn)單的HelloWorld開始, 設(shè)置build.gradle, 并添加依賴庫(kù).

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

// Lambda表達(dá)式
plugins {
    id "me.tatarka.retrolambda" version "3.2.4"
}

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt' // 注釋處理

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "clwang.chunyu.me.wcl_dagger_demo"
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    // 注釋沖突
    packagingOptions {
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }

    // 使用Java1.8
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:recyclerview-v7:23.1.1' // RecyclerView

    compile 'com.jakewharton:butterknife:7.0.1' // 標(biāo)注

    compile 'com.google.dagger:dagger:2.0.2' // dagger2
    compile 'com.google.dagger:dagger-compiler:2.0.2' // dagger2

    compile 'io.reactivex:rxandroid:1.1.0' // RxAndroid
    compile 'io.reactivex:rxjava:1.1.0' // 推薦同時(shí)加載RxJava

    compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' // Retrofit網(wǎng)絡(luò)處理
    compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2' // Retrofit的rx解析庫(kù)
    compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2' // Retrofit的gson庫(kù)

    provided 'javax.annotation:jsr250-api:1.0' // Java標(biāo)注
}

Gradle的配置與功能.
android-apt, 提供dagger2使用編譯生成類的功能.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

apply plugin: 'com.neenbedankt.android-apt' // 注釋處理

retrolambda, 提供Lambda表達(dá)式支持的功能.

// Lambda表達(dá)式
plugins {
    id "me.tatarka.retrolambda" version "3.2.4"
}

android{
    ...
    // 使用Java1.8
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

recyclerview, 提供RecyclerView控件的功能.

   compile 'com.android.support:recyclerview-v7:23.1.1' // RecyclerView

butterknife, 提供xml至java的id映射的功能.

   compile 'com.jakewharton:butterknife:7.0.1' // 標(biāo)注

dagger2, 提供dagger2支持的功能.

    compile 'com.google.dagger:dagger:2.0.2' // dagger2
    compile 'com.google.dagger:dagger-compiler:2.0.2' // dagger2

rx, 提供rxandroid和rxjava支持的功能.

    compile 'io.reactivex:rxandroid:1.1.0' // RxAndroid
    compile 'io.reactivex:rxjava:1.1.0' // 推薦同時(shí)加載RxJava

retrofit, 提供網(wǎng)絡(luò)請(qǐng)求的支持的功能.

    compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' // Retrofit網(wǎng)絡(luò)處理
    compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2' // Retrofit的rx解析庫(kù)
    compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2' // Retrofit的gson庫(kù)

annotation, 提供java注釋解析的功能.

    provided 'javax.annotation:jsr250-api:1.0' // Java標(biāo)注

2. 主活動(dòng)

使用主頁跳轉(zhuǎn)頁面展示dagger2.

dagger2主要包含inject, module, component三個(gè)部分, 即:
Inject, 依賴注入dependency injection, 把定義的類注入聲明.
Module, 模塊, 提供若干類, 在依賴注入中使用.
Component, 組件, 注冊(cè)若干模塊至項(xiàng)目中.

提供圖接口, 在項(xiàng)目中, 使用注入的類.

/**
 * Dagger2的圖接口
 * <p/>
 * Created by wangchenlong on 16/1/2.
 */
public interface DemoGraph {
    void inject(MainActivity mainActivity); // 注入MainActivity

    void inject(ReposListActivity reposListActivity); // 注入列表Activity
}

組件, 注冊(cè)Module, 添加主Module.

/**
 * 組件
 * Created by wangchenlong on 16/1/2.
 */
@Singleton
@Component(modules = {MainModule.class, ApiModule.class})
public interface DemoComponent extends DemoGraph {
    final class Initializer {
        private Initializer() {
        } // No instances.

        // 初始化組件
        public static DemoComponent init(DemoApplication app) {
            return DaggerDemoComponent.builder()
                    .mainModule(new MainModule(app))
                    .build();
        }
    }
}

如果沒有Module可以暫時(shí)不添加, 但是要提供類, 項(xiàng)目注冊(cè)需要使用中間類.
DaggerDemoComponent是自動(dòng)生成的類, Dagger+類名.

項(xiàng)目的應(yīng)用, 把Application添加至組件, 并提供注冊(cè)類的圖接口.

/**
 * 應(yīng)用信息
 * <p/>
 * Created by wangchenlong on 16/1/2.
 */
public class DemoApplication extends Application {
    private static DemoGraph sDemoGraph;
    private static DemoApplication sInstance;

    @Override public void onCreate() {
        super.onCreate();
        sInstance = this;
        buildComponentAndInject();
    }

    public static DemoGraph component() {
        return sDemoGraph;
    }

    public static void buildComponentAndInject() {
        sDemoGraph = DemoComponent.Initializer.init(sInstance);
    }
}

主活動(dòng), 注冊(cè)入圖, 并添加跳轉(zhuǎn)下一頁功能.

/**
 * 主活動(dòng), 注冊(cè)類.
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);

        DemoApplication.component().inject(this); // 應(yīng)用注入
    }

    // 跳轉(zhuǎn)列表視圖
    public void gotoReposList(View view) {
        startActivity(new Intent(this, ReposListActivity.class));
    }
}

主模塊, 提供Application和Resources.

/**
 * 主要模塊, 提供Application和resources.
 * <p/>
 * Created by wangchenlong on 16/1/2.
 */
@Module
public class MainModule {
    private final DemoApplication mApp;

    public MainModule(DemoApplication application) {
        mApp = application;
    }

    @Provides
    @Singleton
    protected Application provideApplication() {
        return mApp;
    }

    @Provides
    @Singleton
    protected Resources provideResources() {
        return mApp.getResources();
    }
}

方法名添加@Provides@Singleton, 使用時(shí), 添加@Inject即可. 表示在Module中創(chuàng)建, 在其他類中, 可以任意注入使用.
方法的參數(shù), 因?yàn)闆]有調(diào)用方法的過程, 所以需要模塊(Module)提供.

3. 其他活動(dòng)

主要是列表展示GitHub用戶的庫(kù)信息, 使用Retrofit和RxAndroid的方法.

使用RecyclerView展示庫(kù)信息, 注入類到圖中, 并注入Github服務(wù), Rx分發(fā)信息.

/**
 * 代碼庫(kù)列表
 * <p>
 * Created by wangchenlong on 16/1/2.
 */
public class ReposListActivity extends Activity {
    @Bind(R.id.repos_rv_list) RecyclerView mRvList;

    @Inject
    GitHubService mGitHubService;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_repos_list);
        ButterKnife.bind(this);

        DemoApplication.component().inject(this);

        LinearLayoutManager manager = new LinearLayoutManager(this);
        manager.setOrientation(LinearLayoutManager.VERTICAL);
        mRvList.setLayoutManager(manager);

        ListAdapter adapter = new ListAdapter();
        mRvList.setAdapter(adapter);
        loadData(adapter);
    }

    // 加載數(shù)據(jù)
    private void loadData(ListAdapter adapter) {
        mGitHubService.getRepoData("SpikeKing")
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(adapter::setRepos);
    }
}

適配器.

/**
 * RecyclerView的Adapter
 * <p>
 * Created by wangchenlong on 16/1/2.
 */
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.RepoViewHolder> {

    private ArrayList<Repo> mRepos; // 庫(kù)信息

    public ListAdapter() {
        mRepos = new ArrayList<>();
    }

    public void setRepos(ArrayList<Repo> repos) {
        mRepos = repos;
        notifyItemInserted(mRepos.size() - 1);
    }

    @Override
    public RepoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_repo, parent, false);
        return new RepoViewHolder(view);
    }

    @Override public void onBindViewHolder(RepoViewHolder holder, int position) {
        holder.bindTo(mRepos.get(position));
    }

    @Override public int getItemCount() {
        return mRepos.size();
    }

    public static class RepoViewHolder extends RecyclerView.ViewHolder {

        @Bind(R.id.item_iv_repo_name) TextView mIvRepoName;
        @Bind(R.id.item_iv_repo_detail) TextView mIvRepoDetail;

        public RepoViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

        public void bindTo(Repo repo) {
            mIvRepoName.setText(repo.name);
            mIvRepoDetail.setText(String.valueOf(repo.description + "(" + repo.language + ")"));
        }
    }

    public static class Repo {
        public String name; // 庫(kù)的名字
        public String description; // 描述
        public String language; // 語言
    }
}

GitHub請(qǐng)求接口, 返回Rx的觀察者.

/**
 * GitHub服務(wù)
 * <p>
 * Created by wangchenlong on 16/1/2.
 */
public interface GitHubService {
    String ENDPOINT = "https://api.github.com";

    // 獲取庫(kù), 獲取的是數(shù)組
    @GET("/users/{user}/repos")
    Observable<ArrayList<ListAdapter.Repo>> getRepoData(@Path("user") String user);
}

Api模塊, 使用請(qǐng)求接口創(chuàng)建GitHub服務(wù).

/**
 * 接口模塊
 * <p>
 * Created by wangchenlong on 16/1/2.
 */
@Module
public class ApiModule {

    @Provides
    @Singleton
    protected GitHubService provideGitHubService() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(GitHubService.ENDPOINT)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 添加Rx適配器
                .addConverterFactory(GsonConverterFactory.create()) // 添加Gson轉(zhuǎn)換器
                .build();
        return retrofit.create(GitHubService.class);
    }
}

不要忘記, 注冊(cè)模塊(Module)到組件(Component). 組件組成到應(yīng)用, 模塊注冊(cè)到組件.

dagger2的重要優(yōu)勢(shì)就是省略了很多重復(fù)的創(chuàng)建, 直接依賴注入非常簡(jiǎn)單.

效果


動(dòng)畫

OK, that's all! Enjoy It!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赡矢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歌径,老刑警劉巖陕赃,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瓜挽,居然都是意外死亡盹廷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門久橙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俄占,“玉大人,你說我怎么就攤上這事淆衷〉叻牛” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵吭敢,是天一觀的道長(zhǎng)碰凶。 經(jīng)常有香客問我,道長(zhǎng)鹿驼,這世上最難降的妖魔是什么欲低? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮畜晰,結(jié)果婚禮上砾莱,老公的妹妹穿的比我還像新娘。我一直安慰自己凄鼻,他們只是感情好腊瑟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布聚假。 她就那樣靜靜地躺著,像睡著了一般闰非。 火紅的嫁衣襯著肌膚如雪膘格。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天财松,我揣著相機(jī)與錄音瘪贱,去河邊找鬼。 笑死辆毡,一個(gè)胖子當(dāng)著我的面吹牛菜秦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舶掖,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼球昨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了眨攘?” 一聲冷哼從身側(cè)響起褪尝,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎期犬,沒想到半個(gè)月后河哑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡龟虎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年璃谨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲤妥。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佳吞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棉安,到底是詐尸還是另有隱情底扳,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布贡耽,位于F島的核電站衷模,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蒲赂。R本人自食惡果不足惜阱冶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滥嘴。 院中可真熱鬧木蹬,春花似錦、人聲如沸若皱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晦譬,卻和暖如春疤苹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蛔添。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工痰催, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兜辞,地道東北人迎瞧。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逸吵,于是被迫代替她去往敵國(guó)和親凶硅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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