Dagger 2中“HasFragmentInjector”的实际用法是什么?

时间:2017-06-07 09:47:46

标签: android dependency-injection dagger-2 dagger

我之前已经实现了dagger2 v2.2但是现在他们也添加了dagger.android部分。所以我正在创建示例项目。

我知道 @Provide @Modules 以及 @Components 等注释的旧方法,但是来自Dagger 2.8+他们已经添加了这个android-support库也有一些新的注入,如 @ActivityKey @ContributesAndroidInjector @ Subcomponent.Builder 等。

所以我的问题是它给桌子带来了什么好处。

它是否解决了像基类的Inject方法可以适用于所有子类的问题?或任何其他好处?

第二个问题 - HasFragmentInjector只是像我们以前使用片段管理器一样加载片段内部活动?或者我错过了什么?

请不要为所有图书馆用户提供更具信息性的问题,因为图书馆的文档没有提供这样的答案。

2 个答案:

答案 0 :(得分:28)

第一个问题

  

在Dagger 2.8+中,他们添加了这个Android支持库,它还有一些新的注释,如@ActivityKey@ContributesAndroidInjector@Subcomponent.Builder等。所以我的问题是它带来了什么好处桌子。

这已在What are the advantages of using DispatchingAndroidInjector and the other dagger-android classes?

中得到解答
  

它是否解决了没有一个可以适用于所有子类的基类的inject方法的问题?

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开始,此方法首先遍历父片段,然后是Activity,最后是Application,以查找HasFragmentInjector并使用AndroidInjector<Fragment>注入片段的字段。

然而,HasFragmentInjector的存在并不意味着您应该使用Dagger 2开始管理碎片:

public class MainActivity {

     @Inject CoffeeFragment coffeeFragment; //no! don't do this
     @Inject TeaFragment teaFragment; //no!

您仍应使用实例化使用静态工厂方法的Fragments的惯用方法。当他们调用onAttach(Context context)时,例如,您使用事务添加片段或委托给ViewPager时,Dagger 2将对片段内的字段执行注入。以下代码是一个非常简单的Activity,带有ViewPager和两个片段:

,而不是上面的例子
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正确处理Fragments的管理,我们不会在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!!!!";
    }
}

答案 1 :(得分:2)

Official Documentation在我的观点中很好地解释了这个话题。

无论如何,主要的好处是,而不是像这样的东西

((SomeApplicationBaseType) getContext().getApplicationContext())
    .getApplicationComponent()
    .newActivityComponentBuilder()
    .activity(this)
    .build()
    .inject(this);

你可以简单地写这个,这让每个人的生活更轻松。

AndroidInjection.inject(this);
  1. 更少的样板,更易于维护。

  2. 以前的方法有点打破了依赖注入的基本概念,类不应该知道有关依赖注入方式的任何细节。