目录
3.让dagger知道从哪儿获取依赖,注入依赖到哪儿:构造方法提供依赖
3.让dagger知道从哪儿获取依赖,注入依赖到哪儿:Module类提供依赖
前置:
依赖倒置原则、控制反转(Inversion of Control)、依赖注入(Dependency Injection) 有一定的了解。
依赖倒置:高层不依赖低层而依赖抽象,抽象不依赖实现类。换言之,解耦具体实现,提升扩展性。
控制反转:降低类与类耦合度。包括:依赖注入和依赖查找两种实现方式。
依赖注入:不直接在需要依赖的地方new创建依赖,将依赖部分与逻辑分离、解耦。
几个明显的坑:
- Component inject(container c) 容器必须传入与你实际调用inject相同的类。也就是说不能c传入BaseActivity,实际调用在XActivity。
- 一个容器不能注入多个相同依赖,或者用@qualifier注明不同Provides。
- 很多注解都需要配对使用,否则报错,特别注意。
三种常用的依赖注入方式:
A依赖B。其实三种方式平时也在用,只是没有特别去关注。
构造器注入:
public class InjectionA {
private B b;
public InjectionA(B b) {
this.b = b;
}
}
setter方法注入:
public class InjectionA {
private B b;
public void setB(B b) {
this.b = b;
}
}
接口注入:
interface Inject{
void inject(B b);
}
public class InjectionA implements Inject{
private B b;
@Override
public void inject(B b) {
this.b = b;
}
}
Dagger简单注入:
1.依赖创建:构造方法提供依赖
package com.fengzhen.dagger;
import javax.inject.Inject;
public class User {
String name;
// 提供依赖
@Inject
public User() {
this.name = "张三";
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
1.依赖创建:Module类提供依赖
package com.fengzhen.dagger;
public class User2 {
String name;
public User2(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.fengzhen.dagger;
import dagger.Module;
import dagger.Provides;
@Module
public class ActivityModule {
@Provides
User2 provider(){
return new User2("李四");
}
}
2.依赖注入位置:属性注入 User注入
package com.fengzhen.dagger;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
private TextView mTV;
private Button mBtn;
// 哪里需要依赖?
@Inject
User mUser;
@Inject
User2 mUser2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTV = (TextView) findViewById(R.id.tv);
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mTV.setText(/*mUser.getName() + */mUser2.getName());
}
});
DaggerActivityComponet.create().inject(this);
}
}
2.依赖注入位置:方法注入 User2注入
不常用,一般用于需要this初始化的情况。
package com.fengzhen.dagger;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity {
private TextView mTV;
private Button mBtn;
// 哪里需要依赖?
@Inject
User mUser;
User2 mUser2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("fengzhen", "onCreate: ==onCreate方法被调用");
setContentView(R.layout.activity_main);
mTV = (TextView) findViewById(R.id.tv);
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mTV.setText(mUser.getName() + mUser2.getName());
}
});
DaggerActivityComponet.create().inject(this);
}
@Inject
public void setmUser2(User2 mUser2) {
Log.i("fengzhen", "setmUser2: ==set方法被调用");
this.mUser2 = mUser2;
}
}
3.让dagger知道从哪儿获取依赖,注入依赖到哪儿:构造方法提供依赖
package com.fengzhen.dagger;
import dagger.Component;
// 如何将依赖注入给对象
@Component()
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
3.让dagger知道从哪儿获取依赖,注入依赖到哪儿:Module类提供依赖
这里@Componet传入了提供依赖的Class
package com.fengzhen.dagger;
import dagger.Component;
// 如何将依赖注入给对象
@Component(modules = ActivityModule.class)
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
4.生成的代码
生成路径:dagger2demo/build/generated/source/apt/debug/
User_Factory: 构造方法使用@Inject生成,静态工厂创建依赖实例。
ActivityModule_ProviderFactory: 根据Module类静态工厂创建依赖实例。
MainActivity_membersInjector: 拿到创建的依赖注入需要依赖的位置。
DaggerActivityComponet:实现ActivityComponet接口,实现具体的关联逻辑。
关键字
@Inject
@Target({ METHOD, CONSTRUCTOR, FIELD }) @Retention(RUNTIME) @Documented public @interface Inject {}
1.方法上
类似方法注入,构造器执行后调用此方法。
2.构造器上
提供依赖/注入依赖,视具体情况定。
3.属性上
最常用的属性注入。
@Componet 单独依赖(modules)
@Retention(RUNTIME) @Target(TYPE) @Documented public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies() default {}; @Target(TYPE) @Documented @interface Builder {} }
void inject()
指定注入目标,查找@Inject注解,注入对象。
modules
传入Module方式的提供依赖类。
@Module、@Provides
@Module表明该类可以提供依赖,@Provides代表了具体提供不同依赖的方法。
@Named
提供相同依赖的不同实例,用来标记类别。
@Module
public class ActivityModule {
@Provides
@Named("user2")
IUser provider(){
return new User2("李四");
}
@Provides
@Named("user1")
IUser providerUser(){
return new User("张三");
}
}
// 哪里需要依赖?
@Inject
@Named("user1")
IUser mUser;
@Inject
public void setmUser2(@Named("user2") IUser mUser2) {
Log.i("fengzhen", "setmUser2: ==set方法被调用");
this.mUser2 = mUser2;
}
@Qualifier
功能类似于@named,用来自定义注解,实现区分的效果。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface AUser {}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface AUser2 {}
@Module
public class ActivityModule {
@Provides
// @Named("user2")
@AUser2
IUser provider(){
return new User2("李四");
}
@Provides
// @Named("user1")
@AUser
IUser providerUser(){
return new User("张三");
}
}
// 哪里需要依赖?
@Inject
// @Named("user1")
@AUser
IUser mUser;
@Inject
public void setmUser2(/*@Named("user2")*/@AUser2 IUser mUser2) {
Log.i("fengzhen", "setmUser2: ==set方法被调用");
this.mUser2 = mUser2;
}
@Componet 嵌套依赖(dependencies)
已经了解了 module 的使用。dependencies可以将Componet相互嵌套起来使用。
将整个流程代码贴一次。省略IUser、User、User2、AUser、AUser2。
Store
package com.fengzhen.dagger.subcomponent;
import com.fengzhen.dagger.IUser;
public class Store {
IUser user;
public Store(IUser user) {
this.user = user;
}
public String getUserName() {
return user.getName();
}
}
IUser依赖提供:UserModule
package com.fengzhen.dagger;
import dagger.Module;
import dagger.Provides;
@Module
public class UserModule {
@Provides
@AUser2
IUser provider() {
return new User2("User2李四");
}
@Provides
@AUser
IUser providerUser() {
return new User("User张三");
}
}
IUser注解组件:IUserComponet
@Component(modules = UserModule.class)
public interface IUserComponet {
@AUser
IUser getUser();
@AUser2
IUser getUser2();
}
Store依赖提供:StoreModule
@Module
public class StoreModule {
@Provides
Store provideStore(@AUser2 IUser user){
return new Store(user);
}
}
Store注解组件:StoreComponet
这里StoreComponet依赖于UserComponet,写法如下:
@Component(modules = StoreModule.class,
dependencies = IUserComponet.class)
public interface StoreComponent {
Store getStore();
}
Container指定组件:ActivityComponet
如果Activity仍需要注入IUser,取消注释即可。
// 如何将依赖注入给对象
@Component(/*modules = UserModule.class,*/
dependencies = StoreComponent.class)
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
Container注入
DaggerActivityComponet.builder()
.storeComponent(DaggerStoreComponent.builder()
.iUserComponet(DaggerIUserComponet.create())
.build())
.build()
.inject(this);
即。每个Bean、Module、Componet为整体,缺一不可,可通过dependencies将组与组连接嵌套在一起。
@Subcomponet 嵌套依赖
@Componet 嵌套依赖的更加紧密的实现方式。只需要修改Componet实现
@Component(modules = UserModule.class)
public interface IUserComponet {
//
// @AUser
// IUser getUser();
//
// @AUser2
// IUser getUser2();
StoreComponent plus(StoreModule storeModule);
}
//@Component(modules = StoreModule.class,
// dependencies = IUserComponet.class)
@Subcomponent(modules = StoreModule.class)
public interface StoreComponent {
// Store getStore();
ActivityComponet plus();
}
// 如何将依赖注入给对象
//@Component(modules = UserModule.class,
// dependencies = StoreComponent.class)
@Subcomponent
public interface ActivityComponet {
void inject(MainActivity mainActivity);
}
Container注入
DaggerIUserComponet.create()
.plus(new StoreModule())
.plus()
.inject(this);
两者区别:
- dependencies能单独使用,而Subcomponent必须由Component调用方法获取
- Container使用差别,dependencies使用creat(),Subcomponent使用new。
- dependencies可将低层User也进行注入,Subcomponent联系紧密不能注入。
@Module + @Binds
@Binds和@Provides的功能类似,不同于:
@Provides 注解可以提供第三方类和接口的注入;
@Binds 注解只能提供接口的注入,且只能注解抽象方法。
Module:(这里重写了一遍嵌套的过程,所以类名不一样了)
@Module
public abstract class StoreModule {
// @Provides
// IStore provideStore(Customer customer){
// return new Store(customer);
// }
// 传入参数为具体的返回接口(IStore)的实现类
@Binds
abstract IStore provideStore(Store store);
}
Store:依赖类,构造方法@Inject,通过Component依赖传入Customer。
public class Store implements IStore {
Customer customer;
@Inject
public Store(Customer customer) {
this.customer = customer;
}
public String getName(){
return customer.name;
}
}
剩下的就完全和前面的一模一样。
@Singleton
实现依赖单例。每次都提供同一个实例,实现与Componet同生命周期的单例。
且必须配对使用,Module和Componet必须配对使用否则报错。
@Scope @Documented @Retention(RUNTIME) public @interface Singleton {}
DaggerActivityComponet.create().inject(this);
StoreComponent component = DaggerStoreComponent.create();
Store containerA = new Store();
Store containerB = new Store();
component.inject(containerA);
component.inject(containerB);
Log.i("fengzhen", "onCreate: " + mUser2.toString());
Log.i("fengzhen", "onCreate: " + containerA.user.toString());
Log.i("fengzhen", "onCreate: " + containerB.user.toString());
分别创建两个Componet,分别注入Activity和两个Store,打印结果可见:
两个Store的User是一个实例,且与Activity的User不是一个实例。
@Scope
@Singleton是@Scope的一种,也是官方给出来的,我们也可以自定义Scope实现我们想要的生命周期。
定义一个App全局单例。
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface AppLifecycle {
}
package com.fengzhen.dagger;
import android.app.Application;
import com.fengzhen.dagger.scope.ConfigComponet;
import com.fengzhen.dagger.scope.DaggerConfigComponet;
public class App extends Application {
private static ConfigComponet mConfigComponet;
@Override
public void onCreate() {
super.onCreate();
// 与App生命周期进行绑定,实现全App单例
mConfigComponet = DaggerConfigComponet.create();
}
/**
* 具体容器进行自定义注入
*/
public static ConfigComponet getConfigComponet() {
return mConfigComponet;
}
}
Map
注入Map类型数据,目前支持int、string、long、class、自定义枚举。
Module:
@Provides
@IntoMap
@IntKey(1)
int provideUser111(){
return 111;
}
@Provides
@IntoMap
@StringKey("user222")
int provideUser222(){
return 222;
}
Container:
@Inject
Map<Integer, Integer> mSet;
private void inject() {
CollectComponet collectComponet = DaggerCollectComponet.create();
collectComponet.inject(this);
Log.i("fengzhenl", "inject: " + mSet.toString());
}
Set
Module:
@Provides
@IntoSet
@Singleton
User2 provideUser2() {
return new User2("multi张三");
}
@Provides
@Singleton
@ElementsIntoSet
Set<User2> provideUser2Set() {
return new HashSet<>(Arrays.asList(new User2("multi李四"), new User2("multi王五")));
}
Container:
@Inject
Set<User2> mUserSet;
private void inject() {
CollectComponet collectComponet = DaggerCollectComponet.create();
collectComponet.inject(this);
Log.i("fengzhenl", "inject: " + mUserSet.toString());
}
也可以通过此方式获取:
Component:
@Singleton
@Component(modules = UserMultiModule.class)
public interface CollectComponet {
void inject(MainActivity activity);
Set<User2> getUsers();
}
Container:
@Inject
Set<User2> mUserSet;
private void inject() {
CollectComponet collectComponet = DaggerCollectComponet.create();
collectComponet.inject(this);
Set<User2> users = collectComponet.getUsers();
Log.i("fengzhenl", "inject: " + mUserSet.toString());
Log.i("fengzhenl", "inject: " + users.toString());
}