第一个问题
在 Dagger 2.8+ 中,他们添加了这个 android-support 库,其中还添加了一些新的注释,如 @ActivityKey、@ContributesAndroidInjector、@Subcomponent.Builder 等。所以我的问题是它给桌面带来了什么好处。
What are the advantages of using DispatchingAndroidInjector and the other dagger-android classes?已经回答了这个问题
它是否解决了诸如没有适用于所有子类的基类的注入方法之类的问题?
Dagger 2 在编译时使用代码生成来进行依赖注入。在这一点上,它与其他依赖注入框架(如 Guice)在运行时检查注入站点不同。为了让 Dagger 2 工作,您必须在某些时候指定注入位点的不变量。因此,永远不可能写出这样的东西:
void inject(Activity activity);
在 Dagger 2 组件中并让它注入所有活动。
但是,dagger-android 中的新类有很多改进。而之前你必须写:
void inject(MainActivity mainActivity);
对于每个不同的注射部位,您现在可以编写以下代码:
@Module(subcomponents = MainActivitySubcomponent.class)
public abstract class MainActivityModule {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity> mainActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
}
然后:
AndroidInjection.inject(this);
在您的 MainActivity 中的适当位置。
第二个问题
HasFragmentInjector 只是像我们以前使用 FragmentManager 那样在 Activity 中加载 Fragment?还是我错过了什么?
HasFragmentInjector 只是标记了 Fragment 应该从哪个类获取其AndroidInjector。您可以在代码on GitHub 中亲自查看AndroidInjection#inject(Fragment fragment):
public static void inject(Fragment fragment) {
checkNotNull(fragment, "fragment");
HasFragmentInjector hasFragmentInjector = findHasFragmentInjector(fragment);
Log.d(TAG, String.format(
"An injector for %s was found in %s",
fragment.getClass().getCanonicalName(),
hasFragmentInjector.getClass().getCanonicalName()));
AndroidInjector<Fragment> fragmentInjector = hasFragmentInjector.fragmentInjector();
checkNotNull(fragmentInjector,"%s.fragmentInjector() returned null",
hasFragmentInjector.getClass().getCanonicalName());
fragmentInjector.inject(fragment);
}
从 javadoc 中,该方法首先遍历 parent-fragment,然后是 Activity,最后是 Application 找到 HasFragmentInjector 并使用 AndroidInjector<Fragment> 注入 Fragment 的字段。
但是,HasFragmentInjector 的存在并不意味着您应该开始使用 Dagger 2 管理 Fragments:
public class MainActivity {
@Inject CoffeeFragment coffeeFragment; //no! don't do this
@Inject TeaFragment teaFragment; //no!
您仍然应该使用使用静态工厂方法来实例化片段的惯用方式。当您使用事务添加片段或委托给 ViewPager 时,当调用它们的 onAttach(Context context) 时,Dagger 2 将为片段中的字段执行注入。代替上面的例子,下面的代码是一个非常简单的 Activity,有一个 ViewPager 和两个 Fragment:
public class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector {
@Inject
DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BeveragesPagerAdapter beveragesPagerAdapter = new BeveragesPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setAdapter(beveragesPagerAdapter);
}
class BeveragesPagerAdapter extends FragmentStatePagerAdapter {
public BeveragesPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return TeaFragment.instantiate(new Bundle());
case 1:
return CoffeeFragment.instantiate(new Bundle());
default:
throw new IllegalStateException();
}
}
@Override
public int getCount() {
return 2;
}
@Override
public CharSequence getPageTitle(int position) {
return "tab " + (position + 1);
}
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return fragmentDispatchingAndroidInjector;
}
}
FragmentStatePagerAdapter 正确处理 Fragment 的管理,我们不会在 MainActivity 中注入字段。
片段本身如下所示:
在CoffeeFragment.java中:
public class CoffeeFragment extends Fragment {
public static CoffeeFragment instantiate(@Nullable Bundle arguments) {
CoffeeFragment coffeeFragment = new CoffeeFragment();
coffeeFragment.setArguments(arguments);
return coffeeFragment;
}
@Inject
@Named("Coffee")
Repository repository;
TextView textView;
@Override
public void onAttach(Context context) {
AndroidSupportInjection.inject(this);
super.onAttach(context);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_coffee, container, false);
textView = (TextView) v.findViewById(R.id.coffee_textview);
return v;
}
@Override
public void onResume() {
textView.setText(repository.retrieve());
}
}
在CoffeeFragmentModule.java中:
@Module(subcomponents = CoffeeFragmentSubcomponent.class )
public abstract class CoffeeFragmentModule {
@Binds
@Named("Coffee")
abstract Repository repository(CoffeeRepository coffeeRepository);
@Binds
@IntoMap
@FragmentKey(CoffeeFragment.class)
abstract AndroidInjector.Factory<? extends Fragment> bindCoffeeFragmentInjectorFactory(CoffeeFragmentSubcomponent.Builder builder);
}
在CoffeeFragmentSubcomponent.java中:
@Subcomponent
public interface CoffeeFragmentSubcomponent extends AndroidInjector<CoffeeFragment> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<CoffeeFragment> {}
}
在CoffeeRepository.java:
public class CoffeeRepository implements Repository {
@Inject
public CoffeeRepository() {
}
@Override
public String retrieve() {
return "Coffee!!!!";
}
}