使用 Dagger 库 基础篇

作者: rivendell1984 | 来源:发表于2017-07-24 19:07 被阅读0次

    使用 Dagger 库 基础篇
    Dagger 注入对象的原理

    Dagger 是一个依赖注入的库,采用编译时生成代码的方式实现,现在的版本是 2.11。

    Dagger 涉及的概念很多,为了避免过早的陷入细节,这篇文章先通过一个例子,介绍 Dagger 库基本的 @Inject@Component@Module 几个知识点。

    下面我们就看看如何用 Dagger 造个凳子(图片来源于 Muji 官网):

    Stool.jpg

    注:这个 Muji 家的凳子和我们经常看到的条凳很相似,相关背景可以看知乎上的问题。选用这个凳子纯粹是因为该款式结构简单,便于拆分。

    我们在这篇文章中将凳子作为一个整体考虑,直接创建凳子对象。

    传统方法创建被依赖对象

    首先,创建被依赖的类 Stool :

    public class Stool {
        public Stool() {
    
        }
    }
    

    MainActivity 需要(依赖)这个对象,所以有一个 Stool 成员变量,并且我们在适当时机 new 一个对象:

    public class MainActivity extends AppCompatActivity {
    
        Stool mStool;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mStool = new Stool();
        }
    }
    

    这样写很符合习惯,但是造成了紧耦合。关于这部分知识,请参考这篇文章

    那么接下来演示下,如何用 Dagger 最简单的方式创建一个对象。

    使用 Dagger 创建被依赖对象 (@Inject 方式)

    首先,在 app 的 build.gradle 加入 Dagger 库 :

    dependencies {
        ...
        compile 'com.google.dagger:dagger:2.11'
        annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
    }
    

    在被依赖的类 Stool 的构造函数上加上 @Inject 注解,表示我可以提供这个对象:

    public class Stool {
        @Inject
        public Stool() {
    
        }
    }
    

    相应的,MainActivity 的 Stool 成员变量也要加上 @Inject 注解,表示我需要这个对象:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Stool mStool;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }
    

    如果这样就结束了,那就太简单了。但实际上完成上述步骤,只是有了需求者和提供者,还需要有一个运送者负责传递。这个任务是由 Dagger 最重要的 Component 接口完成

    @Component()
    public interface MainActivityComponent {
    
        void inject(MainActivity activity);
    
    }
    

    在接口前加上 @Component() 标注,告诉 Dagger 这是一个 Component 接口。同时,接口方法任意命名(通常约定俗成是 inject ),只不过需要传入要注入的目的地:MainActivity 对象。
    然后,Dagger 预编译器会根据这个接口自动加上 Dagger- 前缀,生成一个实现类 DaggerMainActivityComponent。

    如果没有生成对应的代码,需要在 Android Studio 点击 Build -> Rebuild Project。

    上述步骤搭好了架子,最后还需要手动输入,决定注入的时机。这里就在 onCreate 注入 Stool 对象,再次修改 MainActivity,添加DaggerMainActivityComponent.create().inject(this)

    public class MainActivity extends AppCompatActivity {
        @Inject
        Stool mStool;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);
        }
    }
    

    自动生成的类 DaggerMainActivityComponent 采用了 Builder 模式(关于这部分分析,可以参考接下来讲述原理的文章)。所以通常的教程会看到 DaggerMainActivityComponent.builder().build() 的方式创建 Component 对象,实际上 create() 封装了 builder().build() 方法,所以用 DaggerMainActivityComponent.create() 创建 Component 对象效果相同。

    如上就是采用 Dagger 最基本的方式创建并注入一个凳子对象。涉及的知识点包括:@Inject 注解和 @Component 接口。

    使用 Dagger 创建被依赖对象 (@Module 方式 + static 方法)

    接下来我们用 @Module 方式创建对象,引入 @Module 源于有些时候无法在构造函数添加 @Inject 注解。

    这次,被依赖的类 Stool 构造函数没有 @Inject 注解:

    public class Stool {
    
        public Stool() {
    
        }
    }
    

    然后添加 StoolModule 类,用于创建 Stool 依赖对象:

    import dagger.Module;
    import dagger.Provides;
    
    @Module
    public class StoolModule {
    
        @Provides
        static Stool provideStool() {
            return new Stool();
        }
    }
    

    @Module 标注说明这个类可以提供依赖,@Provides@Module 中使用,说明标注的方法可以返回依赖。

    由于采用了 Module 方式创建被依赖对象,Component 接口也需要做出些修改:

    @Component(modules = StoolModule.class)
    public interface MainActivityComponent {
        void inject(MainActivity activity);
    }
    

    @Component 注解中,定位到之前定义的 StoolModule 类 (modules = StoolModule.class),表示采用这个类提供依赖对象。

    此处 MainActivity 保持原样:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Stool mStool;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);
        }
    }
    

    可以看到,通过引入 @Module ,并在 @Component 指定,完全可以平滑的替代在构造函数前加 @Inject 的方式创建依赖对象。

    这回涉及的知识点包括:@Module 注解和 @Component 接口指定 Module 。

    但是,在自动生成的 DaggerMainActivityComponent 类中发生了些改变,采用 Module 方式会在其中增加一个 @Deprecated 方法:

    @Deprecated
    public Builder stoolModule(StoolModule stoolModule)
    

    这个方法在这个例子中没有什么作用。因为我们在 StoolModule 中定义的是一个静态方法,并不需要传递一个 StoolModule 对象:

    @Provides
    static Stool provideStool()
    

    所以,会增加 @Deprecated 标注。这个标注会出现的原因,可以参看官方文档:Unused Modules and Component Dependencies

    • 如果 Module 的方法是 static , Dagger 并不需要这个对象,可以直接调用静态方法
    • 如果一个 Module 未和 Component 关联起来 (例如,我们没有在 MainActivity 的成员变量前加 @Inject 注解 ),也没有必要创建这个 Module 对象。

    使用 Dagger 创建被依赖对象 (@Module 方式 + 非 static 方法)

    这里我们将 Module 改为非 static 方法创建 Stool 依赖对象:

    import dagger.Module;
    import dagger.Provides;
    
    @Module
    public class StoolModule {
    
        @Provides
        Stool provideStool() {
            return new Stool();
        }
    }
    

    此时 MainActivity 可以保持原样,也可以采用 Builder 模式手动创建并传递 Module 对象。如果没有传递, DaggerMainActivityComponent 在调用 build() 方法时会自动创建:

    public class MainActivity extends AppCompatActivity {
        @Inject
        Stool mStool;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);
            //DaggerMainActivityComponent.builder()
            //  .stoolModule(new StoolModule()).build().inject(this);
        }
    }
    

    关于这部分原理,可以参考接下来的文章。

    综上,Dagger 中频繁出现的几个知识点就介绍完了。在后续的文章中,会进一步完善这个程序,并分析 Dagger 工作的原理。

    相关文章

      网友评论

        本文标题:使用 Dagger 库 基础篇

        本文链接:https://www.haomeiwen.com/subject/yitikxtx.html