Dagger2入门学习之MVP项目整合(下)

上一篇Dagger2入门学习之MVP项目整合(上)的最后我们列举了Dagger的关键注释,其中@Singleton和@Scope还没有接触,接下来我们来先看看这两个标签的使用。

@Singleton

类似于SharedPreferences对象,我们可能在整个App的生命周期中只需要一个单例,而不需要每次都通过application.getSharedPreferences(“spfile”, Context.MODE_PRIVATE)获得新的对象,那么怎么办呢,我们只需要在你需要单例的对象提供方法上加一个注解@Singleton ,类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Module
public class AppModule {

private MyApplication application;

public AppModule(MyApplication application) {
this.application = application;
}

//全局单例SharedPreferences
@Provides
@Singleton
SharedPreferences provideSharedPreferences() {
return application.getSharedPreferences("spfile", Context.MODE_PRIVATE);
}

@Provides
MyApplication provideApplication() {
return application;
}
}

只需要一个@Singleton,无论我们在多少个Activity容器中通过@Inject获取这个SharedPreferences对象的实例,该对象都是同一个对象,从而实现了全局单例的效果。

你需要什么对象全局单例,就在提供该对象方法的@Provides注解旁加上一个@Singleton,并且在该module关联的Component中加上同样的注解

1
2
3
4
5
6
7
8
9
@Singleton      //不要忘了还要在关联的Component接口中声明,否则会编译报错
@Component(modules = AppModule.class)
public interface AppComponent {

SharedPreferences sharedPreferences();

MyApplication myApplication();

}

@Scope

除了全局单例,我们可能在开发中更多的是需要局部单例,比如,我在ActivityA中需要实例化两个Student对象,在ActivityB中也需要一个Student对象,但我希望ActivityA中的两个Student都叫小明,但ActivityB中的Student对象叫小刚。这个时候我们可以使用@Scope来自定义注解限定注解作用域。

1
2
3
4
@Scope  //声明这是一个自定义@Scope注解
@Retention(RUNTIME)
public @interface ActivityScope {
}

使用自定义@Scope注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Module
public class A03Module {

private A03Activity activity;

public A03Module(A03Activity activity) {
this.activity = activity;
}

@Provides
@ActivityScope//添加注解实现局部单例
Student provideStudent() {
return new Student();
}

}

在Component中同样添加@ActivityScope注解,否则会编译报错

1
2
3
4
5
6
7
@ActivityScope//添加注解实现局部单例
@Component(modules = A03Module.class, dependencies = AppComponent.class)
public interface A03Component {

void inject(A03Activity activity);

}

事实上,Android开发中使用Dagger,开发人员仍然需要面对一些问题。Google工程师们尝试弥补Dagger的问题,于是Dagger2-Android基于Dagger2应用于Android开发,由google开发的的拓展库应运而生。

Dagger2-Android

Demo Github地址:https://github.com/lxqxsyu/TestDagger

Dagger2-Android引入

  1. 环境&依赖
1
2
3
4
annotationProcessor 'com.google.dagger:dagger-compiler:2.11' //一定要添加dagger2的annotationProcessor!
compile 'com.google.dagger:dagger-android:2.11'
compile 'com.google.dagger:dagger-android-support:2.11' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11
  1. Demo结构

这个就是整个demo的结构,图中MVP三层的接口和实现很容易理解,最右边的AppComponent实现的是全局的依赖注入,左边的MainComponent实现的是简单业务逻辑的注入关系,具体我们看代码分析。

Demo实现

AppComponent

1
2
3
4
5
@Singleton
@Component(modules = {AppModule.class, OkHttpModule.class})
public interface AppComponent {
MainComponent addSub(MainModule mainModule);
}

这是一个全局的Component,这里例举了两个modules(根据实际需要可以添加多个)

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
26
27
28
29
@Module
public class AppModule {

private Context context;

public AppModule(CustomeApplication application) {
this.context = application;
}

@Singleton
@Provides
public Context ProviderApplicationContext(){
return context;
}

@Singleton
@Provides
@Named("default")
public SharedPreferences providerDefaultSharedPreferences(){
return PreferenceManager.getDefaultSharedPreferences(context);
}

@Singleton
@Provides
@Named("encode")
public SharedPreferences providerEncodeSharedPreferences(){
return context.getSharedPreferences("encode",Context.MODE_PRIVATE);
}
}

后面使用SharePreference和ApplicationContext就可以直接使用了而且是使用@Singleton修饰的。

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
26
public class CustomeApplication extends Application{

private static AppComponent appComponent;

@Override
public void onCreate() {
super.onCreate();
}

public static CustomeApplication get(Context context) {
return (CustomeApplication) context.getApplicationContext();
}

private void setupApplicationComponent() {
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}

public AppComponent getAppComponent() {
if(appComponent == null){
this.setupApplicationComponent();
}
return appComponent;
}
}

MainComponent

1
2
3
4
5
@ActivityScope
@Subcomponent(modules = MainModule.class)
public interface MainComponent {
void inject(MainMvpActivity mainMvpActivity);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Module
public class MainModule {

private MainMvpView mView;
private MainMvpModel mModel;

public MainModule(MainMvpView view, MainMvpModel model){
mView = view;
mModel = model;
}

@ActivityScope
@Provides
MainMvpView provideMainMvpView() {
return mView;
}

@ActivityScope
@Provides
MainMvpModel provideMainMvpModel(){
return mModel;
}
}
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
26
27
public class MainMvpActivity extends AppCompatActivity implements MainMvpView{

@Inject
MainMvpPresenterImpl mPresenter;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomeApplication.get(this)
.getAppComponent()
.addSub(new MainModule(this, new MainMvpModelImpl()))
.inject(this);

findViewById(R.id.click_me).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.loadData();
}
});
}

@Override
public void updateUI(String showMsg) {
Toast.makeText(MainMvpActivity.this, showMsg, Toast.LENGTH_LONG).show();
}
}

相关链接

Demo Github地址
轻松学,听说你还没有搞懂 Dagger2
告别Dagger2模板代码:Dagger Android使用详解