1.遇到的问题
相信使用过Dagger
开发Android应用的小伙伴会知道(如果你还不是很了解Daager
,可以先看我之前的一篇基本介绍:Dagger2使用攻略),我们会在Activity
或Fragment
的生命周期方法中执行成员注入。比如这样:
public class MyActivity extends Activity {
@Inject
Test test; @Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
DaggerActivityComponent
.builder()
.appComponent(((MyApplication)this.getApplication()).getAppComponent())
.build()
.inject(this);
test.getXX();
}
}123456789101112131415
但是有一些问题:
随着越来越多的这样代码块的复制粘贴,使得以后很难重构。
更重要的是,它要求注入类型( MyActivity )知道其注入器。 即使这是通过接口而不是具体类型完成的,它打破了依赖注入的核心原则:一个类不应该知道如何注入它。
那么我们怎么解决他呢?
2.解决问题
不用担心,Dagger2
在2.10版本为我们提供了解决的方案。 并在2.11版本中增加了@ContributesAndroidInjector
注解,使得我们的实现更加方便。具体变化可以查看这里
1.配置
首先将以下内容添加到您的build.gradle中:(在原先Dagger2的基础上添加)
dependencies {
compile 'com.google.dagger:dagger-android:2.11'
compile 'com.google.dagger:dagger-android-support:2.11'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'}12345
2.实现
为了更清楚的说明,我会举一个简单的例子使用新旧两种写法实现。
现在的场景是这样的,我要在一个页面中使用一个Login
对象,如下:
public class Login { private String name ; private String password ; public String getName() { return name;
} public void setName(String name) { this.name = name;
} public String getPassword() { return password;
} public void setPassword(String password) { this.password = password;
}
}123456789101112131415161718192021
假设初始化name
为小明
,password
为******
。我们使用Dagger
进行依赖注入,实现UserModule
。
@Modulepublic class UserModule {
@Provides
Login provideXiaoMingUser() {
Login xiaomin = new Login();
xiaomin.setPassword("******");
xiaomin.setName("小明"); return xiaomin;
}
}12345678910111213
相对应的UserComponent
如下
@Component(modules = {UserModule.class})public interface UserComponent { void inject(SecondActivity mActivity);
}1234
那么对应的SecondActivity
也就出来了。
public class SecondActivity extends AppCompatActivity {
@Inject
Login xiaoming; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
DaggerUserComponent.builder()
.userModule(new UserModule())
.build()
.inject(this);
xiaoming.getName(); //直接使用
}1234567891011121314151617
以上就是我们通常的使用方式,而SecondActivity
中就体现了我们一开始说到的问题。接下来我用新方法实现一遍。
1.首先我们在AppComponent
中统一注入AndroidSupportInjectionModule
@Singleton
@Component(modules = {
AppModule.class,
StorageModule.class,
BuildersModule.class,
AndroidSupportInjectionModule.class
})interface AppComponent extends AndroidInjector<MyApplication>{
@Component.Builder abstract class Builder extends AndroidInjector.Builder<MyApplication> {}
}12345678910111213
AndroidInjectionModule
源码如下 ,AndroidSupportInjectionModule
可以额外支持V4包下的Fragment
.
@Beta
@Modulepublic abstract class AndroidInjectionModule {
@Multibinds abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>> activityInjectorFactories();
@Multibinds
abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> fragmentInjectorFactories();
@Multibinds
abstract Map<Class<? extends Service>, AndroidInjector.Factory<? extends Service>> serviceInjectorFactories();
@Multibinds
abstract Map< Class<? extends BroadcastReceiver>, AndroidInjector.Factory<? extends BroadcastReceiver>> broadcastReceiverInjectorFactories();
@Multibinds
abstract Map< Class<? extends ContentProvider>, AndroidInjector.Factory<? extends ContentProvider>> contentProviderInjectorFactories(); private AndroidInjectionModule() {}
}12345678910111213141516171819202122232425262728
可以看到它可以帮我们将安卓中四大组件以及Fragment
进行绑定。
BuildersModule
是我为了统一管理依赖于AppComponent
的Module
添加的中间件。如下
@Module(subcomponents = {UserComponent.class})
public abstract class BuildersModule {
@Binds
@IntoMap
@ActivityKey(SecondActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindSecondActivityInjectorFactory(UserComponent.Builder builder);
}12345678910
有了BuildersModule
,我们之前的UserModule
保持不变,UserComponent
修改如下
@Subcomponent(modules = {UserModule.class})public interface UserComponent extends AndroidInjector<SecondActivity> {
@Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<SecondActivity> {}
}1234567
UserComponent
需继承自AndroidInjector
,在该子组件中含有一个抽象类Builder
,继承自AndroidInjector.Builder
,并由@Subcomponent.Builder
注解。注意:这里UserComponent
使用@Subcomponent
注解是为了使用AppComponent
中的AndroidSupportInjectionModule
.
接下来自定义MyApplication
继承DaggerApplication
public class MyApplication extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() { return DaggerAppComponent.builder().create(this);
}
}1234567
如果我们代码中已经有继承的父类Application
,则可以根据DaggerApplication
源码去实现对应接口。
最后一步Activity
继承DaggerAppCompatActivity
,在super.onCreate(savedInstanceState)
之前调用AndroidInjection.inject(this)
.
public class SecondActivity extends DaggerAppCompatActivity {
@Inject
Login xiaoming; @Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
xiaoming.getName(); //直接使用
}123456789101112
当然了,我们可以将AndroidInjection.inject(this)
封装进BaseActivity
,这样使用起来更酸爽。
有些人会觉得这写起来比之前麻烦多了,为了解决这个问题,在最近的2.11版中新增了@ContributesAndroidInjector
注解。有了它我们上面的UserComponent
可以不要了。(惊不惊喜,意不意外!)
@Modulepublic abstract class BuildersModule {
@ContributesAndroidInjector(modules = UserModule.class) abstract SecondActivity secondActivityInjector();
}123456
我们可以看一下自动生成的代码:
@Module(subcomponents = BuildersModule_SecondActivityInjector.SecondActivitySubcomponent.class)public abstract class BuildersModule_SecondActivityInjector {
private BuildersModule_SecondActivityInjector() {}
@Binds
@IntoMap
@ActivityKey(SecondActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
SecondActivitySubcomponent.Builder builder);
@Subcomponent(modules = UserModule.class) public interface SecondActivitySubcomponent extends AndroidInjector<SecondActivity> {
@Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<SecondActivity> {}
}
}12345678910111213141516
是不是一毛一样。。。不要怪我不早说,我也是为了大家可以更多的了解其中的细节。
3.工作原理
那么它是如何工作的?(前方一大堆代码乱入,不重要部分已去除)
我们首先从MyApplication
开始,在我们的父类DaggerApplication
帮我们实现了注入。
public abstract class DaggerApplication extends Application{
@Inject DispatchingAndroidInjector<Activity> activityInjector; @Override
public void onCreate() { super.onCreate();
injectIfNecessary();
} @ForOverride
protected abstract AndroidInjector<? extends DaggerApplication> applicationInjector(); private void injectIfNecessary() {
AndroidInjector<DaggerApplication> applicationInjector =
(AndroidInjector<DaggerApplication>) applicationInjector();
applicationInjector.inject(this); //这里注入
} @Override
public DispatchingAndroidInjector<Activity> activityInjector() { return activityInjector;
}
}123456789101112131415161718192021222324
注入时的具体内容
private Provider<AndroidInjector.Factory<? extends Activity>> bindAndroidInjectorFactoryProvider;private void initialize(final Builder builder) { //这里不就是我们使用@ContributesAndroidInjector生成的Subcomponent吗,在这里进行了实现
this.secondActivitySubcomponentBuilderProvider = new dagger.internal.Factory<
BuildersModule_SecondActivityInjector.SecondActivitySubcomponent.Builder>() {
@Override public BuildersModule_SecondActivityInjector.SecondActivitySubcomponent.Builder get() { return new SecondActivitySubcomponentBuilder();
}
};
this.bindAndroidInjectorFactoryProvider = (Provider) secondActivitySubcomponentBuilderProvider; //再将所有的Activity对应的SubcomponentBuilder存进MapProviderFactory
this.mapOfClassOfAndProviderOfFactoryOfProvider =
MapProviderFactory
.<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>builder(1)
.put(SecondActivity.class, bindAndroidInjectorFactoryProvider)
.build(); this.dispatchingAndroidInjectorProvider = DispatchingAndroidInjector_Factory.create(mapOfClassOfAndProviderOfFactoryOfProvider);
//将四大组件及Fragment全部放入 this.myApplicationMembersInjector = MyApplication_MembersInjector.create(dispatchingAndroidInjectorProvider);
}
@Override
public void inject(MyApplication arg0) {
myApplicationMembersInjector.injectMembers(arg0); //注入
}12345678910111213141516171819202122232425262728293031323334
private final class SecondActivitySubcomponentBuilder
extends BuildersModule_ContributeSecondActivityInjector.SecondActivitySubcomponent.Builder {
private UserModule userModule; private SecondActivity seedInstance; @Override
public BuildersModule_ContributeSecondActivityInjector.SecondActivitySubcomponent build() { if (userModule == null) { this.userModule = new UserModule();
} if (seedInstance == null) { throw new IllegalStateException(SecondActivity.class.getCanonicalName() + " must be set");
} return new SecondActivitySubcomponentImpl(this);
} @Override
public void seedInstance(SecondActivity arg0) { this.seedInstance = Preconditions.checkNotNull(arg0);
}
}12345678910111213141516171819202122
当我们在Activity
调用AndroidInjection.inject(this)
时,从Application
获取一个DispatchingAndroidInjector<Activity>
,并将您的activity传递给inject(activity)
public static void inject(Activity activity) {
Application application = activity.getApplication(); //获取DaggerApplication中的activityInjector
AndroidInjector<Activity> activityInjector =
((HasActivityInjector) application).activityInjector();
activityInjector.inject(activity);
}123456789
DispatchingAndroidInjector
通过AndroidInjector.Factory
创建AndroidInjector
,并将您的activity传递至SecondActivitySubcomponentImpl
中。
@Betapublic final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {
@Inject
DispatchingAndroidInjector(
Map<Class<? extends T>, Provider<AndroidInjector.Factory<? extends T>>> injectorFactories) {
this.injectorFactories = injectorFactories;
}
@CanIgnoreReturnValue public boolean maybeInject(T instance) {
Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
injectorFactories.get(instance.getClass()); if (factoryProvider == null) { return false;
}
@SuppressWarnings("unchecked")
AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get(); try {
AndroidInjector<T> injector =
checkNotNull(
factory.create(instance),//<-创建
"%s.create(I) should not return null.",
factory.getClass().getCanonicalName());
injector.inject(instance);//传递
return true;
} catch (ClassCastException e) {
}
}
@Override public void inject(T instance) {
boolean wasInjected = maybeInject(instance); if (!wasInjected) { throw new IllegalArgumentException(errorMessageSuggestions(instance));
}
}
}123456789101112131415161718192021222324252627282930313233343536373839404142
private final class SecondActivitySubcomponentImpl
implements BuildersModule_ContributeSecondActivityInjector.SecondActivitySubcomponent {
private Provider<Login> provideXiaoMingUserProvider; private MembersInjector<SecondActivity> secondActivityMembersInjector; private SecondActivitySubcomponentImpl(SecondActivitySubcomponentBuilder builder) { assert builder != null;
initialize(builder);
} @SuppressWarnings("unchecked") private void initialize(final SecondActivitySubcomponentBuilder builder) { this.provideXiaoMingUserProvider =
UserModule_ProvideXiaoMingUserFactory.create(builder.userModule); this.secondActivityMembersInjector =
SecondActivity_MembersInjector.create(
DaggerAppComponent.this.dispatchingAndroidInjectorProvider6,
DaggerAppComponent.this.dispatchingAndroidInjectorProvider3,
provideXiaoMingUserProvider);
} @Override
public void inject(SecondActivity arg0) {
secondActivityMembersInjector.injectMembers(arg0);//注入
}
}1234567891011121314151617181920212223242526272829
到此为止,它的工作流程就是这样。
细心地你其实这里会发现,我们依赖的Module
不需要我们像之前一样去一个一个创建好去设置了,会默认实现它的无参构造方法。当然在这个Module
中可以使用我们注入的Activity
。如果你之前的Module
有构造方法,试着去修改它、
4.其他
以上是以Activity
作为例子实现的,对于其他的四大组件以及Fragment
,使用起来大同小异。比如使用Fragment
,我们就将@ActivityKey
替换为@FragmentKey
。AndroidInjection.inject(this)
方法,在Fragment
的onAttach()
中的super.onAttach()
方法之前调用。当然如果你使用了@ContributesAndroidInjector
则可以不用去管@xxxKey
。
@Module(subcomponents = {TestFragmentComponent.class})public abstract class FragmentBuildersModule {
@Binds
@IntoMap
@FragmentKey(TestFragment.class) //<-- 这里
abstract AndroidInjector.Factory<? extends Fragment>
bindTopFragmentInjectorFactory(TestFragmentComponent.Builder builder);
}
@Subcomponent(modules = TestFragmentModule.class)public interface TestFragmentComponent extends AndroidInjector<TestFragment> {
@Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<TestFragment> {
}
}
@Modulepublic class TestFragmentModule {}public class TestFragment extends Fragment {
@Override public void onAttach(Activity activity) {
AndroidInjection.inject(this); //<--这里
super.onAttach(activity);
}
@Nullable
@Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment, container, false);
}
}1234567891011121314151617181920212223242526272829303132333435363738
我已经将这些代码上传到了我的Github,大家可以在分支dagger2.11
下查看新的写法。(主分支为旧写法,方便大家对比。)
参考
Dagger & Android官方文档
Android and Dagger 2.10 AndroidInjector