您的位置:首页 > 移动开发 > Android开发

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

2016-07-25 11:45 666 查看
原文链接: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如何提供从AppComponent到UserProfileActivityComponent的依赖。子组件可访问基础组件提供的域,所以它们可以直接使用。

不同情况取决于@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账号
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android