Dagger学习记录

本文详细介绍了Dagger2依赖注入框架的使用方法及其优化过程。通过实例对比展示了依赖注入如何降低代码耦合度,提高可测试性。并提供了基于Dagger2的MVP模式示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么用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构造方法变了之后就要修改依赖的类了

依赖注入原理

Android单排上王者系列之Dagger2使用解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值