登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

框架 Dagger2 的简单使用 [复制链接]

2017-6-28 10:25
James1991 阅读:2495 评论:1 赞:2
Tag:  

Dagger2

Google开发的针对Android的依赖注入框架,它的设计基于面向对象的一种设计模式(控制反转IOC),最大的特点就是低耦合。 
一般依赖注入框架都是通过反射实现,而Dagger2使用编译时生成代码,也就是apt动态生成。这样提高了效率不影响性能。

导入依赖

在Module的build.gradle下添加如下代码:

apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
    ...
    apt 'com.google.dagger:dagger-compiler:2.4'
    compile 'com.google.dagger:dagger:2.4'
    compile 'org.glassfish:javax.annotation:10.0-b28'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在Project的build.gradle下添加如下代码:

dependencies {
   ...
   classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

导入完成Sync一下就可以了。

进入正题

要使用之前要明白各个部分是干嘛的,一头雾水直接用会很不爽。其实看很多项目比如google dagger2-mvp,在Activity或者Fragment中想要实例化对象并不是new一个对象,而是仅仅使用@Inject注解,这个对象就可以直接使用了。而且这个对象想要实现单例并不需要在编写单例设计模式,考虑同步锁之类的代码,其中一系列的操作dagger帮你实现了。这种方式既简单,又解藕还能提高程序员的装x境界..

使用Dagger首先要创建两个部分Component,Module当然还有你自己的对象(比如Fragment)
Component:个人理解就是一个中介,它帮你联系你需要注入的对象(Module中提供的对象),和要将对象注入给谁(Fragment)。
Module:在这里它可以提供你要的对象。

可以配合下面的代码理解上面的意思:

Module,Component,Provides

1.创建FragmentComponent:

@Component(modules = FragmentModule.class)
public interface FragmentComponent {
    //它会从Module中查找NewsListFragment中需要的Acitivity实例。找到后交给NewsListFragment。
    void inject(NewsListFragment newsListFragment);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

2.创建FragmentModule:

@Module
public class FragmentModule {
    private Fragment fragment;

    public FragmentModule(Fragment fragment) {
        this.fragment = fragment;
    }
    //这里提供的Activity就可以在Fragment中使用了。
    @Provides
    Activity provideActivity() {
        return fragment.getActivity();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3.在NewsListFragment相应的位置初始化FragmentComponent:

public class NewsListFragment extends Fragment {

    @Inject
    Activity activity;

    @Inject
    User user;//可以看到这个User在Module中并没有提供,那么就去它构造中看看。

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //这里在创建完Module,Component后要make Project编译一下!
        FragmentComponent fragmentComponent = DaggerFragmentComponent.builder()
                .fragmentModule(new FragmentModule(this))
                .build();
        fragmentComponent.inject(this);

        return super.onCreateView(inflater, container, savedInstanceState);
    }
}
public class User {
    //如果Fragment中需要这个实例,而Module中还没有提供该实例化,那么就必须在该对象的构造上加上@Inject注解。
    @Inject
    public User() {}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
总结-->
其中的注解:
    @Module:提供对象的module必须用它来标注。
    @Provides:用于标注提供的对象。(提供的方法名称随意)
    @Component:作为中介的一个标注。
    @Inject:可以理解为整个过程的起点,最终找的就是它标注下的实例,或者方法。

整个过程就是:
    Component将Fragment注入进来,
    它会先去Fragment的Module中查找带有@Provides注解的对象,如果找到了Fragment中带有@Inject注解的对象则成功注入,
    如果Module中没有找到,去该对象中寻找带有@Inject注解的构造,找到则成功注入,
    否则失败。

接下来介绍Dagger中的一些注解:

@Singleton

如果刚才Fragment中的User想要实现单例:
        要在FragmentModule中:
@Module
public class FragmentModule {
    ...
    @Provides
    @Singleton
    User provideUser() {
        //这就提供了单例,但是仅限于Fragment生命周期内。
        return new User();              
    }
}

同时FragmentComponent上要添加注解:
@Singleton
@Component(modules = FragmentModule.class)
public interface FragmentComponent {
    //它会从Module中查找NewsListFragment中需要的Acitivity实例。找到后交给NewsListFragment。
    void inject(NewsListFragment newsListFragment);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

@Scope

    Dagger中的单例可以限制生命周期内单例(整个app生命周期内单例,和Activity或者Fragment生命周期内单例)
    所以如果控制整个app生命周期内单例和Activity生命周期内单例,都用@Singleton就造成冲突会出现问题。
    -->这时我们可以自定义scope(其实就是有限制的控制单例):
        其实@Singleton的实现就是Dagger自定义的scope
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
(1)自定义Fragment生命周期内单例:
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerFragment {}
将刚才的FragmentModule中的单例注解替换为@PerFragment即可,FragmentComponent上的注解也要替换掉。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
(2)想要实现全局的单例:
(假如我们要在Fragment中获取全局单例对象People)
public class People {
    public People(){}               
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
a.创建全局单例的Scope:
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerApp {}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
b.创建全局AppModule:
@Module
public class AppModule {
    private final Context context;
    public AppModule(Context context) {
        this.context = context;
    }
    @Provides
    Context provideContext() {
        return context;
    }
    //↓↓↓这里提供的对象可以在依赖AppComponent的所有Component注入的对象中使用
    // 比如(ActivityComponent,FragmentComponent中inject的对象)
    // 自然这里限制的单例,全局有效。
    @Provides
    @PerApplication
    People proPeople() {
        return new People();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
c.创建全局AppComponent:
@PerApplication
@Component(modules = AppModule.class)
public interface AppComponent {
    //↓↓↓它的特点是,需要向下层(也就是需要的层)提供AppModule中提供好的对象
    Context getContext();//方法名随意
    People getPeople();
}
注意:刚才的FragmentComponent要依赖全局的APPComponent:
@PerFragment
@Component(dependencies = AppComponent.class, modules = FragmentModule.class)
public interface FragmentComponent {
    void inject(NewsListFragment newsListFragment);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
d.在Application的onCreate()方法中初始化AppComponent:
@Override
public void onCreate() {
    super.onCreate();
    appComponent = DaggerAppComponent.builder()
            .appModule(new AppModule(this))
            .build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
e.在Fragment中获取FragmentComponent:
public class NewsListFragment extends Fragment {

    @Inject
    Activity activity;

    @Inject
    User user;

    @Inject
    People people;//这个people就是全局单例。

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        FragmentComponent fragmentComponent = DaggerFragmentComponent.builder()
               .appComponent(appComponent//app中初始化好的)
               .fragmentModule(new FragmentModule(this))
               .build();
        fragmentComponent.inject(this);

        return super.onCreateView(inflater, container, savedInstanceState);
    }
}   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
            总结:-->其实之前写这么多代码,都是配置,完事在相应的Fragment或Activity中使用就非常方便了。
分享到:
我来说两句
facelist
您需要登录后才可以评论 登录 | 立即注册
所有评论(1)
lilongfei0504 2017-7-4 11:07
不过代码可读性不高,因为大多数程序员不习惯这种方式
回复

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

返回顶部