为什么用Dagger
Dagger是一个依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建。主要来解决依赖倒置问题
依赖倒置的优化
原始版
public abstract class UserActivity {
private ImageView imageView
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Glide.with(this).load(url).into(imageView);
//Picasso.with(this).load(url).into(imageView);
}
}
优化
public abstract class UserActivity {
private ImageView imageView
private ImageLoaderStrategy imageLoaderStrategy
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
imageLoaderStrategy = new ImageLoaderStrategy();
imageLoaderStrategy.loadImage(url,imageView);
}
}
public class ImageLoaderStrategy {
public void loadImage(String url, ImageView imageView) {
Glide.with(imageView.getContext()).load(url).into(imageView);
//Picasso.with(imageView.getContext()).load(url).into(imageView);
}
优化2
public abstract class UserActivity {
private ImageView imageView
private BaseImageLoaderStrategy imageLoaderStrategy
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
imageLoaderStrategy = new GlideImageLoaderStrategy();
imageLoaderStrategy.loadImage(url,imageView);
}
}
public interface BaseImageLoaderStrategy {
public void loadImage(String url, ImageView imageView)
}
public class GlideImageLoaderStrategy implements BaseImageLoaderStrategy{
public void loadImage(String url, ImageView imageView) {
Glide.with(imageView.getContext()).load(url).into(imageView);
}
}
依赖注入
把被依赖项加到需要的依赖中
依赖注入的方式:
1. seter 方法注入
2. 构造器注入
3. 接口注入
public class MovieLister {
private MovieFinder finder;
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
...
}
public class MovieLister {
s...
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
}
class MovieLister implements InjectFinder {
...
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
...
}
依赖注入降低了依赖和被依赖类型间的耦合,在修改被依赖的类型实现时,不需要修改依赖类型的实现,同时,对于依赖类型的测试,可以更方便的使用mocking object替代原有的被依赖类型,以达到对依赖对象独立进行单元测试的目的。
Dagger 2进行依赖注入
简单注入
public class MainActivity extends ActionBarActivity {
UserModel user
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//需要创建对象
user = new UserModel();
((TextView) findViewById(R.id.user_desc_line)).setText(user.id + "\n" + user.name );
}
}
使用 Dagger 之后
- 依赖提供器(构建依赖)
//Dagger2中,这个负责提供依赖的组件被称为Module。
//@Module标识类型为module,并用@Provides标识提供依赖的方法
@Module
public class ActivityModule {
@Provides UserModel provideUserModel() {
return new UserModel();
}
}
- 构建注入器(构建Injector)
//连接提供依赖和消费依赖对象的组件被称为Injector。Dagger2中,我们将其称为component。
//Component是一个使用@Component标识的Java interface。interface的inject方法需要一个消耗依赖的类型对象作为参数。
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
}
- 完成注入
@Inject标志被注入的对象userModel(注意userModel不能为private),之后通过Dagger2生成的实现了我们提供的ActivityComponent接口类DaggerActivityComponent创建component,调用其inject方法完成注入。
public class MainActivity extends ActionBarActivity {
private ActivityComponent mActivityComponent;
@Inject UserModel userModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mActivityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule()).build();
mActivityComponent.inject(this);
((TextView) findViewById(R.id.user_desc_line)).setText(userModel.id + "\n" + userModel.name);
}
...
}
- DaggerActivityComponent是什么(生成的注入器)
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerActivityComponent implements ActivityComponent {
private Provider<Motor> provideMotorProvider;
private Provider<Vehicle> vehicleProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static ActivityComponent create() {
return builder().build();
}
private void initialize(final Builder builder) {
this.provideMotorProvider = ActivityModule_ProvideMotorFactory.create(builder.activityModule);
this.vehicleProvider = Vehicle_Factory.create(provideMotorProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), vehicleProvider);
}
@Override
public void inject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private ActivityModule activityModule;
private Builder() {
}
public ActivityComponent build() {
if (activityModule == null) {
this.activityModule = new ActivityModule();
}
return new DaggerActivityComponent(this);
}
public Builder activityModule(ActivityModule activityModule) {
if (activityModule == null) {
throw new NullPointerException("activityModule");
}
this.activityModule = activityModule;
return this;
}
}
}
涉及到的注解
@Inject 标记由Dagger提供的依赖具体用法:
1. 标记在构造器上
- 声明可以使用该构造器构造对象
- 注入构造器参数
只能标记一个构造器
2. 标记在 public属性上
标记需要注入的属性
3. 标注在 public 方法上
将在构造器执行完后执行标记方法,在需要提供 this 对象试可使用
@Component 用来解析@Inject注入到目标类,两种定义方式
1. void inject(目标类 obj);Dagger2会从目标类开始查找@Inject注解,自动生成依赖注入的代码,调用inject可完成依赖的注入。
2. Object getObj(); 如:Pot getPot();
@Module和@Provides
解决@Inject标记构造器提供依赖的局限性,无法标记到三方的类上面,无法注入抽象依赖
@Module需要和@Provide是需要一起使用的时候才具有作用的,并且@Component也需要指定了该Module的时候。
@Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provide标注的方法,相当于构造器的@Inject,可以提供依赖。
还有一点要说的是,@Component可以指定多个@Module的,如果需要提供多个依赖的话。
并且Component也可以依赖其它Component存在
学习成果
基于 Dagger 的 mvp
public class MainActivity extends AppCompatActivity implements MainContract.View {
private MainPresenter mainPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化presenter 将view传递给presenter
mainPresenter = new MainPresenter(this);
//调用Presenter方法加载数据
mainPresenter.loadData();
}
}
public class MainPresenter {
private MainContract.View mView;
MainPresenter(MainContract.View view) {
mView = view;
}
public void loadData() {
//调用model层方法,加载数据
...
//回调方法成功时
mView.updateUI();
}
改
public class MainActivity extends AppCompatActivity implements MainContract.View {
@Inject
MainPresenter mainPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);
//调用Presenter方法加载数据
mainPresenter.loadData();
}
}
public class MainPresenter {
//MainContract是个接口,View是他的内部接口,这里看做View接口即可
private MainContract.View mView;
@Inject
MainPresenter(MainContract.View view) {
mView = view;
}
public void loadData() {
//调用model层方法,加载数据
...
//回调方法成功时
mView.updateUI();
}
@Module
public class MainModule {
private final MainContract.View mView;
public MainModule(MainContract.View view) {
mView = view;
}
@Provides
MainView provideMainView() {
return mView;
}
}
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
总结
module 里面就是把被依赖的实例封装起来了,就是一个工厂模式,发生改变时修改module 就行了,但是 module构造方法变了之后就要修改依赖的类了