Dagger 2 有什么用?
android 中我们创建一个对象,往往是有着一大堆其他的依赖关系的,我就想要个A类,不好意思你得先提供B类和C类的实例参数。所以常常见到一个Activity中为了得到一个实例,前面个一大堆其他的对象获取,更烦的是偶尔可能某个类发生变动,这个时候跟这个类有关系的类也要跟着全部变动。基于这些场景,为了尽可能的降低耦合,削弱类之间的依赖关系带来的代码不易维护等后果,就产生了一些注解框架。
至于为什么用dagger2 ?
Dagger 2 analyzes these dependencies for you and generates code to help wire them together. While there are other Java dependency injection frameworks, many of them suffered limitations in relying on XML, required validating dependency issues at run-time, or incurred performance penalties during startup. Dagger 2 relies purely on using Java annotation processorsand compile-time checks to analyze and verify dependencies. It is considered to be one of the most efficient dependency injection frameworks built to date.
看了一下dagger2,就蛮记录一下。
@Inject @Component @Provides @Module。(基础几个的注解)
怎么说呢,这几个东西之间的关系就像,酒楼里面的关系。
@inject 就是客人需要的食品,
@Component 就是小二,
@Module就是仓库(囤着食材的地方)
@Provides 就是仓库里面的食材。
1.客人(Mainactivity)说:给老子来条烤鱼!(Fish 不能设置为private)
public class MainActivity extends AppCompatActivity {
@Inject
Fish fish;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
2.这个时候酒楼就会去找打被打上@inject的那条烤鱼。(如果多个重载方法,只能其中一个标注)
public class Fish {
private Vegetables vegetables;
private Fruit fruit;
@Inject
Fish(Vegetables vegetables, Fruit fruit) {
this.vegetables = vegetables;
this.fruit = fruit;
}
public String getMaterialName(){
return vegetables.getName()+"-->"+ fruit.getName();
}
}
3 然后酒楼一看我靠这条鱼还要两个食材搭配,就会进到仓库@Module去寻找被打上@Provides并且是烤鱼需要的食材。
3.1 如果没有参数,也就是不需要其他配料那就不用到仓库了也就是不用@Module、@Provides。
public class Apple extends Fruit {
@Override
public String getName() {
return "苹果嘛";
}
}
public class Lettuce extends Vegetables {
@Override
public String getName() {
return "生菜啊";
}
}
@Module
public class FruitModule {
@Provides
public Fruit getApple() {
return new Apple();
}
}
@Module
public class VegetablesModule {
@Provides
public Vegetables getLettuce() {
return new Lettuce();
}
}
3.2 如果酒楼压根就找不到这种鱼(鱼是来自第三方类库,我们无法对他的构造函数打上@Inject),这个时候?
3.2.1.新建鱼仓库:
@Module
public class FishModule {
@Provides
public Fish getFish(Vegetables vegetables, @FruitApple Fruit fruit){
return new Fish(vegetables,fruit);
}
}
3.2.2
FishComponent 需要多指定一个FishModule或者改用dependencies 也可以。
@Component(modules ={FishModule.class,FruitModule.class,VegetablesModule.class})
public interface FishComponent {
//将实例注入目标
void inject(MainActivity mainActivity);
}
4 酒楼拿着提供的两样食材之后,做好烤鱼后,小二@Component 将烤鱼送上。
@Component(modules ={FruitModule.class,VegetablesModule.class})
public interface FishComponent {
//自定义注入方法,将实例注入目标 (注入目标要有)
void inject(MainActivity mainActivity);
}
4 .动手解决(写这段代码前先rebuild 一下。DaggerFishComponent 是自动生成的 -->Dagger+你的component类名)
public class MainActivity extends AppCompatActivity {
@Inject
Fish fish;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//FruitModule 为无参构造函数时可用
DaggerFishComponent.create().inject(this);
//FruitModule 为有参构造函数时用
// //DaggerFishComponent.builder().fruitModule(new FruitModule()).build().inject(this);
Log.e("MainActivity","result is---->"+fish.getMaterialName());//生菜啊-->苹果嘛
//结果说明Fish是注入的,并且打出结果。
}
}
仅仅打了几个注解,鱼到底怎么生成的?
思路应该也是差不多,要得到这条鱼肯定得提供两个配菜。看下生成的代码:
@Provides 会生成对应的提供类。所以有FruitModule_GetAppleFactory、VegetablesModule_GetLettuceFactory 。假如FruitModule 还有其他的@Provides 就还会生成FruitModule_XXXFactory。
FruitModule_GetAppleFactory :可以看到我们可以通过creat获取该实例,然后get一apple对象(该类重写了Factory
VegetablesModule_GetLettuceFactory 也是一样的方式。@Inject 生成的Fish_Factor也是差不多。
public final class FruitModule_GetAppleFactory implements Factory {
private final FruitModule module;
public FruitModule_GetAppleFactory(FruitModule module) {
assert module != null;
this.module = module;
}
@Override
public Fruit get() {
return Preconditions.checkNotNull(
module.getApple(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory create(FruitModule module) {
return new FruitModule_GetAppleFactory(module);
}
}
这样鱼的材料凑齐,可以看到在@Component 生成的DaggerFishComponent类中,该类实现了FishComponent的inject。在我们调用build或者create(无参数module可用create)之后实现Fish的注入。
public final class DaggerFishComponent implements FishComponent {
private Provider getLettuceProvider;
private Provider getAppleProvider;
private Provider fishProvider;
private MembersInjector mainActivityMembersInjector;
private DaggerFishComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static FishComponent create() {
return builder().build();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.getLettuceProvider = VegetablesModule_GetLettuceFactory.create(builder.vegetablesModule);
this.getAppleProvider = FruitModule_GetAppleFactory.create(builder.fruitModule);
this.fishProvider = Fish_Factory.create(getLettuceProvider, getAppleProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(fishProvider);
}
@Override
public void inject(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
public static final class Builder {
private VegetablesModule vegetablesModule;
private FruitModule fruitModule;
private Builder() {}
public FishComponent build() {
if (vegetablesModule == null) {
this.vegetablesModule = new VegetablesModule();
}
if (fruitModule == null) {
this.fruitModule = new FruitModule();
}
return new DaggerFishComponent(this);
}
public Builder fruitModule(FruitModule fruitModule) {
this.fruitModule = Preconditions.checkNotNull(fruitModule);
return this;
}
public Builder vegetablesModule(VegetablesModule vegetablesModule) {
this.vegetablesModule = Preconditions.checkNotNull(vegetablesModule);
return this;
}
}
}
补:谷歌的官方示例中 @inject 也是可以注解方法的。(依赖this的时候,可以提供安全的this对象,他是在构造函数之后执行的)