产品使用Dagger 2——减少方法数

原文链接:https://medium.com/azimolabs/dagger-2-on-production-reducing-methods-count-5a13ff671e30#.2gs179pgj

Dagger 2——完全静态,编译时依赖注入框架是Azimo Android应用的代码架构骨干。我们已经知道,随着开发团队的增长,干净的代码结构是每个项目中最重要的事情之一。初始化/使用分离,更以测试(单元或功能),更好扩展——这些只是引入如Dagger 2依赖注入框架的一小部分好处。

现在我们可以找到许多教程和代码例子展示如何在Android中开始使用Dagger2和依赖注入。如果这是你寻找的,这是我的系列博客可以帮助你:
- 介绍依赖注入
- Dagger 2 API
- Dagger 2——定制范围
- Dagger 2——图形创建性能
- 使用Dagger2进行依赖注入——生产者
- Dagger2使用RxJava进行异步注入
- 注入万物——ViewHolder和Dagger2(使用Multibinding和AutoFactor的例子)

但这些只展示如何开始使用DI。这也是在我们app中使用两年后,为什么今天打算开始分析使用Dagger2的经验。

@Component vs @Subcomponent

自定义范围在简单教程中通常解释不清楚,但它是Dagger2最强有力功能之一。在更复杂的app中只使用@Singleton不会让你的工作更简单。

让我们考虑一个简单的例子——我们有严格连接当前登录用户的依赖(例如,UserProfilePresenter类负责用户配置屏幕的逻辑)。当我们需要用户实体时,不需要每次都调用数据存储,我们可以创建@User范围,并将所有依赖保持在单一实例UserComponent中,该实例生命周期与登陆的用户一致。

在生成app中使用自定义范围不是这篇文字的主题,但我们会在接下来讲解它。

在Dagger2,我没有两种方式构建自定义范围和组件来继承并扩展对象图:

  • 我们可以构建另一个@Component来明确展示扩展Component(本例的AppComponent)
@UserScope
@Component(
    modules = UserModule.class,
    dependencies = AppComponent.class
)
public interface UserComponent {
    UserProfileActivity inject(UserProfileActivity activity);
}
  • 或者我们可以定义@Subcomponent,它是从基础组件的抽象工厂方法(阅读更多)创建的:
@UserScope
@Subcomponent(
    modules = UserModule.class
)
public interface UserComponent {
    UserProfileActivity inject(UserProfileActivity activity);
}

//===== AppComponent.java =====

@Singleton
@Component(modules = {...})
public interface AppComponent {
    // Factory method to create subcomponent
    UserComponent plus(UserModule module);
}

这两种方法的区别?

文档讨论了依赖可视性的区别。@Subcomponent从它的父类访问所有依赖,而@Component只能访问在基类@Component接口暴露的公共性的依赖。

考虑到这点,我们最初选择带依赖@Component的方法。工程的所有组件都依赖范围是@SingletonAppComponent

当出现方法数事情…

但在@Component@Subcomponent之间有另一个重要的不同。让我们看看生成的代码。子组件的实现只是基础组件的一个内部类。所以对于依赖AppCompoenet生成代码的UserProfiileActivityComponent可能长这样:

public final class DaggerAppComponent implements AppComponent {

    //...AppComponent code...

    private final class UserProfileActivityComponentImpl implements UserProfileActivityComponent {
        private final UserProfileActivityComponent.UserProfileActivityModule userProfileActivityModule;
        private Provider<UserProfileActivity> provideActivityProvider;
        private Provider<UserProfileActivityPresenter> userProfileActivityPresenterProvider;
        private MembersInjector<UserProfileActivity> userProfileActivityMembersInjector;

        private UserProfileActivityComponentImpl(
            UserProfileActivityComponent.UserProfileActivityModule userProfileActivityModule) {
            this.userProfileActivityModule = Preconditions.checkNotNull(userProfileActivityModule);
            initialize();
        }

        private void initialize() {
            this.provideActivityProvider = DoubleCheck.provider(BaseActivityModule_ProvideActivityFactory.create(userProfileActivityModule));

            this.userProfileActivityPresenterProvider = DoubleCheck.provider(
                UserProfileActivityPresenter_Factory.create(
                    MembersInjectors.<UserProfileActivityPresenter>noOp(),
                    provideActivityProvider,
                    DaggerAppComponent.this.logoutManagerProvider,
                    DaggerAppComponent.this.userManagerProvider)
            );

            this.userProfileActivityMembersInjector = UserProfileActivity_MembersInjector.create(
                DaggerAppComponent.this.logoutManagerProvider,
                DaggerAppComponent.this.userManagerProvider
                userProfileActivityPresenterProvider)
            );
        }

        @Override
        public UserProfileActivity inject(UserProfileActivity activity) {
            userProfileActivityMembersInjector.injectMembers(activity);
            return activity;
        }
    }
}

20-31行展示了Dagger如何提供从AppComponentUserProfileActivityComponent的依赖。子组件可访问基础组件提供的域,所以它们可以直接使用。

不同情况取决于@Component。相同的结构(UserProfileActivityComponent依赖AppComponent)将生成这样的代码:

public final class DaggerUserProfileActivityComponent implements UserProfileActivityComponent {
    private Provider<LogoutManager> logoutManagerProvider;
    private Provider<UserManager> userManagerProvider;

    //...

    private DaggerUserProfileActivityComponent(Builder builder) {
        assert builder != null;
        initialize(builder);
    }

    @SuppressWarnings("unchecked")
    private void initialize(final Builder builder) {
        this.logoutManagerProvider = new Factory<LogoutManager>() {
            private final AppComponent appComponent = builder.appComponent;

            @Override
            public LogoutManager get() {
                return Preconditions.checkNotNull(
                    appComponent.getLogoutManager(),
                    "Cannot return null from a non-@Nullable component method");
            }
        };

        this.userManagerProvider = new Factory<UserManager>() {
            private final AppComponent appComponent = builder.appComponent;

            @Override
            public UserManager get() {
                return Preconditions.checkNotNull(
                    appComponent.getUserManager(),
                    "Cannot return null from a non-@Nullable component method");
            }
        };

        //... more providers ....

    }

    @Override
    public UserProfileActivity inject(UserProfileActivity activity) {
        userProfileActivityMembersInjector.injectMembers(activity);
        return activity;
    }

    //...
}

14-34行展示了每个从AppComponent发出的依赖请求都需要自己的方法来生成Provider<>对象。为什么?因为依赖组件只能访问那些基类组件暴露了公共接口的依赖。

这对我们意味着什么——Android开发者?从基类组件带到依赖组件中的每一个依赖都讲都让我们更接近65k方法数限制:

因为这一点,我们决定所有依赖于@Component都迁移到@SubComponent。经过这样处理,我们减少了大约5000个额外的方法。

快速分析你的APK

最后值得一提的是从Android Studio 2.2开始出现了一个新的功能,让我们分析APK文件。访问方式是Build -> Analyze APK

这个工具允许我们检查特殊组件的大小(类,资源等),和最能帮助我们的——得到.dex文件的基础信息(类/方法数)。这是依赖注入优化的起始点。

今天就到这里了,但保持联系。不久,我们将分享更多关于Dagger2和依赖注入的经验。感觉阅读!

想了解更多?关注我们的Twitter@AzimoLabsGithub账号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值