Dagger基础回顾
在前面一篇Dagger2基础传送门我们得出了一个结论。
- 若一个类(Xx)的构造函数被@inject标注,则该类编译时会产生Xx_Factory.
- 若一个类(Xx)的成员变量被@inject标注,则该类编译时会产生Xx_MembersInjector.
- @Component标注的接口(Xx)在编译时生成DaggerXx,负责将上面两个联系起来。
下面我们通过前面提到的这个例子再来回顾一下这个结论
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| /**
* Created by 水寒 on 2017/11/16.
*/
public class Province {
@Inject
public City city;
@Inject
public Province(City city) {
this.city = city;
}
public String showAddress() {
return "四川省" + city.show();
}
}
|
Dagger2会在编译过程中生成对应的依赖项,这些依赖项在Android Studio该路径下,如图所示:
Dagger依赖生成文件目录
第一条结论:若一个类(Xx)的构造函数被@inject标注,则该类编译时会产生Xx_Factory.
1
2
3
4
| @Inject
public Province(City city) {
this.city = city;
}
|
产生的对应的Province_Factory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public final class Province_Factory implements Factory<Province> {
private final MembersInjector<Province> provinceMembersInjector;
private final Provider<City> cityProvider;
public Province_Factory(
MembersInjector<Province> provinceMembersInjector, Provider<City> cityProvider) {
this.provinceMembersInjector = provinceMembersInjector;
this.cityProvider = cityProvider;
}
@Override
public Province get() {
return MembersInjectors.injectMembers(
provinceMembersInjector, new Province(cityProvider.get()));
}
public static Factory<Province> create(
MembersInjector<Province> provinceMembersInjector, Provider<City> cityProvider) {
return new Province_Factory(provinceMembersInjector, cityProvider);
}
}
|
上面代码看似比较多,其实做了一件很简单的事情,创建实例create方法(这里注入了cityProvider,通过get方法可以得到City实例)
我们接下来看看Province_Factory的构造函数,我们看到传进一个对应的City_MemberInjector和City的Provider.
1
2
3
| public interface Provider<T> {
T get();
}
|
第二条结论:若一个类(Xx)的成员变量被@inject标注,则该类编译时会产生Xx_MembersInjector.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| public final class City_MembersInjector implements MembersInjector<City> {
private final Provider<Street> streetProvider;
public City_MembersInjector(Provider<Street> streetProvider) {
this.streetProvider = streetProvider;
}
public static MembersInjector<City> create(Provider<Street> streetProvider) {
return new City_MembersInjector(streetProvider);
}
@Override
public void injectMembers(City instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.street = streetProvider.get();
}
}
|
生成的City_MembersInjector中我们注意其中重写的MembersInjector接口的injectMembers方法,这里进行了实例真正的赋值操作(关联)。
第三条结论:@Component标注的接口(Xx)在编译时生成DaggerXx,负责将上面两个联系起来。
1
2
3
4
5
| @Component
public interface MainActivityComponent {
void inject(MainActivity activity);
}
|
在生成的DaggerMainActivityComponent里面我们看看MainActivityComponet的inject方法实现
1
2
3
4
| @Override
public void inject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
|
通过injectMembers()完成真正目标对象实例化以及依赖操作
1
2
3
4
5
6
7
| //MainActivity_MembersInjector.java
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.province = provinceProvider.get();
}
|
我们再来看看DaggerMainActivityComponent中的initialize方法
1
2
3
4
5
6
7
8
9
10
11
12
| private void initialize(final Builder builder) {
this.cityMembersInjector = City_MembersInjector.create(Street_Factory.create());
this.cityProvider = City_Factory.create(cityMembersInjector, Street_Factory.create());
this.provinceMembersInjector = Province_MembersInjector.create(cityProvider);
this.provinceProvider = Province_Factory.create(provinceMembersInjector, cityProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(provinceProvider);
}
|
可以看到inject()和initialize()刚好是相反的过程,直到找到依赖的源头完成源头对象的实例化,即这里的Street_Factory的get()方法的返回值;在Street实例化完成之后返回给City完成City实例化,City实例化完之后对自己的成员重新赋值了一遍,即产生依赖关系:
MVP模式
MVP 模式是 MVC 模式在 Android 上的一种变体,要介绍 MVP 就得先介绍 MVC。在 MVC 模式中,Activity 应该是属于 View 这一层。而实质上,它既承担了 View,同时也包含一些 Controller 的东西在里面。这对于开发与维护来说不太友好,耦合度大高了。把 Activity 的 View 和 Controller 抽离出来就变成了 View 和 Presenter,这就是 MVP 模式。
MVP模式的作用:
- 分离了视图逻辑和业务逻辑,降低了耦合
- Activity 只处理生命周期的任务,代码变得更加简洁
- 视图逻辑和业务逻辑分别抽象到了 View 和 Presenter 的接口中去,提高代码的可阅读性
- Presenter 被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
- 把业务逻辑抽到 Presenter 中去,避免后台线程引用着 Activity 导致 Activity 的资源无法被系统回收从而引起内存泄露和 OOM
MVP模式将原来一个Activity可以解决的问题,分成了M、V、P三部分,这在项目中会产品大量的类,如果利用Dagger2来进行这些类的有效管理,是接下来我们要思考的问题。
MVP实例
Model 接口
1
2
3
4
| public interface MainMvpModel extends IModel{
void requestAPI(ApiCallback callback);
}
|
Model 实现
1
2
3
4
5
6
7
| public class MainMvpModelImpl implements MainMvpModel {
@Override
public void requestAPI(ApiCallback callback) {
Log.d("TEST", "请求接口");
}
}
|
View 接口
1
2
3
4
| public interface MainMvpView {
void updateUI();
}
|
View 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class MainMvpActivity extends AppCompatActivity implements MainMvpView{
private MainMvpPresenter mPresenter = new MainMvpPresenterImpl();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPresenter.attachView(this);
mPresenter.loadData();
}
@Override
public void updateUI() {
}
@Override
protected void onDestroy() {
super.onDestroy();
mPresenter.detachView(this);
}
}
|
Presenter 接口
1
2
3
4
| public interface MainMvpPresenter extends IPresenter{
void loadData();
}
|
Presenter 实现
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
30
| public class MainMvpPresenterImpl implements MainMvpPresenter {
private MainMvpModel mModel;
private MainMvpView mView;
public MainMvpPresenterImpl(){
mModel = new MainMvpModelImpl();
}
@Override
public void loadData() {
mModel.requestAPI(new ApiCallback() {
@Override
public void callback(int code) {
}
});
}
@Override
public void attachView(IView view) {
mView = (MainMvpView) view;
}
@Override
public void detachView(IView view) {
mView = null;
}
}
|
上面是典型的MVP开发安卓项目的结构,我们看到Presenter中强制注入了View和Model.如果我们要修改View和Model的构造方法的时候就需要修改Presenter, 同样我们修改Presenter的构造方法的时候就需要在对应的Activity中做相应的修改。接下来我们使用Dagger2的注释来实现这种依赖关系。
Component和Module
在使用Dagger实现MVP结构前我们得先知道关于Module的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| @Module
public class MainModule {
private MainMvpView mView;
public MainModule(MainMvpView view){
mView = view;
}
@Provides
MainMvpView provideMainView() {
return mView;
}
}
|
1
2
3
4
5
| @Component(modules = {MainModule.class})
public interface MainMvpActivityComponent {
void inject(MainMvpActivity activity);
}
|
这个@Module相当于一个额外的拓展,通过@Provides提供给一种直接的依赖关系,假如我们不能通过给构造函数添加@Inject,则可以通过该方式进行依赖注入。
1
2
3
4
| DaggerMainMvpActivityComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);
|
现在我们来理一理这三者的关系
@Inject : 注入,被注解的构造方法会自动编译生成一个Factory工厂类提供该类对象。
@Component: 注入器,类似快递员,作用是将产生的对象注入到需要对象的容器中,供容器使用。
@Module: 模块,类似快递箱子,在Component接口中通过@Component(modules =
xxxx.class),将容器需要的商品封装起来,统一交给快递员(Component),让快递员统一送到目标容器中。
全局类 AppComponent & AppModule
开发中,局部变量尚还好说,我们在没有Dagger的时候,用的时候new一个就可以了,类似于SharedPerferences这种对象我们就比较头疼,也没有必要每次都去context.getSharedPerferences()吧,但是我们有了Dagger,我们可以通过依赖注入的方式,仅仅初始化一次,之后每次想使用,只需要@Inject注解,就能直接使用了。
1. 创建AppModule,提供你想要提供的全局变量
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 AppModule {
private MyApplication application;
public AppModule(MyApplication application) {
this.application = application;
}
//提供全局的sp对象
@Provides
SharedPreferences provideSharedPreferences(){
return application.getSharedPreferences("spfile", Context.MODE_PRIVATE);
}
//提供全局的Application对象
@Provides
MyApplication provideApplication(){
return application;
}
//你还可以提供更多.......
}
|
2. 创建AppComponent,然后ctrl+F9编译
1
2
3
4
5
6
7
| @Component(modules = AppModule.class)
public interface AppComponent {
SharedPreferences sharedPreferences();
MyApplication myApplication();
}
|
3. 编译成功后,修改Application类,把Component注入器注入你的Application中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class MyApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
inject();
}
private void inject() {
AppComponent appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
ComponentHolder.setAppComponent(appComponent);
}
}
|
4. ComponentHolder类,方便获取appComponent对象
1
2
3
4
5
6
7
8
9
10
11
| public class ComponentHolder {
private static AppComponent myAppComponent;
public static void setAppComponent(AppComponent component) {
myAppComponent = component;
}
public static AppComponent getAppComponent() {
return myAppComponent;
}
}
|
Activity的Component和Module
1
2
3
4
5
6
| @Component(modules = MainModule.class, dependencies = AppComponent.class)
public interface MainMvpComponent {
void inject(MainMvpActivity activity);
}
|
请注意dependencies = AppComponent.class, 这句话意思是可以依赖全局的AppComponent,相当于一种继承关系。这样我们的MainMvpActivity中就可以使用SharePreference了(因为AppComponent注入器中已经有AppModule了)。
1
2
3
4
5
6
7
8
9
10
| @Inject
SharedPreferences sp;
....
DaggerA02Component.builder()
.appComponent(ComponentHolder.getAppComponent())//添加appComponent注入器
.mainModule(new MainModule(this))
.build()
.inject(this);
|
关于Android中Dagger实现MVP下篇中再看。
关键的注释
Dagger中的关键注释,如果有点不清晰,没关系,后面会慢慢理解。
注解 | 用法 |
---|
@Module | Modules类里面的方法专门提供依赖,所以我们定义一个类,用@Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的 依赖。modules的一个重要特征是它们设计为分区并组合在一起(比如说,在我们的app中可以有多个组成在一起的modules) |
@Provide | 在modules中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。 |
@Singleton | 当前提供的对象将是单例模式 ,一般配合@Provides一起出现 |
@Component | 用于接口,这个接口被Dagger2用于生成用于模块注入的代码 |
@Inject | 在需要依赖的地方使用这个注解。(你用它告诉Dagger这个 构造方法,成员变量或者函数方法需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。) |
@Scope | Scopes可是非常的有用,Dagger2可以通过自定义注解限定注解作用域。 |
参考:谷歌官方Demo https://google.github.io/dagger//android.html
参考:http://blog.csdn.net/mq2553299/article/details/73065745
参考:https://www.jianshu.com/p/39d1df6c877d