“ HasFragmentInjector”的实际用法是什么?在Dagger 2中 [英] What is actual usage of "HasFragmentInjector" in Dagger 2

查看:84
本文介绍了“ HasFragmentInjector”的实际用法是什么?在Dagger 2中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我知道 @Provide @Modules 的旧方法。和 @Components 等批注,但是从Dagger 2.8开始,他们添加了这个android-support库,其中还包含一些新的注入,例如 @ActivityKey @ContributesAndroidInjector @ Subcomponent.Builder 等。



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



它是否解决了诸如带有基类的Inject方法可以适用于所有子类的问题?还是有其他好处?



第二个问题-HasFragmentInjector只是将片段加载到活动中,就像我们以前使用片段管理器所做的那样?还是我丢失了某些东西?



请不要为所有图书馆用户投票赞成更多信息的问题,因为图书馆的文档未提供此类答案。

解决方案

第一个问题


在Dagger 2.8+中,他们添加了这个android-support库,其中还包含一些新的注释,例如 @ActivityKey @ContributesAndroidInjector @ Subcomponent.Builder 等。所以我的问题是它给表带来了什么好处。


这已经在使用DispatchingAndroidInjector和其他dagger-android类有什么优势?


可以吗?解决诸如在基类上没有注入方法这样的问题可以为所有子类工作吗?


Dagger 2在编译时使用代码生成进行依赖项注入。在此方面,它与其他依赖项注入框架(例如Guice)不同,后者在运行时检查注入站点。为了使Dagger 2正常工作,您必须在某个时候指定注入部位的不变性。因此,将永远不可能这样写:

  void inject(Activity activity); 

在Dagger 2组件内部,并注入所有活动。



但是,dagger-android中提供的新类进行了许多改进。而之前您必须编写:

  void inject(MainActivity mainActivity); 

依此类推,对于每个不同的注射部位,现在可以编写以下代码:

  @Module(子组件= MainActivitySubcomponent.class)
公共抽象类MainActivityModule {

@Binds
@IntoMap
@ActivityKey(MainActivity.class)
抽象的AndroidInjector.Factory< ;?扩展Activity> mainActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
}

然后:

  AndroidInjection.inject(this); 

在适当的时候在MainActivity内部。



第二个问题


HasFragmentInjector只是将Fragment加载到Activity中,就像我们以前使用FragmentManager一样吗?还是我丢失了什么?


HasFragmentInjector 只是将片段标记在类上应该从中获取其 AndroidInjector 。您可以在GitHub上的代码 / a>用于 AndroidInjection#inject(片段片段)

  public静态无效注入(片段片段){
checkNotNull(fragment, fragment);
HasFragmentInjector hasFragmentInjector = findHasFragmentInjector(fragment);
Log.d(TAG,String.format(
在%s中找到%s的注入器,
fragment.getClass()。getCanonicalName(),
hasFragmentInjector .getClass()。getCanonicalName()));

AndroidInjector< Fragment> fragmentInjector = hasFragmentInjector.fragmentInjector();
checkNotNull(fragmentInjector,%s.fragmentInjector()返回null,
hasFragmentInjector.getClass()。getCanonicalName());
fragmentInjector.inject(fragment);
}

从javadoc中,此方法首先遍历父片段,然后遍历Activity ,最后,应用程序找到 HasFragmentInjector 并使用 AndroidInjector< Fragment> 注入Fragment的字段。 / p>

但是, HasFragmentInjector 的存在并不意味着您应该开始使用Dagger 2管理片段。

 公共类MainActivity {

@Inject CoffeeFragment coffeeFragment; //没有!不要这样做
@Inject TeaFragment teaFragment; //没有!

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

 公共类MainActivity扩展了AppCompatActivity实现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 drinksPagerAdapter = new BeveragesPagerAdapter(getSupportFragmentManager());
mViewPager =(ViewPager)findViewById(R.id.viewpager);
mViewPager.setAdapter(beveragesPagerAdapter);
}

类BeveragesPagerAdapter扩展FragmentStatePagerAdapter {

public BeveragesPagerAdapter(FragmentManager fm){
super(fm);
}

@Override
public Fragment getItem(int i){
switch(i){
case 0:
返回TeaFragment。实例化(new Bundle());
情况1:
返回CoffeeFragment.instantiate(new Bundle());
默认值:
抛出新的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正确处理了片段的管理,我们



片段本身看起来像这样:



CoffeeFragment中.java

 公共类CoffeeFragment扩展Fragment {

public static CoffeeFragment instantiate( @Nullable Bundle参数){
CoffeeFragment coffeeFragment = new CoffeeFragment();
coffeeFragment.setArguments(arguments);
return coffeeFragment;
}

@Inject
@Named( Coffee)
存储库;

TextView textView;

@Override
public void onAttach(Context context){
AndroidSupportInjection.inject(this);
super.onAttach(上下文);
}

@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)
公共抽象类CoffeeFragmentModule {

@Binds
@Named( Coffee)
抽象存储库(CoffeeRepository coffeeRepository);

@Binds
@IntoMap
@FragmentKey(CoffeeFragment.class)
abstract AndroidInjector.Factory< ;?延伸Fragment> bindCoffeeFragmentInjectorFactory(CoffeeFragmentSubcomponent.Builder builder);
}

CoffeeFragmentSubcomponent.java 中:

  @Subcomponent 
公共接口CoffeeFragmentSubcomponent扩展了AndroidInjector< CoffeeFragment>。 {

@ Subcomponent.Builder
抽象类Builder扩展了AndroidInjector.Builder< CoffeeFragment> {}
}

CoffeeRepository.java 中:

 公共类CoffeeRepository实现存储库{

@Inject
public CoffeeRepository(){
}

@Override
public String Retrieve(){
return Coffee !!!!;
}
}


I have implemented dagger2 v2.2 previously but as now they have added dagger.android part also. so I am creating sample project with that.

I am aware about old methodology of @Provide and @Modules and @Components etc annotations but from Dagger 2.8+ they have added this android-support library also which have some new Injections like @ActivityKey, @ContributesAndroidInjector, @Subcomponent.Builder etc.

So my question is what benefits it brings to the table.

Does it resolve problems like Inject method with base class can work for all child class ? or Any other benefits ?

2nd question - HasFragmentInjector is just to load fragment inside activity like we used to do using fragment manager ? or I am missing some thing ?

Please don't downvote its more informative question for all library users as documentation of library don't provide such answers.

解决方案

First question

In Dagger 2.8+ they have added this android-support library also which have some new annotations like @ActivityKey, @ContributesAndroidInjector, @Subcomponent.Builder etc. So my question is what benefits it brings to the table.

This has already been answered in What are the advantages of using DispatchingAndroidInjector and the other dagger-android classes?

Does it resolve problems like not having an inject method for a base class that can work for all child class?

Dagger 2 uses code generation at compile time for dependency injection. In this, it is different from other dependency injection frameworks like Guice that inspect injection sites at runtime. In order for Dagger 2 to work, you must at some point specify the invariant of the injection site. Therefore it will never be possible to write something like:

void inject(Activity activity);

inside a Dagger 2 component and have it inject all activities.

However, there are many improvements with the new classes available in dagger-android. Whereas before you would have to write:

void inject(MainActivity mainActivity);

and so on for each different injection site you can now write the following code:

@Module(subcomponents = MainActivitySubcomponent.class)
public abstract class MainActivityModule {

    @Binds
    @IntoMap
    @ActivityKey(MainActivity.class)
    abstract AndroidInjector.Factory<? extends Activity> mainActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
 }

and then:

AndroidInjection.inject(this);

inside your MainActivity at the appropriate point.

Second question

HasFragmentInjector is just to load Fragment inside Activity like we used to do using FragmentManager? or I am missing something?

HasFragmentInjector simply marks the class where the Fragment should get its AndroidInjector from. You can see for yourself in the code on GitHub for 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);
} 

From the javadoc, this method walks first the parent-fragment, then the Activity, then finally the Application to find HasFragmentInjector and uses the AndroidInjector<Fragment> to inject the fields of the Fragment.

However, the presence of HasFragmentInjector does not mean that you should start managing Fragments using Dagger 2:

public class MainActivity {

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

You should still use the idiomatic way of instantiating Fragments which is using static factory methods. Dagger 2 will perform injection for the fields inside the Fragments when their onAttach(Context context) is invoked when, say, you add the Fragment using a transaction or you delegate to a ViewPager. Instead of the above example, the following code is a very simple Activity with a ViewPager and two Fragments:

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;
    }
}

The FragmentStatePagerAdapter correctly handles the management of the Fragments and we do not inject as fields inside MainActivity.

The Fragments themselves look like this:

in 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());
    }
}

in 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);
}

in CoffeeFragmentSubcomponent.java:

@Subcomponent
public interface CoffeeFragmentSubcomponent extends AndroidInjector<CoffeeFragment> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<CoffeeFragment> {}
}

in CoffeeRepository.java:

public class CoffeeRepository implements Repository {

    @Inject
    public CoffeeRepository() {
    }

    @Override
    public String retrieve() {
        return "Coffee!!!!";
    }
}

这篇关于“ HasFragmentInjector”的实际用法是什么?在Dagger 2中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆