草庐IT

android - 如何在Android项目中从头开始设置DAGGER依赖注入(inject)?

coder 2023-05-07 原文

如何使用 Dagger ?如何配置 Dagger 以在我的 Android 项目中工作?

我想在我的 Android 项目中使用 Dagger,但我觉得它很困惑。

编辑:Dagger2 也从 2015 年 04 月 15 日开始发布,它更令人困惑!

[这个问题是一个“ stub ”,当我更多地了解 Dagger1 和更多地了解 Dagger2 时,我将添加到我的答案中。这个问题更像是一个 指南 而不是一个“问题”。]

最佳答案

指南 Dagger 2.x (修订版 6):

步骤如下:

1.) 添加 Dagger给您的 build.gradle文件:

  • 顶级 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()
        }
    }
    
  • 应用级别 build.gradle :

  • .
    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
    }
    

    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);
        }
    }
    

    3.) 创建 AppContextComponent提供获取可注入(inject)类的接口(interface)的类。
    public interface AppContextComponent {
        CustomApplication application(); //provision method
        Context applicationContext(); //provision method
        LocationManager locationManager(); //provision method
    }
    

    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);
    }
    

    当心: : 您需要提供@Scope模块的 @Singleton 上的注释(如 @ActivityScope@Provides )带注释的方法在生成的组件中获取作用域提供程序,否则它将是无作用域的,并且每次注入(inject)时都会获得一个新实例。

    3.2.) 创建一个应用程序范围的组件,指定您可以注入(inject)的内容(这与 Dagger 1.x 中的 injects={MainActivity.class} 相同):
    @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);
    }
    

    3.3.) 对于您可以自己通过构造函数创建并且不想使用 @Module 重新定义的依赖项(例如,您使用构建风格来更改实现类型),您可以使用 @Inject带注释的构造函数。
    public class Something {
        OtherThing otherThing;
    
        @Inject
        public Something(OtherThing otherThing) {
            this.otherThing = otherThing;
        }
    }
    

    另外,如果您使用 @Inject构造函数,您可以使用字段注入(inject)而无需显式调用 component.inject(this) :
    public class Something {
        @Inject
        OtherThing otherThing;
    
        @Inject
        public Something() {
        }
    }
    

    这些 @Inject构造函数类会自动添加到相同作用域的组件中,而无需在模块中显式指定它们。

    一个 @Singleton范围@Inject构造函数类将在 @Singleton 中看到作用域组件。
    @Singleton // scoping
    public class Something {
        OtherThing otherThing;
    
        @Inject
        public Something(OtherThing otherThing) {
            this.otherThing = otherThing;
        }
    }
    

    3.4.) 在为给定接口(interface)定义特定实现后,如下所示:
    public interface Something {
        void doSomething();
    }
    
    @Singleton
    public class SomethingImpl {
        @Inject
        AnotherThing anotherThing;
    
        @Inject
        public SomethingImpl() {
        }
    }
    

    您需要使用 @Module 将特定实现“绑定(bind)”到接口(interface)。 .
    @Module
    public class SomethingModule {
        @Provides
        Something something(SomethingImpl something) {
            return something;
        }
    }
    

    自 Dagger 2.4 以来,对此的简写如下:
    @Module
    public abstract class SomethingModule {
        @Binds
        abstract Something something(SomethingImpl something);
    }
    

    4.) 创建一个 Injector类来处理您的应用程序级组件(它取代了整体 ObjectGraph)

    (注意:Rebuild Project 使用 APT 创建 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;
        }
    }
    

    5.) 创建您的 CustomApplication类(class)
    public class CustomApplication
            extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            Injector.initialize(this);
        }
    }
    

    6.) 添加 CustomApplication给您的 AndroidManifest.xml .
    <application
        android:name=".CustomApplication"
        ...
    

    7.) MainActivity 中注入(inject)您的类(class)
    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
        }
    }
    

    8.) 享受!

    +1。) 您可以指定 Scope用于您可以创建的组件 Activity 级范围组件 .子作用域允许您提供仅对给定子作用域而不是在整个应用程序中需要的依赖项。通常,每个 Activity 都会通过此设置获得自己的模块。请注意存在范围内的提供者 每个组件 ,这意味着为了保留该 Activity 的实例,组件本身必须在配置更改后幸免于难。例如,它可以通过 onRetainCustomNonConfigurationInstance() 存活下来。 ,或迫击炮瞄准镜。

    有关子范围划分的更多信息,请查看 the guide by Google .另请参阅 this site about provision methods还有 component dependencies section ) 和 here .

    要创建自定义范围,您必须指定范围限定符注释:
    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface YourCustomScope {
    }
    

    要创建子作用域,您需要在组件上指定作用域,并指定 ApplicationComponent作为它的依赖。显然,您还需要在模块提供程序方法上指定子范围。
    @YourCustomScope
    @Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
    public interface YourCustomScopedComponent
            extends ApplicationComponent {
        CustomScopeClass customScopeClass();
    
        void inject(YourScopedClass scopedClass);
    }
    

    并且
    @Module
    public class CustomScopeModule {
        @Provides
        @YourCustomScope
        public CustomScopeClass customScopeClass() {
            return new CustomScopeClassImpl();
        }
    }
    

    请注意只有可以将作用域组件指定为依赖项。想想它就像 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);
    }
    

    变成这样:
    @Singleton
    @Component
    public interface ApplicationComponent {
        YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
    }
    
    @Subcomponent(modules={CustomScopeModule.class})
    @YourCustomScope
    public interface YourCustomScopedComponent {
        CustomScopeClass customScopeClass();
    }
    

    而这个:
    DaggerYourCustomScopedComponent.builder()
          .applicationComponent(Injector.get())
          .customScopeModule(new CustomScopeModule())
          .build();
    

    变成这样:
    Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());
    

    +3.): 请检查其他有关 Dagger2 的 Stack Overflow 问题,它们提供了很多信息。例如,我当前的 Dagger2 结构在 this answer 中指定.

    感谢

    感谢您在 Github 的指导, TutsPlus , Joe Steele , Froger MCSGoogle .

    也是为了这个step by step migration guide I found after writing this post.

    而对于 scope explanation通过基里尔。

    更多信息请见 official documentation .

    关于android - 如何在Android项目中从头开始设置DAGGER依赖注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27036933/

    有关android - 如何在Android项目中从头开始设置DAGGER依赖注入(inject)?的更多相关文章

    1. ruby - 如何在 Ruby 中顺序创建 PI - 2

      出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

    2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

      如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

    3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

      我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

    4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

      exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

    5. ruby - 如何在续集中重新加载表模式? - 2

      鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

    6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

      我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

    7. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

      我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

    8. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

      我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

    9. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

      我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

    10. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

      我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

    随机推荐