Android依赖注入框架之Dagger2
主页: https://github.com/google/dagger
历史
*
Dagger1是由Square公司受到Guice(https://github.com/google/guice)启发创建的依赖注入框架.
*
Dagger2是Dagger1(https://github.com/square/dagger)的分支,由谷歌开发.该项目受到了Auto项目(https://github.com/google/auto)的启发
优点
* 没有使用反射,图的验证、配置和预先设置都在编译的时候执行
*
容易调试,完全具体地调用提供和创建的堆栈
*
更高的性能,谷歌声称他们提高了13%的处理性能
*
代码混淆,使用派遣方法,就如同自己写的代码一样
配置:
dependencies {
api 'com.google.dagger:dagger:2.15'
annotationProcessor 'com.google.dagger:dagger-compiler:2.15'
}
核心注解:
@Inject:
有两个作用:
1是在需要依赖的类(目标类,即宿主)中标记成员变量告诉Dagger这个类型的变量需要一个实例对象。
2是标记类中的构造方法(一般为无参构造方法)告诉Dagger我可以提供这种类型的依赖实例。
@Provides:
@Provides:
用来提供依赖实例,对方法进行注解,且都是有返回类型的。用来告诉Dagger我们想如何创建并提供该类型的依赖实例(一般会在方法中new出实例)。用@Provides标记的方法,谷歌推荐采用provide为前缀,必须用@Module注解的类中,方法所需的参数也需要以方法的形式返回提供。
@Module:
@Module:
用来标记类(一般类名以Module结尾)。Module主要的作用是用来集中管理@Provides标记的方法。我们定义一个被@Module注解的类,Dagger就会知道在哪里找到依赖来满足创建类的实例。modules的一个重要特征是被设计成区块并可以组合在一起供@Component所注解的类使用。
@Component:
@Component:
用来标记接口或者抽象类(一般以Component结尾),是@Inject(指第一个作用)和@Module之间的桥梁,主要职责是把二者组合在一起,Module中的实例对象必须在Component中暴露出来才能供之后使用。所有的components都可以通过它的modules知道它所提供的依赖范围。一个Component可以依赖一个或多个Component,并拿到被依赖Component暴露出来的实例,Component的dependencies属性就是确定依赖关系的实现。
@Scope:
@Scope:
作用域,Dagger2通过自定义注解来限定作用域,有一个默认的作用域注解@Singleton,通常在Android中用来标记在App整个生命周期内存活的实例。也可以自定义一个@PerActivity、@PerFragment注解,用来表明实例生命周期与Activity、Fragment一致。我们可以自定义作用域的粒度(比如@PerUser等等)。
代码如下:
package com.loaderman.dagger2; import android.app.Application; /* Provide 如果是单例模式 对应的Compnent 也要是单例模式 inject(Activity act) 不能放父类 即使使用了单利模式,在不同的Activity 对象还是不一样的 依赖component, component之间的Scoped 不能相同 子类component 依赖父类的component ,子类component的Scoped 要小于父类的Scoped,Singleton的级别是Application 多个Moudle 之间不能提供相同的对象实例 Moudle 中使用了自定义的Scoped 那么对应的Compnent 使用同样的Scoped * */ public class MyApp extends Application { private static AppComponent appComponent; @Override public void onCreate() { super.onCreate(); appComponent = DaggerAppComponent.builder().build(); } public static AppComponent getAppComponent() { return appComponent; } }
package com.loaderman.dagger2; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import javax.inject.Scope; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Scope @Documented @Retention(RUNTIME) public @interface ActivityScoped { }
package com.loaderman.dagger2; import javax.inject.Singleton; import dagger.Component; //全局单例 @Singleton @Component(modules = AppModule.class) public interface AppComponent { AppApi getAppApi(); }
package com.loaderman.dagger2; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; @Module public class AppModule { @Singleton @Provides AppApi providerAppApi() { return new AppApi(); } }
package com.loaderman.dagger2; import dagger.Component; //第一步 添加@Component //第二步 添加module //注意:如果 moudule所依赖的Comonent 中有被单例对象,那么Conponnent也必须是单例对象 //注意:子类component 依赖父类的component ,子类component的Scoped 要小于父类的Scoped,Singleton的级别是Application @ActivityScoped @Component(modules ={MainModule.class} ,dependencies = AppComponent.class) public interface MainComponent { //第三步 写一个方法 绑定Activity /Fragment void inject(MainActivity activity); void inject(TestActivity activity); }
package com.loaderman.dagger2; import javax.inject.Named; import dagger.Module; import dagger.Provides; // @Named注解 可实例化对象不同 //第一步 添加@Module 注解 @Module public class MainModule { //第二步 使用Provider 注解 实例化对象 @Provides User providerUserA() { return new User(); } @Named("B") @Provides User providerUserB() { return new User(); } //单例模式 @ActivityScoped @Provides MainApi providerMainApi() { return new MainApi(); } @Provides TestA providerTestA() { return new TestA(); } }
package com.loaderman.dagger2; public class AppApi { }
package com.loaderman.dagger2; public class MainApi { }
package com.loaderman.dagger2; public class TestA { }
package com.loaderman.dagger2; import javax.inject.Inject; public class TestB { @Inject public TestB() { } }
package com.loaderman.dagger2; public class User { }
package com.loaderman.dagger2; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import javax.inject.Inject; import dagger.Lazy; public class MainActivity extends AppCompatActivity { @Inject User userA; @Inject User userB; @Inject MainApi apiA; @Inject MainApi apiB; @Inject AppApi appApiA; @Inject AppApi appApiB; @Inject Lazy<TestA> testALazy;//懒加载机 @Inject TestB testB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainComponent .builder() //这里传入appComponent实例,我们可以通过application获取到 .appComponent(MyApp.getAppComponent()) .build() .inject(this); System.out.println("-----------------输出--------------------------"); System.out.println("userA" + userA); System.out.println("userB" + userB); System.out.println("userA==userB? :" + (userA == userB)); //测试单例 System.out.println("apiA" + apiA); System.out.println("apiB" + apiB); System.out.println("apiA==apiB? :" + (apiA == apiB)); System.out.println("appApiA" + appApiA); System.out.println("appApiB" + appApiB); System.out.println("appApiA==appApiB? :" + (appApiA == appApiB)); System.out.println("testALazy" + testALazy); TestA testA = testALazy.get(); System.out.println("testA" + testA); //注解构造函数,创建实例 System.out.println("testB" + testB); } public void go(View view) { startActivity(new Intent(this, TestActivity.class)); } }
package com.loaderman.dagger2; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import javax.inject.Inject; public class TestActivity extends AppCompatActivity { @Inject MainApi mainApi; @Inject AppApi api; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); DaggerMainComponent.builder() //这里传入appComponent实例,我们可以通过application获取到 .appComponent(MyApp.getAppComponent()) .build() .inject(this); System.out.println("-----------------输出--------------------------"); System.out.println("mainApi"+mainApi); System.out.println("api"+api); } }
日志:
12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: -----------------MainActivity输出-------------------------- 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: userAcom.loaderman.dagger2.User@198c9ed7 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: userBcom.loaderman.dagger2.User@2a8f53c4 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: userA==userB? :false 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: apiAcom.loaderman.dagger2.MainApi@182492ad 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: apiBcom.loaderman.dagger2.MainApi@182492ad 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: apiA==apiB? :true 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: appApiAcom.loaderman.dagger2.AppApi@b1159e2 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: appApiBcom.loaderman.dagger2.AppApi@b1159e2 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: appApiA==appApiB? :true 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: testALazydagger.internal.DoubleCheck@26925173 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: testAcom.loaderman.dagger2.TestA@330fe830 12-26 15:16:03.000 15389-15389/com.loaderman.dagger2 I/System.out: testBcom.loaderman.dagger2.TestB@1ba4aca9
12-26 15:16:29.560 15389-15389/com.loaderman.dagger2 I/System.out: -----------------TestActivity输出--------------------------
12-26 15:16:29.560 15389-15389/com.loaderman.dagger2 I/System.out: mainApicom.loaderman.dagger2.MainApi@16e6aef2
12-26 15:16:29.560 15389-15389/com.loaderman.dagger2 I/System.out: apicom.loaderman.dagger2.AppApi@b1159e2
最后,关注【码上加油站】微信公众号后,有疑惑有问题想加油的小伙伴可以码上加入社群,让我们一起码上加油吧!!!