Epi*_*rce 96 android dependency-injection dagger dagger-2
如何使用Dagger?如何配置Dagger在我的Android项目中工作?
我想在我的Android项目中使用Dagger,但我发现它令人困惑.
编辑:Dagger2也从2015年04月15日开始,它更令人困惑!
[这个问题是一个"存根",我在我的答案中添加了更多关于Dagger1的知识,并且更多地了解了Dagger2.这个问题更多的是指导而不是"问题".
Epi*_*rce 183
Dagger 2.x 指南(修订版第6版):
步骤如下:
1.)添加Dagger
到您的build.gradle
文件:
.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //added apt for source code generation
}
}
allprojects {
repositories {
jcenter()
}
}
Run Code Online (Sandbox Code Playgroud)
.
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt' //needed for source code generation
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "your.app.id"
minSdkVersion 14
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.google.dagger:dagger:2.7' //dagger itself
provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
}
Run Code Online (Sandbox Code Playgroud)
2.)创建AppContextModule
提供依赖项的类.
@Module //a module could also include other modules
public class AppContextModule {
private final CustomApplication application;
public AppContextModule(CustomApplication application) {
this.application = application;
}
@Provides
public CustomApplication application() {
return this.application;
}
@Provides
public Context applicationContext() {
return this.application;
}
@Provides
public LocationManager locationService(Context context) {
return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
}
Run Code Online (Sandbox Code Playgroud)
3.)创建AppContextComponent
提供接口的类,以获取可注入的类.
public interface AppContextComponent {
CustomApplication application(); //provision method
Context applicationContext(); //provision method
LocationManager locationManager(); //provision method
}
Run Code Online (Sandbox Code Playgroud)
3.1.)这是您使用实现创建模块的方法:
@Module //this is to show that you can include modules to one another
public class AnotherModule {
@Provides
@Singleton
public AnotherClass anotherClass() {
return new AnotherClassImpl();
}
}
@Module(includes=AnotherModule.class) //this is to show that you can include modules to one another
public class OtherModule {
@Provides
@Singleton
public OtherClass otherClass(AnotherClass anotherClass) {
return new OtherClassImpl(anotherClass);
}
}
public interface AnotherComponent {
AnotherClass anotherClass();
}
public interface OtherComponent extends AnotherComponent {
OtherClass otherClass();
}
@Component(modules={OtherModule.class})
@Singleton
public interface ApplicationComponent extends OtherComponent {
void inject(MainActivity mainActivity);
}
Run Code Online (Sandbox Code Playgroud)
注意::您需要在模块的注释方法上提供@Scope
注释(如@Singleton
或@ActivityScope
)@Provides
以在生成的组件中获取范围提供者,否则它将是未编组的,并且每次注入时都会获得一个新实例.
3.2.)创建一个应用程序范围的组件,指定可以注入的内容(这与injects={MainActivity.class}
Dagger 1.x中的相同):
@Singleton
@Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope
public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods
void inject(MainActivity mainActivity);
}
Run Code Online (Sandbox Code Playgroud)
3.3.)对于您可以自己通过构造函数创建的依赖项,并且不希望使用@Module
(例如,您使用构造flavor来改变实现的类型)来重新定义,您可以使用带@Inject
注释的构造函数.
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
Run Code Online (Sandbox Code Playgroud)
此外,如果使用@Inject
构造函数,则可以使用字段注入而无需显式调用component.inject(this)
:
public class Something {
@Inject
OtherThing otherThing;
@Inject
public Something() {
}
}
Run Code Online (Sandbox Code Playgroud)
这些@Inject
构造函数类会自动添加到同一作用域的组件中,而不必在模块中显式指定它们.
一个@Singleton
范围的@Inject
构造函数的类会在可见@Singleton
范围的部件.
@Singleton // scoping
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
Run Code Online (Sandbox Code Playgroud)
3.4.)在为给定接口定义特定实现之后,如下所示:
public interface Something {
void doSomething();
}
@Singleton
public class SomethingImpl {
@Inject
AnotherThing anotherThing;
@Inject
public SomethingImpl() {
}
}
Run Code Online (Sandbox Code Playgroud)
您需要使用a将特定实现"绑定"到接口@Module
.
@Module
public class SomethingModule {
@Provides
Something something(SomethingImpl something) {
return something;
}
}
Run Code Online (Sandbox Code Playgroud)
自Dagger 2.4以来的一个简写如下:
@Module
public abstract class SomethingModule {
@Binds
abstract Something something(SomethingImpl something);
}
Run Code Online (Sandbox Code Playgroud)
4.)创建一个Injector
类来处理你的应用程序级组件(它取代了整体ObjectGraph
)
(注意:使用APT Rebuild Project
创建DaggerApplicationComponent
构建器类)
public enum Injector {
INSTANCE;
ApplicationComponent applicationComponent;
private Injector(){
}
static void initialize(CustomApplication customApplication) {
ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
.appContextModule(new AppContextModule(customApplication))
.build();
INSTANCE.applicationComponent = applicationComponent;
}
public static ApplicationComponent get() {
return INSTANCE.applicationComponent;
}
}
Run Code Online (Sandbox Code Playgroud)
5.)创建你的CustomApplication
课程
public class CustomApplication
extends Application {
@Override
public void onCreate() {
super.onCreate();
Injector.initialize(this);
}
}
Run Code Online (Sandbox Code Playgroud)
6.)加入CustomApplication
你的AndroidManifest.xml
.
<application
android:name=".CustomApplication"
...
Run Code Online (Sandbox Code Playgroud)
7.)注入你的课程MainActivity
public class MainActivity
extends AppCompatActivity {
@Inject
CustomApplication customApplication;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Injector.get().inject(this);
//customApplication is injected from component
}
}
Run Code Online (Sandbox Code Playgroud)
8.)享受!
+1.)您可以Scope
为组件指定可以创建活动级范围组件的组件.子望远镜允许您提供仅对给定子范围只需要的依赖关系,而不是整个应用程序.通常,每个Activity都使用此设置获得自己的模块.请注意,每个组件都存在一个作用域提供程序,这意味着为了保留该活动的实例,组件本身必须在配置更改后继续存在.例如,它可以存活onRetainCustomNonConfigurationInstance()
或通过Mortar范围.
有关subscoping的更多信息,请查看Google的指南.另请参阅此站点有关提供方法以及组件依赖性部分)和此处.
要创建自定义范围,必须指定范围限定符注释:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}
Run Code Online (Sandbox Code Playgroud)
要创建子范围,您需要在组件上指定范围,并指定ApplicationComponent
其依赖关系.显然,您还需要在模块提供程序方法上指定子范围.
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
Run Code Online (Sandbox Code Playgroud)
和
@Module
public class CustomScopeModule {
@Provides
@YourCustomScope
public CustomScopeClass customScopeClass() {
return new CustomScopeClassImpl();
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,只能将一个范围组件指定为依赖项.可以想象它与Java中不支持多继承的方式完全一样.
+2.)关于@Subcomponent
:基本上,作用域@Subcomponent
可以替换组件依赖; 但是,您需要使用组件工厂方法,而不是使用注释处理器提供的构建器.
所以这:
@Singleton
@Component
public interface ApplicationComponent {
}
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
Run Code Online (Sandbox Code Playgroud)
变成这样:
@Singleton
@Component
public interface ApplicationComponent {
YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}
@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
CustomScopeClass customScopeClass();
}
Run Code Online (Sandbox Code Playgroud)
还有这个:
DaggerYourCustomScopedComponent.builder()
.applicationComponent(Injector.get())
.customScopeModule(new CustomScopeModule())
.build();
Run Code Online (Sandbox Code Playgroud)
变成这样:
Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());
Run Code Online (Sandbox Code Playgroud)
+3.):请检查有关Dagger2的其他Stack Overflow问题,它们提供了大量信息.例如,我的当前Dagger2结构在此答案中指定.
谢谢
感谢Github,TutsPlus,Joe Steele,Froger MCS和Google的指南.
而对于Kirill的范围说明.
官方文档中的更多信息.
Epi*_*rce 11
匕首指南1.x:
步骤如下:
1.)为依赖项添加Dagger
到build.gradle
文件中
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
...
compile 'com.squareup.dagger:dagger:1.2.2'
provided 'com.squareup.dagger:dagger-compiler:1.2.2'
Run Code Online (Sandbox Code Playgroud)
另外,添加packaging-option
以防止出现错误duplicate APKs
.
android {
...
packagingOptions {
// Exclude file to avoid
// Error: Duplicate files during packaging of APK
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
}
Run Code Online (Sandbox Code Playgroud)
2.)创建一个Injector
类来处理ObjectGraph
.
public enum Injector
{
INSTANCE;
private ObjectGraph objectGraph = null;
public void init(final Object rootModule)
{
if(objectGraph == null)
{
objectGraph = ObjectGraph.create(rootModule);
}
else
{
objectGraph = objectGraph.plus(rootModule);
}
// Inject statics
objectGraph.injectStatics();
}
public void init(final Object rootModule, final Object target)
{
init(rootModule);
inject(target);
}
public void inject(final Object target)
{
objectGraph.inject(target);
}
public <T> T resolve(Class<T> type)
{
return objectGraph.get(type);
}
}
Run Code Online (Sandbox Code Playgroud)
3.)创建一个RootModule
将未来模块链接在一起.请注意,您必须包括injects
指定要使用@Inject
注释的每个类,否则Dagger会抛出RuntimeException
.
@Module(
includes = {
UtilsModule.class,
NetworkingModule.class
},
injects = {
MainActivity.class
}
)
public class RootModule
{
}
Run Code Online (Sandbox Code Playgroud)
4.)如果Root中指定的模块中有其他子模块,请为这些模块创建模块:
@Module(
includes = {
SerializerModule.class,
CertUtilModule.class
}
)
public class UtilsModule
{
}
Run Code Online (Sandbox Code Playgroud)
5.)创建接收依赖关系的叶子模块作为构造函数参数.在我的情况下,没有循环依赖,所以我不知道Dagger是否可以解决这个问题,但我发现它不太可能.构造函数参数也必须在Module by Dagger中提供,如果您指定,complete = false
那么它也可以在其他模块中.
@Module(complete = false, library = true)
public class NetworkingModule
{
@Provides
public ClientAuthAuthenticator providesClientAuthAuthenticator()
{
return new ClientAuthAuthenticator();
}
@Provides
public ClientCertWebRequestor providesClientCertWebRequestor(ClientAuthAuthenticator clientAuthAuthenticator)
{
return new ClientCertWebRequestor(clientAuthAuthenticator);
}
@Provides
public ServerCommunicator providesServerCommunicator(ClientCertWebRequestor clientCertWebRequestor)
{
return new ServerCommunicator(clientCertWebRequestor);
}
}
Run Code Online (Sandbox Code Playgroud)
6.)扩展Application
并初始化Injector
.
@Override
public void onCreate()
{
super.onCreate();
Injector.INSTANCE.init(new RootModule());
}
Run Code Online (Sandbox Code Playgroud)
7.)在你MainActivity
的onCreate()
方法中,调用Injector .
@Override
protected void onCreate(Bundle savedInstanceState)
{
Injector.INSTANCE.inject(this);
super.onCreate(savedInstanceState);
...
Run Code Online (Sandbox Code Playgroud)
8.)使用@Inject
你的MainActivity
.
public class MainActivity extends ActionBarActivity
{
@Inject
public ServerCommunicator serverCommunicator;
...
Run Code Online (Sandbox Code Playgroud)
如果您收到错误no injectable constructor found
,请确保您没有忘记@Provides
注释.
归档时间: |
|
查看次数: |
19118 次 |
最近记录: |