依赖注入,完美解决了类间解藕的问题。搞了接近一周的dagger,终于明白点了。将心得记录下来,庆祝一下。dagger与java的spring不同之处在于,dagger是采用了预编译技术而spring则是采用了反射技术。dagger对资源的消耗比spring小很多。知道了这点,使用起来就放心多了。
首先引入依赖库,
在app的gradle中添加
apply plugin: 'com.neenbedankt.android-apt'//不加这个,编译不过去
compile 'com.google.dagger:dagger:2.0.1' apt 'com.google.dagger:dagger-compiler:2.0.1'//编译,自动生成代码用 provided 'org.glassfish:javax.annotation:10.0-b28'
compile 'com.jakewharton:butterknife:6.1.0'//
在项目的gradle中,添加
dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' }这样之后,依赖包导入完成,可以愉快的写代码了
首先,介绍一下Dagger的必要组件,Module(用于提供各种需要的实例,这些实例会注入到dagger框架之中,供我们调用),Component(一个接口,会被dagger自动生成实现类,该实现类用于对注入的实例进行初始化操作)
然后看一下我们的需求,demo中的需求非常简单,在MainActivity中自动注入一个MainActivityPresenter,当点击MainActivity中的某一个Button时,调用MainActivityPresenter中的方法,弹出一个toast完事。看上去,需求很简单,但麻雀虽小,五脏俱全。
为了接近实际应用效果,我们让MainActivity模块依赖于一个全局模块。在实际应用中,这个需求很常见,dagger这样一个牛*的框架,当然也会想到了。为此,我们设计了这样两个模块。
Application模块。
组件包括AppModule(提供Application的实例),AppComponent,DaggerAppComponent在Application中初始化各实例。
看一下AppModule的代码:
@Module public class AppModule { private Application application; public AppModule(Application application){ this.application = application; } @Provides @Singleton public Application provideApplication(){ return application; } }
@Module 标记这个calss是一个Module,对外提供实例用
接下来看一下AppComponent的代码@Provides 标记方法返回值需要注入到dagger中
@Singleton @Component(modules = AppModule.class) public interface AppComponent { Application getAppLication(); }
仅提供一个方法获取Application,自动生成的代码中这个application取自于AppModule
@Component(modules = AppModule.class)
这样,rebuild一下之后,我们就可以在Application中将需要的类初始化出来,看初始化代码
public class MyTestApplication extends Application { private AppComponent appComponent; public static MyTestApplication get(Context context){ return (MyTestApplication)context.getApplicationContext(); } @Override public void onCreate() { super.onCreate(); appComponent = DaggerAppComponent.builder() .appModule(new AppModule(this))//初始化AppModule .build(); } public AppComponent getAppComponent(){ return appComponent; } }
这样,application模块就算搞定了,这里的application主要是提供一个Application,还可以AppComponent中提供一些其他的工具类什么的,为了不影响主逻辑,这里就不写了。
最后,就可以写我们自己的业务逻辑了。
MainActivity模块,组件包括:MainActivityModule,MainActivityComponent,MainActivityPresenter。
看一下MainActivityModule的代码实现
@Module public class MainActivityModule { private MainActivity mainActivity; public MainActivityModule(MainActivity mainActivity){ this.mainActivity = mainActivity; } @Provides MainActivity provideMainActivity(){ return mainActivity; } @Provides MainActivityPresenter providrMainActivityPresenter(){ return new MainActivityPresenter(mainActivity); } }
MainActivityComponent的代码是这个样子的
@ActivityScope//该注解表示MainActivityComponent的生命周期与调用他的Activity一样 @Component(modules = MainActivityModule.class, dependencies = AppComponent.class ) public interface MainActivityComponent { MainActivity inject(MainActivity mainActivity); MainActivityPresenter presenter(); }
MainActivityPresenter的代码实现
public class MainActivityPresenter { private MainActivity mainActivity; public MainActivityPresenter(MainActivity mainActivity) { this.mainActivity = mainActivity; } public void systemTest() { Toast.makeText(mainActivity, "hhhhhh", Toast.LENGTH_LONG).show(); Log.v("vhawk", "fucking great !"); } }
一切准备就绪了,那么牛*的MainActivity出场了
public class MainActivity extends AppCompatActivity { @Inject MainActivityPresenter presenter;//自动实例话 @InjectView(R.id.hello) Button helloView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); ButterKnife.inject(this);//点击事件注入
/**
*初始化
*/ DaggerMainActivityComponent.builder() .appComponent(MyTestApplication.get(this).getAppComponent()) .mainActivityModule(new MainActivityModule(this)) .build().inject(this); } @OnClick(R.id.hello) public void test(){ presenter.systemTest(); } }
Button点击的时候,神奇的现象发生了,正如你所期待的那样,打出了log,弹出了toast。