Dagger2
最近在android中使用dagger2做开发的项目越来越多了,然后去学习了下dagger2,在github上面看了不少关于dagger2的demo,但是感觉dagger2在android中并不是太好使用了,例如本人看过的一些列子
将对象注入到Activity中
写法一
public interface AppComponent{
void inject(SplashActivity activity);
void inject(MainActivity activity);
void inject(GuideFragment fragment);
...
}
这种写法是在Application中生成AppComponent对象 然后提供全局获取这个对象的static方法 在其他Activity中调用inject(xxxxxx)
写法二
对于Activity
public interface ActivityComponent{
void inject(SplashActivity activity);
void inject(MainActivity activity);
...
}
这里写代码片
对于Fragment
public interface FragmentComponent{
void inject(GuideFragment fragment);
...
}
然后每个activity和fragment创建的时候去创建对应的ActivityComponent与FragmentComponent对象
说明
对于方法一来说 AppCompoent中inject方法可能或很多
方法二 每个Activity与Fragment中都需要 DaggerXXXX.create().inject(xxxx)
这个没有统一的写法,所以我再github上面看别人的demo很头疼,所以项目一直没准备上dagger2,前段时间无聊,去google的github看了下dagger2的最新版本,在里面发现了一个新东西dagger2-android,然后百度了下dagger2-android ,结果没看到一篇文章介绍这个…..感觉有点悲剧,然后自己就看dagger2官方指导,学习了下这个框架,个人感觉相对于dagger2在android中的使用,dagger2-android更加适合
感觉有点不好说,先上代码吧
gradle 配置如下
dependencies {
compile 'com.google.dagger:dagger:2.11'
compile 'com.google.dagger:dagger-android:2.11-rc2'
compile 'com.google.dagger:dagger-android-support:2.11-rc2'
compile 'com.google.errorprone:error_prone_annotations:2.0.19'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.10'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
}
如果你的项目中未使用v4包的Fragment与v7包的AppCompatActivity的话 可以去掉
compile 'com.google.dagger:dagger-android-support:2.11-rc2'
demo:现在我们要做一个coffee贩卖的app,需求是这样的
coffee全球定价都是一致的 为1RMB 但是不同的国家价格不同
中国区是1CNY
美国区售价1USD
欧洲区售价1EUR
其他区售价1RMB
好了 我们可以来编写代码了
首先我们新建个Coffee类 里面就是设置coffee的价格
public class Coffee {
public String price(){//全球统一定价
return "1RMB";
}
}
新建App的Application
//dagger-android 与dagger-android-support中都有DaggerApplication
//不同的是support中的是会自动对v4包中的Fragment进行注入,本demo
//是用了ViewPager+Fragment 所以选择dagger-android-support中的
//DaggerApplication作为基类
public class App extends DaggerApplication{
//DaggerApplication abstract method
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
//return null;
//当我们App的Component写好后
return DaggerApp_Component.builder().create(this);
}
//代码编写
//创建CoffeeModule 全球统一售价
//也可以在MainActivity中创建CoffeeModule
//那么App的Component的modules中就不能包含CoffeeModule
@dagger.Module
public static class CoffeeModule{
@Provides
public Coffee provideCoffee(){
return new Coffee();
}
}
//创建App的Component
@dagger.Component(modules = {
AndroidSupportInjectionModule.class,
AndroidInjectionModule.class,
CoffeeModule.class,
/*activity inject*/
MainActivity.Module.class
})
public interface Component extends AndroidInjector<App>{
@dagger.Component.Builder
public abstract class Builder extends AndroidInjector.Builder<App>{
//这个就是我们以前在dagger2中提供module的方法
public abstract Builder coffeeModule(CoffeeModule coffeeModule);
//重载这个函数保存我们需要new的module
@Override
public void seedInstance(App instance) {
coffeeModule(new CoffeeModule());
}
}
}
}
当代码完成后 你可能会发现MainActivity不存在,不要急,这个为什么要写在这里呢,不要急 等下我把Activity代码写完就来解释
看上面发的图 你能看到每个界面中底部都有全球统一售价1RMB 这个是在Activity中获取coffee的价格进行显示的
以下是Activity代码
/*DaggerAppCompatActivity 是support包中的注入基类*/
public class MainActivity extends DaggerAppCompatActivity {
@dagger.Module(subcomponents = {
Component.class
})
public abstract class Module{
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
public abstract AndroidInjector.Factory<? extends Activity> bind(Component.Builder builder);
}
@dagger.Subcomponent(modules = {
CoffeeFragment.Module.class//这一句可以写到App的Component的modules中 但是如果在app中的话 那么CoffeeFragment.Module中的东西将是单例 在Activity中 随着Activity销毁 CoffeeFragment的数据也将销毁
})
public interface Component extends AndroidInjector<MainActivity>{
@dagger.Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MainActivity>{}
}
@Inject
Coffee coffee;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView(R.id.coffeePrice).setText("全球统一售价:" + coffee.price());
setupCoffees();
}
private void setupCoffees(){
final List<Fragment> fragments = new ArrayList<>();
fragments.add(CoffeeFragment.newInstance(1));
fragments.add(CoffeeFragment.newInstance(2));
fragments.add(CoffeeFragment.newInstance(3));
fragments.add(CoffeeFragment.newInstance(4));
((ViewPager)findViewById(R.id.viewPager)).setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
@Override
public CharSequence getPageTitle(int position) {
String title = "";
switch (position){
case 0:
title = "中国";
break;
case 1:
title = "美国";
break;
case 2:
title = "欧洲";
break;
case 3:
title = "其他";
break;
}
return title;
}
});
((TabLayout)findViewById(R.id.tabLayout)).setupWithViewPager(((ViewPager)findViewById(R.id.viewPager)));
}
public TextView textView(int id){
return (TextView) findViewById(id);
}
}
CoffeeFragment代码
//这里的DaggerFragment是dagger-android-support的DaggerFragment
//有的版本中叫DaggerSupportFragment
public class CoffeeFragment extends DaggerFragment{
@dagger.Module
public static class FragmentModule{
//由于AppModule中提供了Coffee
//CoffeeFragment依赖与MainActivity
//MainActivity依赖于App
//所以@Inject Coffee是有对象的
//因此我们在这里用@Named使用fragment中新建的Coffee
@Provides
@Named("country")
public Coffee provideCoffee(){
return new CountyCoffee();
}
}
@dagger.Module(subcomponents = {
Component.class
})
public abstract class Module{
@Binds
@IntoMap
@FragmentKey(CoffeeFragment.class)
public abstract AndroidInjector.Factory<? extends Fragment> bind(CoffeeFragment.Component.Builder builder);
}
@dagger.Subcomponent(modules = {
FragmentModule.class
})
public interface Component extends AndroidInjector<CoffeeFragment>{
@dagger.Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<CoffeeFragment>{
public abstract Builder fragmentModule(FragmentModule module);
@Override
public void seedInstance(CoffeeFragment instance) {
fragmentModule(new FragmentModule());
}
}
}
public static Fragment newInstance(int index){
CoffeeFragment fragment = new CoffeeFragment();
return fragment;
}
@Inject
@Named("country")
Coffee coffee;
private View rootView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (rootView == null){
rootView = inflater.inflate(R.layout.fragment_coffee,null);
textView(R.id.coffeePrice).setText(coffee.price());
}
return rootView;
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (rootView.getParent() != null){
((ViewGroup)rootView.getParent()).removeView(rootView);
}
}
public TextView textView(int id){
return (TextView) rootView.findViewById(id);
}
}
CountryCoffee代码
public class CountyCoffee extends Coffee{
private String price;
private static int index = 0;
public CountyCoffee(){
switch (index){
case 0:
price = "1CNY";
break;
case 1:
price = "1USD";
break;
case 2:
price = "1EUR";
break;
case 3:
price = "1RMB";
break;
}
index++;
}
@Override
public String price() {
return price;
}
}
好了 我们来解释下App中Component的modules的 MainActivity.Module.class
说白了 这个就是告诉App MainActivity依赖App的Component 所以在MainActivity中可以@Inject Coffee coffee; 同理 MainActivity中的CoffeeFragment.Module.class也是一样的道理 不能写在Application中的原因是App只会创建一次 如果写App里面就是单例了 ,本例写App中和MainActivity中都是可以的 但是推荐写在Activity中 这样生命周期就对应了
其他说明
dagger2-android最新版可以自动注入很多类 下面列出来能注入对象的基类
DaggerApplication dagger-android基础包
DaggerActivity
DaggerBroadcastReceiver
DaggerContentProvider
DaggerFragment dagger-android基础包 不是v4的Fragment
DaggerIntentService
DaggerService
DaggerAppCompatActivity
DaggerApplication 支持v4的 一般来说 现在的都用这个最好
DaggerFragment 支持v4包的fragment的注入基类