Dagger 2.11在Fragment注入Retrofit遇阻及架构疑问求助
问题1:不用DaggerFragment实现Fragment注入
首先你完全不用被迫把BaseFragment改成DaggerFragment,问题出在注入时机和全局配置上,咱们一步步修正:
先搞定Application和Activity的注入基础配置
- 你的Application需要继承
DaggerApplication,或者手动实现HasActivityInjector来提供Activity的注入器:class MyApp : Application(), HasActivityInjector { @Inject lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity> override fun onCreate() { super.onCreate() DaggerAppComponent.create().inject(this) } override fun activityInjector(): AndroidInjector<Activity> { return dispatchingActivityInjector } } - 宿主Activity要实现
HasFragmentInjector,并注入Fragment的分发注入器,这样Dagger才能识别并注入Fragment:class MainActivity : AppCompatActivity(), HasFragmentInjector { @Inject lateinit var dispatchingFragmentInjector: DispatchingAndroidInjector<Fragment> override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun fragmentInjector(): AndroidInjector<Fragment> { return dispatchingFragmentInjector } }
- 你的Application需要继承
修正Fragment的注入时机
你当前的onAttach重载写法混乱了,应该统一在onAttach(Context)中调用注入,并且放在super.onAttach(context)之前执行。修改你的BaseFragment:open class BaseFragment : Fragment() { override fun onAttach(context: Context) { AndroidInjection.inject(this) super.onAttach(context) } }这样HomeFragment继承后会自动在附着时完成注入,不用重复写注入逻辑,你之前同时注入activity和自身的操作完全没必要,反而会引发问题。
把HomeFragment关联到Dagger组件
你需要通过@ContributesAndroidInjector告诉Dagger如何注入这个Fragment。比如创建一个Activity关联的Module:@Module abstract class ActivityModule { @ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity @ContributesAndroidInjector abstract fun contributeHomeFragment(): HomeFragment }然后在AppComponent中引入这个Module和你的Retrofit提供Module:
@Singleton @Component(modules = [AndroidInjectionModule::class, ActivityModule::class, RetrofitModule::class]) interface AppComponent { fun inject(app: MyApp) }这里的
RetrofitModule是提供Retrofit单例的类,比如:@Module class RetrofitModule { @Provides @Singleton fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://your-api-base-url.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } }
问题2:是否需要为每个Activity单独创建Module和Component?
完全不用手动为每个Activity写Component!Dagger 2.11引入的@ContributesAndroidInjector就是为了简化这个流程:
- 如果多个Activity依赖逻辑相似:可以共用全局Module,甚至在
@ContributesAndroidInjector中不指定专属Module,直接复用Retrofit这类全局单例依赖。 - 如果Activity有独特依赖需求:再为它单独创建一个Module,通过
@ContributesAndroidInjector(modules = [XXXActivityModule::class])关联,这样该Activity的自动生成Subcomponent会同时包含全局依赖和专属依赖。
简单说,@ContributesAndroidInjector会帮你自动生成对应的Subcomponent,你只需要通过抽象Module声明关联关系就行,既保证架构清晰,又减少重复代码。
最后简化你的HomeFragment,去掉冗余代码:
class HomeFragment : BaseFragment() { @Inject lateinit var retrofit: Retrofit override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { // 此时retrofit已被正确注入 println("----Retrofit----"+retrofit.baseUrl()) return inflater.inflate(R.layout.fragment_home, container, false) } }
内容的提问来源于stack exchange,提问作者vishal sharma

