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(); } }
但是有一些问题:
- 随着越来越多的这样代码块的复制粘贴,使得以后很难重构。
- 更重要的是,它要求注入类型( 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' }
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; } }
假设初始化name为小明,password为。我们使用Dagger进行依赖注入,实现UserModule。
@Module public class UserModule {
@Provides Login provideXiaoMingUser() { Login xiaomin = new Login(); xiaomin.setPassword(""); xiaomin.setName("小明"); return xiaomin; } }
相对应的UserComponent如下
@Component(modules = {UserModule.class}) public interface UserComponent { void inject(SecondActivity mActivity); }
那么对应的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(); //直接使用 }
以上就是我们通常的使用方式,而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> {
} }
AndroidInjectionModule源码如下 ,AndroidSupportInjectionModule可以额外支持V4包下的Fragment.
@Beta @Module public 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() {
} }
可以看到它可以帮我们将安卓中四大组件以及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); }
有了BuildersModule,我们之前的UserModule保持不变,UserComponent修改如下
@Subcomponent(modules = {UserModule.class}) public interface UserComponent extends AndroidInjector<SecondActivity> {
@Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<SecondActivity> {
} }
UserComponent需继承自AndroidInjector,在该子组件中含有一个抽象类Builder,继承自AndroidInjector.Builder,并由@Subcomponent.Builder注解。注意:这里UserComponent使用@Subcomponent注解是为了使用AppComponent中的AndroidSupportInjectionModule.
接下来自定义MyApplication继承DaggerApplication
public class MyApplication extends DaggerApplication {
@Override protected AndroidInjector
applicationInjector() { return DaggerAppComponent.builder().create(this); } }
如果我们代码中已经有继承的父类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(); //直接使用 }
当然了,我们可以将AndroidInjection.inject(this)封装进BaseActivity,这样使用起来更酸爽。
有些人会觉得这写起来比之前麻烦多了,为了解决这个问题,在最近的2.11版中新增了@ContributesAndroidInjector注解。有了它我们上面的UserComponent可以不要了。(惊不惊喜,意不意外!)
@Module public abstract class BuildersModule {
@ContributesAndroidInjector(modules = UserModule.class) abstract SecondActivity secondActivityInjector(); }
我们可以看一下自动生成的代码:
@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> {
} } }
是不是一毛一样。。。不要怪我不早说,我也是为了大家可以更多的了解其中的细节。
3.工作原理
那么它是如何工作的?(前方一大堆代码乱入,不重要部分已去除)
我们首先从MyApplication开始,在我们的父类DaggerApplication帮我们实现了注入。
public abstract class DaggerApplication extends Application{
@Inject DispatchingAndroidInjector
activityInjector;
@Override
public
void
onCreate() {
super.onCreate(); injectIfNecessary(); }
@ForOverride
protected
abstract AndroidInjector
applicationInjector();
private
void
injectIfNecessary() { AndroidInjector
applicationInjector = (AndroidInjector
) applicationInjector(); applicationInjector.inject(
this);
//这里注入 }
@Override
public DispatchingAndroidInjector
activityInjector() {
return activityInjector; } }
注入时的具体内容
private Provider
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); //注入 }
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); } }
当我们在Activity调用AndroidInjection.inject(this)时,从Application获取一个DispatchingAndroidInjector,并将您的activity传递给
inject(activity)
public static void inject(Activity activity) { Application application = activity.getApplication(); //获取DaggerApplication中的activityInjector AndroidInjector
activityInjector = ((HasActivityInjector) application).activityInjector(); activityInjector.inject(activity); }
DispatchingAndroidInjector通过AndroidInjector.Factory创建AndroidInjector,并将您的activity传递至SecondActivitySubcomponentImpl中。
@Beta public 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
extends T>> factoryProvider = injectorFactories.get(instance.getClass());
if (factoryProvider ==
null) {
return
false; } @SuppressWarnings(
"unchecked") AndroidInjector.Factory
factory = (AndroidInjector.Factory
) factoryProvider.get();
try { AndroidInjector
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)); } } }
private final class SecondActivitySubcomponentImpl implements BuildersModule_ContributeSecondActivityInjector.SecondActivitySubcomponent {
private Provider
provideXiaoMingUserProvider;
private MembersInjector
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);
//注入 } }
到此为止,它的工作流程就是这样。
细心地你其实这里会发现,我们依赖的
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
bindTopFragmentInjectorFactory(TestFragmentComponent.Builder builder); } @Subcomponent(modules = TestFragmentModule.class) public interface TestFragmentComponent extends AndroidInjector<TestFragment> {
@Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<TestFragment> {
} } @Module public 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); } }
我已经将这些代码上传到了我的Github,大家可以在分支dagger2.11下查看新的写法。(主分支为旧写法,方便大家对比。)
参考
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/209851.html原文链接:https://javaforall.net
