产品使用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的经验。
让我们考虑一个简单的例子——我们有严格连接当前登录用户的依赖(例如,UserProfilePresenter类负责用户配置屏幕的逻辑)。当我们需要用户实体时,不需要每次都调用数据存储,我们可以创建@User范围,并将所有依赖保持在单一实例UserComponent中,该实例生命周期与登陆的用户一致。
在生成app中使用自定义范围不是这篇文字的主题,但我们会在接下来讲解它。
在Dagger2,我没有两种方式构建自定义范围和组件来继承并扩展对象图:
我们可以构建另一个@Component来明确展示扩展Component(本例的AppComponent)
或者我们可以定义@Subcomponent,它是从基础组件的抽象工厂方法(阅读更多)创建的:
考虑到这点,我们最初选择带依赖@Component的方法。工程的所有组件都依赖范围是@Singleton的AppComponent。
20-31行展示了Dagger如何提供从AppComponent到UserProfileActivityComponent的依赖。子组件可访问基础组件提供的域,所以它们可以直接使用。
不同情况取决于@Component。相同的结构(UserProfileActivityComponent依赖AppComponent)将生成这样的代码:
14-34行展示了每个从AppComponent发出的依赖请求都需要自己的方法来生成Provider<>对象。为什么?因为依赖组件只能访问那些基类组件暴露了公共接口的依赖。
这对我们意味着什么——Android开发者?从基类组件带到依赖组件中的每一个依赖都讲都让我们更接近65k方法数限制:
因为这一点,我们决定所有依赖于@Component都迁移到@SubComponent。经过这样处理,我们减少了大约5000个额外的方法。
这个工具允许我们检查特殊组件的大小(类,资源等),和最能帮助我们的——得到.dex文件的基础信息(类/方法数)。这是依赖注入优化的起始点。
今天就到这里了,但保持联系。不久,我们将分享更多关于Dagger2和依赖注入的经验。感觉阅读!
想了解更多?关注我们的Twitter@AzimoLabs和Github账号。
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的方法。工程的所有组件都依赖范围是@Singleton的AppComponent。
当出现方法数事情…
但在@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@AzimoLabs和Github账号。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories