Dagger2的理解和使用
Android:dagger2让你爱不释手-基础依赖注入框架篇
Android:dagger2让你爱不释手-重点概念讲解、融合篇
Android:dagger2让你爱不释手-终结篇
Dagger 2 完全解析(一),Dagger 2 的基本使用与原理
Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等
Dagger 2 完全解析(三),Component 的组织关系与 SubComponent
Dagger 2 完全解析(四),Android 中使用 Dagger 2
Dagger 2 完全解析(五),Kotlin 中使用 Dagger 2
Dagger 2 完全解析(六),dagger.android 扩展库的使用
1、Component的使用
作为桥连接依赖和被依赖对象。
每一个Component都会创建一个对应的DaggerComponent
@Inject注解的构造函数会创建对应类的Factory,用于实例化该类
/** * 药物 */public class Medicine { @Inject public Medicine() { } public void treat() { LogUtil.e("开始治疗"); }}
/** * 注射器 */@Componentpublic interface Injector { //注射动作,指定病患 void inject(MainActivity mainActivity);}
/** * 病患 */public class MainActivity extends AppCompatActivity { @Inject Medicine mMedicine; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //口服 Medicine medicine = new Medicine(); medicine.treat(); //打针 DaggerInjector.create().inject(this); mMedicine.treat(); }}
2、Module使用场景
1、没有构造函数
2、有参构造
3、三方库的类
每一个@Provides注解的方法都会创建一个Factory用来提供实例化对象给DaggerComponent使用。
@Provides注解的方法所需要的参数会优先从Module的其他provide中取。
@Modulepublic class ModuleClass { @Provides Gson provideGson() { return new Gson(); }}
@Component(modules = ModuleClass.class)public interface ComponentClass { void inject(MainActivity2 mainActivity);}
public class MainActivity2 extends AppCompatActivity { @Inject Gson mGson; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerComponentClass.create().inject(this); String s = mGson.toJson(new Medicine()); LogUtil.e(s); }}
3、@Scope作用域
@Scope是一个元注解,用于注解自定义注解,可以确定注入的实例的生命周期,并在声明周期内保持实例唯一。使用时Module 中 provide 方法中的 Scope 注解必须和 与之绑定的 Component 的 Scope 注解必须一样,否则作用域不同会导致编译时会报错。
作用域的原理,其实是让生成的依赖实例的生命周期与 Component 绑定,Scope 注解并不能保证生命周期,要想保证赖实例的生命周期,需要确保 Component 的生命周期。
@Singleton是通过@Scope定义的一个新的注解,能够使同一个Component中的对象保持唯一,保持唯一的条件是通过@Scope标记的注解相同。
@Singleton并没有创建单例的能力,起作用为
1、保证Component和Module是匹配的。
2、代码可读性。
以页面划分component,一个页面一个component,但这并不是一定的,有时候多页面会共用一个component,因为它们需要的参数一致。
一个全局component用来管理管理整个App的全局类实例。
@Scope //注明是Scope @Documented //标记在文档 @Retention(RUNTIME) // 运行时级别public @interface Singleton {}
@Modulepublic class FactoryModule { @Provides Gson provideGson() { LogUtil.e("创建Gson对象"); return new Gson(); }}
@Component(modules = FactoryModule.class)public interface BridgeComponent { Gson getGson();}
public class App extends Application { public static BridgeComponent sBridgeComponent; @Override public void onCreate() { super.onCreate(); sBridgeComponent = DaggerBridgeComponent.create(); }}
@Modulepublic class ActivityModule { @Singleton @Provides Person5 providesPersonWithString() { return new Person5("xls"); }}
@Singleton@Component(dependencies = BridgeComponent.class, modules = ActivityModule.class)public interface ActivityComponent { void inject(MainActivity3 mainActivity);}
public class MainActivity3 extends AppCompatActivity { @Inject Person5 mPerson5; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerActivityComponent.builder().bridgeComponent(App.sBridgeComponent).activityModule(new ActivityModule()).build().inject(this); Gson gson = App.sBridgeComponent.getGson(); LogUtil.e(gson.toJson(mPerson5)); }}
4、有参构造
MainModule -->providesPerson()中new Person(context)不能直接使用this.context,Module中查找返回Context的方法,并注入。此场景默认调用providesContext方法获取context。
public class Person { public String name = "张三"; public int age = 23; private Context context; public Person(Context context) { LogUtil.e("a person created with context:" + context); }}
@Modulepublic class MainModule { private Context context; public MainModule(Context context) { this.context = context; } @Provides public Context providesContext() { return this.context; } @Provides public Person providesPerson(Context context) { LogUtil.e("person from module"); return new Person(context); }}
@Component(modules = MainModule.class)public interface MainComponent { void inject(MainActivity4 mainActivity4);}
public class MainActivity4 extends AppCompatActivity { @Inject Person mPerson; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainComponent.builder().mainModule(new MainModule(getApplicationContext())).build().inject(this); String s = App.getInstance().mGson.toJson(mPerson); LogUtil.e(s); }}
5、自定义标记、限定符
用于区分同类的不同依赖
public class Person5 { public String name = "张三"; public int age = 23; public Context context; public Person5(Context context) { this.context = context; LogUtil.e("a person created with context:" + context); } public Person5(String name) { this.name = name; LogUtil.e("a person created with name:" + name); }}
@Modulepublic class MainModule5 { private Context context; public MainModule5(Context context) { this.context = context; } @Provides public Context providesContext() { return this.context; } // @Named("context") @PersonForContext @Provides public Person5 providesPersonWithContext(Context context) { return new Person5(context); } // @Named("string") @PersonForName @Provides public Person5 providesPersonWithName() { return new Person5("yxm"); }}
@Component(modules = MainModule5.class)public interface MainComponent5 { void inject(MainActivity5 mainActivity5);}
public class MainActivity5 extends AppCompatActivity { // @Named("string") @PersonForName @Inject Person5 p1; // @Named("context") @PersonForContext @Inject Person5 p2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainComponent5.builder().mainModule5(new MainModule5(getApplicationContext())).build().inject(this); String s1 = App.getInstance().mGson.toJson(p1); LogUtil.e(s1); //java.lang.SecurityException: Can not make a java.lang.reflect.Method constructor accessible// String s2 = App.getInstance().mGson.toJson(p2);// LogUtil.e(s2); }}
@Qualifier // 关键词@Retention(RetentionPolicy.RUNTIME) // 运行时仍可用public @interface PersonForContext { // Context 对象的注解}
@Qualifier@Retention(RetentionPolicy.RUNTIME)public @interface PersonForName { // name 对象的注解}
6、Provider、Lazy
沿用demo5部分文件
@Modulepublic class MainModule5 { private Context context; public MainModule5(Context context) { this.context = context; } @Provides public Context providesContext() { return this.context; } // @Named("context") @PersonForContext @Provides public Person5 providesPersonWithContext(Context context) { return new Person5(context); } // @Named("string") @PersonForName @Singleton @Provides public Person5 providesPersonWithName() { return new Person5("yxm"); }}
@Singleton@Component(modules = MainModule5.class)public interface MainComponent5 { void inject(MainActivity5 mainActivity5);}
public class MainActivity5 extends AppCompatActivity { // @Named("string") @PersonForName @Inject Person5 p1; @PersonForName @Inject Provider providerPerson; // @Named("context") @PersonForContext @Inject Lazy lazyPerson; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerMainComponent5.builder().mainModule5(new MainModule5(getApplicationContext())).build().inject(this); Person5 person5 = lazyPerson.get();// 调用该方法时才会去创建Person,以后每次调用获取的是同一个对象 Person5 person6 = lazyPerson.get(); Person5 person7 = providerPerson.get();// 调用该方法时才回去创建Person1,以后每次调用都会重新加载Module中的具体方法,根据Module中的实现,可能相同,可能不相同。加@Singletom注解,创建一次 Person5 person8 = providerPerson.get(); String s1 = App.getInstance().mGson.toJson(p1); LogUtil.e(s1); //java.lang.SecurityException: Can not make a java.lang.reflect.Method constructor accessible// String s2 = App.getInstance().mGson.toJson(p2);// LogUtil.e(s2); }}
总结
1、将实例化操作抽离出来,达到解耦的效果
2、单例无需考虑线程是否安全
更多相关文章
- Ubuntu adb devices : no permissions 解决方法
- Android 注解指南
- Android建立对话框基本的几种方法
- 2种自定义android标题栏titleBar的方法
- Android Environment 的作用以及常用的方法
- Android Studio 中方法数65536 或超过64K的解决方案
- Android SDK使用迅雷下载方法