Android -- 带你从源码角度领悟Dagger2入门到放弃(一)
1,以前的博客也寫了兩篇關(guān)于Dagger2,但是感覺自己使用的時(shí)候還是云里霧里的,更不談各位來看博客的同學(xué)了,所以今天打算和大家再一次的入坑試試,最后一次了,保證最后一次了。
2,接入項(xiàng)目
? ? 在項(xiàng)目的Gradle添加如下代碼
dependencies {classpath 'com.android.tools.build:gradle:2.3.0'// 添加android-apt 插件classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'}在app中的Gradle中添加導(dǎo)入
// 應(yīng)用插件apply plugin: 'com.neenbedankt.android-apt'// dagger 2 的配置compile 'com.google.dagger:dagger:2.4'apt 'com.google.dagger:dagger-compiler:2.4'compile 'org.glassfish:javax.annotation:10.0-b28'// 添加java 注解庫(kù)簡(jiǎn)單的注解標(biāo)簽的介紹,由于之前寫過一篇博客和大家思考過為什么使用Dagger2(它這么難使用為什么還要使用!!),并且還有一些常見注解標(biāo)簽的使用,所以這里就不和大家廢話這么引入了,直接上干貨
@Inject Inject主要有兩個(gè)作用,一個(gè)是使用在構(gòu)造函數(shù)上,通過標(biāo)記構(gòu)造函數(shù)讓Dagger2來使用(Dagger2通過Inject標(biāo)記可以在需要這個(gè)類實(shí)例的時(shí)候來找到這個(gè)構(gòu)造函數(shù)并把相關(guān)實(shí)例new出來)從而提供依賴,另一個(gè)作用就是標(biāo)記在需要依賴的變量讓Dagger2為其提供依賴。@Provide 用Provide來標(biāo)注一個(gè)方法,該方法可以在需要提供依賴時(shí)被調(diào)用,從而把預(yù)先提供好的對(duì)象當(dāng)做依賴給標(biāo)注了@Injection的變量賦值。provide主要用于標(biāo)注Module里的方法@Module 用Module標(biāo)注的類是專門用來提供依賴的。有的人可能有些疑惑,看了上面的@Inject,需要在構(gòu)造函數(shù)上標(biāo)記才能提供依賴,那么如果我們需要提供的類構(gòu)造函數(shù)無法修改怎么辦,比如一些jar包里的類,我們無法修改源碼。這時(shí)候就需要使用Module了。Module可以給不能修改源碼的類提供依賴,當(dāng)然,能用Inject標(biāo)注的通過Module也可以提供依賴@Component Component一般用來標(biāo)注接口,被標(biāo)注了Component的接口在編譯時(shí)會(huì)產(chǎn)生相應(yīng)的類的實(shí)例來作為提供依賴方和需要依賴方之間的橋梁,把相關(guān)依賴注入到其中。@Singleton 該注解就是通過@scope定義的注解,一般用于提供全局單例。現(xiàn)在在實(shí)際場(chǎng)景中有這種情況,存在學(xué)生在老師的課堂上上課,那么一個(gè)學(xué)生可能存在多個(gè)老師,而一個(gè)老師也可能存在多個(gè)學(xué)生。這里我們?yōu)榱朔奖憬忉?#xff0c;就直接轉(zhuǎn)換成1對(duì)1的模式即一個(gè)學(xué)生只有一個(gè)老師,一個(gè)老師只有一個(gè)學(xué)生,然我們來看看轉(zhuǎn)換成我們的java對(duì)象是什么樣的,首先創(chuàng)建學(xué)生實(shí)體類
Student.java
public class Student {private int id;private String name;private Course[] course;public Student() {System.out.println("Student create!!!");}public Student(int id, String name, Course[] course) {this.id = id;this.name = name;this.course = course;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Course[] getCourse() {return course;}public void setCourse(Course[] course) {this.course = course;}public void startLessons() {System.out.println("開始上課了");} }我們的學(xué)生有一些基本的屬性,如id、姓名、所學(xué)的課程,還有上課的動(dòng)作。再看看我們創(chuàng)建老師類
public class Teacher {Student student;public Teacher() {student = new student();}public void teacher() {student.startLessons();} }這里我們就有一個(gè)問題了,我們老師類中需要一個(gè)學(xué)生的對(duì)象,而按照以前的方法我們肯定是在老師的構(gòu)造方法中傳遞學(xué)生對(duì)象,毫無疑問肯定是new Student創(chuàng)建學(xué)生對(duì)象的,這里我們要使用Dagger2來代替(至于為什么要使用Dagger2代替,和代替之后有什么好處我以前寫過,這里就不和大家廢話了)
首先在確定是我們Teacher類中的student屬性需要Student對(duì)象,所以添加@Inject注解標(biāo)簽
@InjectStudent student;而我們Dagger2要知道到底我是調(diào)用那個(gè)構(gòu)造函數(shù)來創(chuàng)建Student對(duì)象啊,所以要在Student類中構(gòu)造函數(shù)中添加@Inject標(biāo)簽,標(biāo)明你Dagger2是要在這個(gè)構(gòu)造方法里面創(chuàng)建的
public class Student {private int id;private String name;private Course[] course;@Injectpublic Student() {System.out.println("Student create!!!");}public Student(int id, String name, Course[] course) {this.id = id;this.name = name;this.course = course;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Course[] getCourse() {return course;}public void setCourse(Course[] course) {this.course = course;}public void startLessons() {System.out.println("開始上課了");} }然后我們 Student中對(duì)象被創(chuàng)建了,而我們Teacher中需要這個(gè)student對(duì)象,這時(shí)候我們差一個(gè)橋梁來鏈接這兩個(gè)類,從而讓我們被創(chuàng)建的student對(duì)象運(yùn)送到需要它的地方,所以現(xiàn)在我們需要使用@Component標(biāo)簽,來修飾我們自定義的一個(gè)接口,創(chuàng)建TeacherComponent接口,并使用@Component注解標(biāo)簽修飾,創(chuàng)建inject方法(這里很多看過不少Dagger2文章的同學(xué)坑定會(huì)有疑問,這里的inject是固定方法名嗎,能不能使用injectA啊之類的,先把問題留著,我們后面再講)
package com.qianmo.rxjavatext;import dagger.Component;/*** Created by Administrator on 2017/4/20 0020.* E-Mail:543441727@qq.com*/ @Component public interface TeacherComponent {void inject(Teacher teacher); }再在我們Teacher類中初始化
public Teacher() {DaggerTeacherComponent.builder().build().inject(this);}這時(shí)候可能有同學(xué)又有疑問了,DaggerTeacherComponent這個(gè)類怎么報(bào)錯(cuò)啊 ,其實(shí)這個(gè)類是編譯時(shí)產(chǎn)生的類大家不用慌,把代碼寫完了crtl+F9編譯一下就可以了,但是!!!這里DaggerTeacherComponent的書寫方法是Dagger加上你前面自定義的Component接口類的類名,一定要注意,不然很多同學(xué)都會(huì)在這翻車(我曾經(jīng)在這兒翻出無數(shù)次),然后再說一下我們上一個(gè)問題?TeacherComponent 中的inject方法是固定方法嗎?很明顯這里調(diào)用的是inject(this);所以不是固定方法,只不過你Component接口類寫成injectA(Teacher teacher),那么你這里調(diào)用的方法就是injectA(this)
ok,上面這些都寫好了,我們?cè)赥eacher類中添加測(cè)試類來測(cè)試測(cè)試
public class Teacher {//想持有學(xué)生對(duì)象@InjectStudent student;public Teacher() {DaggerTeacherComponent.builder().build().injectA(this);}public void teacher() {student.startLessons();}public static void main(String[] args) {new Teacher().teacher();} }看一下打印效果
Student create!!! 開始上課了3,源碼分析
ok,沒什么問題,那我們現(xiàn)在只是停留在會(huì)用的階段,底層我們的源碼到底是怎么吧我們的對(duì)象創(chuàng)建出來的,還有怎么將我們的對(duì)象設(shè)置到需要它的地方呢,不要慌,老司機(jī)現(xiàn)在就帶你來看看源碼是什么實(shí)現(xiàn)的。這里的源碼很簡(jiǎn)單,一共涉及到三個(gè)類,都是我們運(yùn)行時(shí)生成的DaggerTeacherComponent、Teacher_MembersInjector、Student_Factory。
先來看看DaggerTeacherComponent,按照字面意思這是我們Teacher的橋梁類,源碼如下:
package com.qianmo.rxjavatext;import dagger.MembersInjector; import javax.annotation.Generated;@Generated(value = "dagger.internal.codegen.ComponentProcessor",comments = "https://google.github.io/dagger" ) public final class DaggerTeacherComponent implements TeacherComponent {private MembersInjector<Teacher> teacherMembersInjector;private DaggerTeacherComponent(Builder builder) {assert builder != null;initialize(builder);}public static Builder builder() {return new Builder();}public static TeacherComponent create() {return builder().build();}@SuppressWarnings("unchecked")private void initialize(final Builder builder) {this.teacherMembersInjector = Teacher_MembersInjector.create(Student_Factory.create());}@Overridepublic void injectA(Teacher teacher) {teacherMembersInjector.injectMembers(teacher);}public static final class Builder {private Builder() {}public TeacherComponent build() {return new DaggerTeacherComponent(this);}} }我們首先來看我們之前的調(diào)用方法如下
DaggerTeacherComponent.builder().build().injectA(this);首先看一下DaggerTeacherComponent.builder()方法,我們從源碼中可以看到DaggerTeacherComponent.builder()調(diào)用生成了一個(gè)Builder 對(duì)象,我們繼續(xù)代用builder.builder()方法,而我們的build類中代碼如下(這里再次吐槽博客園的編輯器,在線編輯的時(shí)候無法顯示引用代碼的行號(hào),這樣我們就沒法通過行號(hào)來解釋每一行代碼的意思,而必須要重寫貼一次代碼,操蛋!!!):
public static final class Builder {private Builder() {}public TeacherComponent build() {return new DaggerTeacherComponent(this);}}“new DaggerTeacherComponent(this);” 看到?jīng)],實(shí)際上是調(diào)用我們的DaggerTeacherComponent對(duì)象,而我們的DaggerTeacherComponent構(gòu)造函數(shù)是調(diào)用的initialize()方法,看一下方法里面具體代碼
@SuppressWarnings("unchecked")private void initialize(final Builder builder) {this.teacherMembersInjector = Teacher_MembersInjector.create(Student_Factory.create());}這時(shí)候出現(xiàn)了Teacher_MembersInjector、Student_Factory類,我們先不要管,繼續(xù)往下看,上面我們調(diào)用完builder.builder()方法方法之后,再調(diào)用injectA(this)的方法,具體代碼如下:
@Overridepublic void injectA(Teacher teacher) {teacherMembersInjector.injectMembers(teacher);}呃,這里我們又看到Teacher_MembersInjector這個(gè)類對(duì)象了,所以這時(shí)候看看我們Teacher_MembersInjector的源碼了,我們上面一共在兩個(gè)地方使用了Teacher_MembersInjector,一個(gè)是.create方法,一個(gè)是injectMember方法,所以我們主要要留心源碼里面這兩個(gè)類,具體源碼如下:
package com.qianmo.rxjavatext;import dagger.MembersInjector; import javax.annotation.Generated; import javax.inject.Provider;@Generated(value = "dagger.internal.codegen.ComponentProcessor",comments = "https://google.github.io/dagger" ) public final class Teacher_MembersInjector implements MembersInjector<Teacher> {private final Provider<Student> studentProvider;public Teacher_MembersInjector(Provider<Student> studentProvider) {assert studentProvider != null;this.studentProvider = studentProvider;}public static MembersInjector<Teacher> create(Provider<Student> studentProvider) {return new Teacher_MembersInjector(studentProvider);}@Overridepublic void injectMembers(Teacher instance) {if (instance == null) {throw new NullPointerException("Cannot inject members into a null reference");}instance.student = studentProvider.get();}public static void injectStudent(Teacher instance, Provider<Student> studentProvider) {instance.student = studentProvider.get();} }先看看.create方法,可以看到就是很簡(jiǎn)單的new Teacher_MembersInjector ,相當(dāng)于初始化了一些成員變量studentProvider ,至于studentProvider 是什么,從字面的意思上來看是我們student的提供者,那么是時(shí)候我們就再來看看Student_Factory.create()方法了,因?yàn)槭沁@個(gè)類提供了studentProvider 對(duì)象
package com.qianmo.rxjavatext;import dagger.internal.Factory; import javax.annotation.Generated;@Generated(value = "dagger.internal.codegen.ComponentProcessor",comments = "https://google.github.io/dagger" ) public enum Student_Factory implements Factory<Student> {INSTANCE;@Overridepublic Student get() {return new Student();}public static Factory<Student> create() {return INSTANCE;} }窩草,請(qǐng)看get方法中的 “new Student()”代碼,這不就是我們的student對(duì)象的創(chuàng)建嘛,原來你在這里,再看一下在哪里調(diào)用我們的studentProvider.get方法拿到創(chuàng)建的Student對(duì)象,這時(shí)候請(qǐng)看Teacher_MembersInjector.injectMembers()方法,具體代碼如下:
@Overridepublic void injectMembers(Teacher instance) {if (instance == null) {throw new NullPointerException("Cannot inject members into a null reference");}instance.student = studentProvider.get();}看到我們倒數(shù)第二行了沒,在這里我們拿到teacher對(duì)象,設(shè)置它的成員變量student。ok,到這里我們就懂了,整個(gè)邏輯就全部通了,首先DaggerTeacherComponent.builder().build()執(zhí)行完在Student_Factory中創(chuàng)建好了student對(duì)象,然后在調(diào)用injectA(this)方法,將創(chuàng)建的student對(duì)象放置到teacher對(duì)象中的student屬性上。
OK,到這里我們就簡(jiǎn)單的了解了Dagger2的使用了,寫到這里篇幅已經(jīng)比較長(zhǎng)了,所以我打算用三篇文章來和大家吃透Dagger2,和大家一起從源碼入坑到跳坑,最后,還有一個(gè)很關(guān)鍵事忘說了:最近打算辭職回北京,有沒有大神同學(xué)推薦工作,帶帶小弟啊.
下一篇:Android -- 帶你從源碼角度領(lǐng)悟Dagger2入門到放棄(二)
?
總結(jié)
以上是生活随笔為你收集整理的Android -- 带你从源码角度领悟Dagger2入门到放弃(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全视曲面屏设计,三星S8又一次走在了行业
- 下一篇: android sina oauth2.