Android开发经验谈Android技术知识

Dagger2入门有这篇就够了(入门篇)

2019-10-12  本文已影响0人  ifjgm
网上的Dagger2各种多,但看完了,只能让原本懵逼的更懵逼,我只能说大神的世界我不懂,那么Dagger2真那么难吗?给我耐心,我给你答案!!!

1.定义:没耐心了解的,也可以下一步。

Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of an earlier versioncreated by Square and now maintained by Google. Dagger aims to address many of the development and performance issues that have plagued reflection-based solutions. More details can be found in this talk(slides) by +Gregory Kick.

什么意思啊?高屋建瓴,一针见血,力透纸背,入木三分,高端大气上档次,

2. 添加依赖

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

apply plugin: 'android-apt'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.zhang.testing.daggertest"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.0'
testCompile 'junit:junit:4.12'
//dagger2
provided 'javax.annotation:javax.annotation-api:1.2'
compile 'com.google.dagger:dagger:2.5'
apt 'com.google.dagger:dagger-compiler:2.5'
}

 到这,我们就能在项目中使用Dagger2了
 #### 3. 最简单的dagger2使用
 这里是基于最简单的MVP模式的dagger2最简单使用。我们先看代码,这样效率高,容易理解。不信,follow me !!!
 
 1. 新建一个类Prensenter(它的实例就是商品),,这个是要注入到MainActivity(MainActivity就是采购商)中的,不懂没事,接着往下看,**这里注意@Inject这个注解(相当于订单,Dagger2老司机就认这个)**
 ```
 public class Presenter {
 private MainActivity mMainActivity;

 @Inject
 public Presenter(MainActivity mainActivity) {
     this.mMainActivity = mainActivity;
 }

 //下载数据的方法,这里只是模拟
 public void loadData() {
     System.out.println("下载中");
 }
}
  1. 再新建个类MainActivityModule(这里比喻为一个仓库,用@Module表示)Module中有用@Provides注解的方法,就相当于仓库中的货架,可以对外提供商品。下面代码中的方法provideMainActivity()方法的返回是MainActivity,那么它提供的商品就是MainActivity的实例
/**
 * Created by zyg on 2016/11/8.
 */
@(个人博客)Module
public class MainActivityModule {
    private MainActivity mMainActivity;

    public MainActivityModule(MainActivity activity) {

        this.mMainActivity = activity;
    }
    @Provides
    public MainActivity provideMainActivity(){
        return mMainActivity;
    }

}
  1. 再 新建接口 MainComponent,这个接口被@Component注解,表示它是个Component(供货商,交易商),在注解的后面的括号里,指明了modules= MainActivityModule.class,将Component 和Module 关联起来(就是说MainActivityModule这个仓库,是MainComponent这个供货商的仓库)
/**
 * Created by zyg on 2016/11/8.
 */
@Component(modules = MainActivityModule.class)
public interface MainComponent {
    void inject(MainActivity mainActivity);
}
  1. 再看MainActivity方法,我们的目的就是将 Prensenter的实例注入到MainActivity中, 这里我们申明了Presenter mPresenter,并且在它的头上也有个@Inject标注(告诉老司机Dagger2这是我缺的货,快去给我从供货商那给我拉回来),然后rebuild工程,注入所需要的代码就会自动生成。然后我们再调用下面这些方法,完成最后的注入

DaggerMainComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.build()
.inject(this);**

package com.zhang.testing.simplemvpdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.zhang.testing.simplemvpdemo.di.component.DaggerMainComponent;
import com.zhang.testing.simplemvpdemo.di.module.MainActivityModule;
import com.zhang.testing.simplemvpdemo.presenter.Presenter;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "daggerTest";
    @Inject
    Presenter mPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainComponent.builder()
                .mainActivityModule(new MainActivityModule(this))
                .build()
                .inject(this);

    }

    //更新UI的操作
    public void refeshUi() {
        Log.d(TAG, "更新ui");

    }
}

分析总结:到这里一个最简单的dagger2注入过程就完成了,我们把Presenter 的实例注入到MainActivity中,这时候我们就能调用Prensent 中的方法了。因为是Mvp模式,所以Prensenter类也需要拿到了MainActivity的实例,(至于怎么拿到的,少年莫急,一步一步慢慢来!)调用Prensent中的方法完成下载后,就可以调用MainActivity中的方法完成UI的更新。

4. Dagger2避免了反射对性能造成的影像,通过自动生成代码完成,注入。现在我们从它生成代码的角度去看看它到底是怎么完成注入的,自动生成的代码在\DaggerTest\app\build\generated\source\apt\debug\下面。下面看代码吧!!

 public static Builder builder() {
    return new Builder();
  }

这是个静态方法,new 了一个 Builder的实例返回,Builder为其内部类,构造方法中,什么也没有做。接着看MainActivity中下一步调用什么。

public static final class Builder {
    private MainActivityModule mainActivityModule;

private Builder() {}

public MainComponent build() {
  if (mainActivityModule == null) {
    throw new IllegalStateException(
        MainActivityModule.class.getCanonicalName() + " must be set");
  }
  return new DaggerMainComponent(this);
}

public Builder mainActivityModule(MainActivityModule mainActivityModule) {
  this.mainActivityModule = Preconditions.checkNotNull(mainActivityModule);
  return this;
}
}

这个方法,把传进来的MainActivityModule的实例被Builder这个类装进自己兜里了是不是?然后又返回了自己。

public final class DaggerMainComponent implements MainComponent {
    private Provider<MainActivity> provideMainActivityProvider;

  private Provider<Presenter> presenterProvider;

  private MembersInjector<MainActivity> mainActivityMembersInjector;

  private DaggerMainComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideMainActivityProvider =
        MainActivityModule_ProvideMainActivityFactory.create(builder.mainActivityModule);

    this.presenterProvider = Presenter_Factory.create(provideMainActivityProvider);

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(presenterProvider);
  }

  @Override
  public void inject(MainActivity mainActivity) {
    mainActivityMembersInjector.injectMembers(mainActivity);
  }

  public static final class Builder {
    private MainActivityModule mainActivityModule;

    private Builder() {}

    public MainComponent build() {
      if (mainActivityModule == null) {
        throw new IllegalStateException(
            MainActivityModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerMainComponent(this);
    }

    public Builder mainActivityModule(MainActivityModule mainActivityModule) {
      this.mainActivityModule = Preconditions.checkNotNull(mainActivityModule);
      return this;
    }
  }
}       
 public final class MainActivityModule_ProvideMainActivityFactory implements Factory<MainActivity> {
  private final MainActivityModule module;

  public MainActivityModule_ProvideMainActivityFactory(MainActivityModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public MainActivity get() {
    return Preconditions.checkNotNull(
        module.provideMainActivity(), "Cannot return null from a non-@Nullable @Provides method");
  }

  public static Factory<MainActivity> create(MainActivityModule module) {
    return new MainActivityModule_ProvideMainActivityFactory(module);
  }
}
public final class Presenter_Factory implements Factory<Presenter> {
  private final Provider<MainActivity> mainActivityProvider;

  public Presenter_Factory(Provider<MainActivity> mainActivityProvider) {
    assert mainActivityProvider != null;
    this.mainActivityProvider = mainActivityProvider;
  }

  @Override
  public Presenter get() {
    return new Presenter(mainActivityProvider.get());
  }

  public static Factory<Presenter> create(Provider<MainActivity> mainActivityProvider) {
    return new Presenter_Factory(mainActivityProvider);
  }
}
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<Presenter> mPresenterProvider;

  public MainActivity_MembersInjector(Provider<Presenter> mPresenterProvider) {
    assert mPresenterProvider != null;
    this.mPresenterProvider = mPresenterProvider;
  }

  public static MembersInjector<MainActivity> create(Provider<Presenter> mPresenterProvider) {
    return new MainActivity_MembersInjector(mPresenterProvider);
  }

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mPresenter = mPresenterProvider.get();
  }

  public static void injectMPresenter(
      MainActivity instance, Provider<Presenter> mPresenterProvider) {
    instance.mPresenter = mPresenterProvider.get();
  }
} 
  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mPresenter = mPresenterProvider.get();
  }

MI的injectMembers,方法把 MainActvity中的mPresenter 取出来了,mPresenter 是谁??,我们需要注入到MainActivity中的Presenter类的引用,只要它被实例化了,咱们工作基本就完成了,那么再看看等号的右边,mPresenterProvider.get(),mPresenterProvider何许人也?,他就是MI creat方法的时候传进来的PF实例,被MI包装了下,搞的差点不认识。(嘿嘿,整容了)。调用它的get方法,依然是个抽象方法,实现就在PF里,(仅仅是换个行头,所以该PF做的事还是PF做啊)

@Override
  public Presenter get() {
    return new Presenter(mainActivityProvider.get());
  }

这里PF new了一个Presenter的实例并返回了,到这里,等号的左边(不要纠结于概念,你非要说在这里它不叫等号,那么我也只能无语)是Presenter的引用,右边是实例,mPresenter实例化完成,即注入完成。这里我们也看到,new Presenter的时候需要传入MainActivity实例作为参数,这里通过mainActivityProvider的get方法获取,mainActivityProvider是谁?不用多说了吧!就是经过整容的MF,可要认的出来才行。

  @Override
  public MainActivity get() {
    return Preconditions.checkNotNull(
        module.provideMainActivity(), "Cannot return null from a non-@Nullable @Provides method");
  }

调用了module的provideMainActivity方法,这 module是谁,不用再说了吧,就是MainActivityMoule的实例,它的provideMainActivity,方法返回什么,还是我们自己写的呢。就是返回MainActivity的实例。通过一系列的get方法,拿到MainActivity的实例,然后传到Presenter的new方法,这样Presenter就拿到了MainActivity的实例。到这里,所有的注入才算是真正完成。我们的最佳MVP也算是正在完成。

如果到这里你还不明白,不怕我们还有一招,看图 image

这里我就不做过多解释了,根据上面文字描述绘制的图谱,从new MainActivityModule开始,MainActivity的实例被包装到 Module里,然后整个Module 的实例又被包装到 Builder里,然后把Modle取出,再次包装到 MF里(Modle的工厂类)然后再 在包装到PF里,最后又把PF包装到MI里,然后再调用一系列的get方法取出this,完成注入。

总结:好累啊,Dagger2最简单的使用和流程,从老司机寓言故事法,到源代码分析法,到流程图谱,用了三种方法来说明Dagger2的代码调用流程,旨在用简单的办法,把原理说清楚。那么你明白了吗?自己去敲代码验证一下吧,源码请看这里,simpleMvpDemo的那个Module哦!这里只是最简单的使用,下一篇进阶篇。

上一篇下一篇

猜你喜欢

热点阅读