写点什么

IOC 架构设计之 Dagger2 架构设计(三)

发布于: 2021 年 11 月 07 日

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


android {compileSdkVersion 23buildToolsVersion "23.0.0"


defaultConfig {applicationId "com.demo.zejun.repodragger2"minSdkVersion 15targetSdkVersion 23versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}}


dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])testCompile 'junit:junit:4.12'compile 'com.android.support:appcompat-v7:23.0.0'//添加(3)apt 'com.googl


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


e.dagger:dagger-compiler:2.0'//添加(4)compile 'com.google.dagger:dagger:2.0'}


第二步:User作为目标类中需要实例化的成员对象,给其构造函数添加@Inject标签:


public class User {


public String name;


@Injectpublic User() {name = "lizejun";}


public String getName() {return name;}}


第三步:声明Component


@Component()public interface OnlyInjectComponent {void inject(AnnotationActivity annotationActivity);}


第四步:在目标类中添加注解@Inject,并根据我们第 3 步中声明的Component,调用DaggerXXX方法来进行注入:


public class AnnotationActivity extends AppCompatActivity {


@Injectpublic User mUser;


@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_dragger2);//在第 3 步声明的 Component 接口或者抽象类的基础上,添加 Dagger 前缀。DaggerOnlyInjectComponent.builder().build().inject(this);}


}


上面这个例子有两个缺点:


  • 只能标记一个构造方法,因为如果标记两个以上,不知道要用哪一个构造提供实例。

  • 不能标记其它我们不能修改的类,例如第三方库。

  • 如果用@Inject标记的构造函数如果有参数,那么这个参数也需要其它地方提供依赖,而类似于String这些我们不能修改的类,只能用@Module中的@Provides来提供实例了。

四、采用@Module来提供依赖

采用@Module标记的类提供依赖是常规套路,@Module标记的类起管理作用,真正提供依赖实例靠的是@Provides标记的带返回类型的方法。第一步:和上面类似,我们定义一个依赖类,但是它的构造方法并不需要用@Inject标记:


public class Person {


private String name;


public Person() {this.name = "lizejun";}


public String getName() {return name;}}


第二步:我们需要定义一个@Module来管理这些依赖类的实例:


@Modulepublic class PersonDataModule {


@Providespublic Person providePerson() {return new Person();}}


第三步:定义一个@Component,它指向上面定义的@Module


@Component(modules = {PersonDataModule.class})public interface PersonInjectComponent {void inject(PersonInjectActivity injectActivity);}


第四步:在目标类中进行依赖注入


public class PersonInjectActivity extends Activity {


@InjectPerson mPerson;


@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);DaggerPersonInjectComponent.create().inject(this);System.out.println("Person name=" + mPerson.getName());}}


这里注入的方式有两种,一种是像上面这样的,它适合于PersonDataModule中只有一个无参的构造方法,否则我们需要这样调用:


DaggerPersonInjectComponent.builder().personDataModule(new PersonDataModule()).build().inject(this);

五、初始化依赖实例的步骤

  • 查找Module中是否存在创建该类型的方法(即@Component标记的接口中包含了@Module标记的Module类,如果没有则直接查找@Inject对应的构造方法)。

  • 如果存在创建类方法,则查看该方法是否有参数

  • 如果不存在参数,直接初始化该类的实例,一次依赖注入到此结束。

  • 如果存在参数,则从步骤 1 开始初始化每个参数。

  • 如果不存在创建类方法,则查找该类型的类中有@Inject标记的构造方法,查看构造方法是否有参数:

  • 如果不存在参数,则直接初始化该类实例,一次依赖注入到此结束。

  • 如果存在参数,则从步骤 1 开始初始化每个参数。

六、@Qualifier限定符

Dagger中,有一个已经定义好的限定符,@Name,下面我们也自己定义一个限定符:


@Qualifier@Retention(RetentionPolicy.RUNTIME)public @interface PeopleThreeQualifier {}


第一步:和前面类似,我们先定义一个需要实例化的依赖类:


public class People {


private int count;


public People() {count = 0;}


public People(int count) {this.count = count;}


public int getCount() {return count;}}


第二步:我定义一个DataModule,和前面不同的是,在它的provideXXX方法的注解中,我们添加了@Name(xxx)和自定义的注解PeopleThreePeople


@Modulepublic class PeopleDataModule {


@Provides@Named("Five People")People provideFivePeople() {return new People(5);}


@Provides@Named("Ten People")People provideTenPeople() {return new People(10);}


@Provides@PeopleThreeQualifierPeople provideThreePeople() {return new People(3);}}


第三步:定义Component


@Component(modules = PeopleDataModule.class)public interface PeopleInjectComponent {void inject(PeopleInjectActivity peopleInjectActivity);}


第四步:在目标类中进行依赖注入,在提供@Inject注解时,我们还需要声明和PeopleDataModule中对应的限定符,这样Dagger就知道该用那个函数来生成目标类中的依赖类实例:


public class PeopleInjectActivity extends Activity {


@Inject@Named("Five People")People mFivePeople;


@Inject@Named("Ten People")People mTenPeople;


@Inject@PeopleThreeQualifierPeople mThreePeople;


@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);DaggerPeopleInjectComponent.builder().peopleDataModule(new PeopleDataModule()).build().inject(this);System.out.println("Five People=" + mFivePeople.getCount() + ",Ten People=" + mTenPeople.getCount() + ", Three People=" + mThreePeople.getCount());}}

七、@Scope

@Scope的作用主要是在组织ComponentModule的时候起到一个提醒和管理的作用,在Dagger中,有一个默认的作用域@Singleton@Scope的作用是:Dagger2可以通过自定义Scope注解,来限定通过ModuleInject方式创建的类的实例的生命周期能够与目标类的生命周期相同。Scope的真正作用在与Component的组织:


  • 更好的管理Component之间的组织方式,不管是依赖方式还是包含方式,都有必要用自定的Scope注解标注这些Component,而且编译器会检查有依赖关系或包含关系的Component,若发现有Component没有用自定义Scope注解,则会报错。

  • 更好地管理ComponentModule之间地关系,编译器会检查Component管理的Module,若发现Component的自定义Scope注解与Module中的标注创建类实例方法的注解不一样,就会报错。

  • 提高程序的可读性。


下面是一个使用@Singleton的例子:第一步:定义需要实例化的类:


public class AnSingleObject {


private String objectId;


public AnSingleObject() {objectId = toString();}


public String getObjectId() {return objectId;}}


第二步:定义DataModule,在它的provideXXX方法,提供了@Singletion注解:


@Modulepublic class AnSingleObjectDataModule {


@Provides@SingletonAnSingleObject provideAnSingleObject() {return new AnSingleObject();}}


第三步:定义Component,和前面不同的是,需要给这个Component添加@Singleton注解:


@Component(modules = {AnSingleObjectDataModule.class})@Singletonpublic abstract class AnSingleObjectInjectComponent {


private static AnSingleObjectInjectComponent sInstance;


public abstract void inject(AnSingleObjectInjectActivity anSingleObjectInjectActivity);


public static AnSingleObjectInjectComponent getInstance() {if (sInstance == null) {sInstance = DaggerAnSingleObjectInjectComponent.create();}return sInstance;}}


第四步:在目标类中进行依赖注入,每次启动Activity的时候,我们可以发现打印出来的hash值都是相同的:


public class AnSingleObjectInjectActivity extends Activity {


@InjectAnSingleObject object;


@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);AnSingleObjectInjectComponent.getInstance().inject(this);System.out.println("AnSingleObject id=" + object.getObjectId());}}

八、组织Component

Component有三种组织方式:


  • 依赖:一个Component依赖一个或多个Component,采用的是@Componentdependencies属性。

  • 包含:这里就用到了@SubComponent注解,用它来标记接口或者抽象类,表示它可以被包干。一个Component可以包含一个或多个Component,而且被包含的Component还可以继续包含其它的Component

  • 继承:用一个Component继承另外一个Component

九、Google官方框架分析

评论

发布
暂无评论
IOC架构设计之Dagger2架构设计(三)