Hilt:自动获取 Fragment LifecycleOwner 和上下文

Hilt: Get Fragment LifecycleOwner and context automagically

我想在将依赖项注入片段时自动获取片段上下文和 lifecycleOwner(例如此处的 viewLifecycleOwner)。我的问题是,该怎么做,因为没有对应的@FragmentContext,就像有@ActivityContext 一样。此外,我想为这个依赖项动态分配一个变量。

我的依赖

class LoginDialog(
    context: Context, // get this from fragment
    private val mLifecycleOwner: LifecycleOwner, // get this from fragment
    private val loginTitle: LoginTitle, // define this when injecting
) : AlertDialog(context, R.style.LoginDialogTheme) {
    private var _binding: LoginLoadingScreenBinding? = null
    private val binding: LoginLoadingScreenBinding get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        initDialog()
        super.onCreate(savedInstanceState)
    }

    override fun show() {
        if (isShowing) return
        _binding = LoginLoadingScreenBinding.inflate(layoutInflater).apply { lifecycleOwner = mLifecycleOwner }
        super.show()
    }

    override fun dismiss() {
        _binding = null
        super.dismiss()
    }

    /**
     * Calls show internally
     */
    fun onChangeIndicator(mText: String) {
        show()
        binding.indicator = mText
    }

    private fun initDialog() {
        setTitle(loginTitle.title)
        setCancelable(false)
        setView(binding.root)
    }

    sealed class LoginTitle(@StringRes val title: Int) {
        object Login : LoginTitle(R.string.loading_login_title)
        object Registration : LoginTitle(R.string.loading_registration_title)
        object ChangingEmail : LoginTitle(R.string.user_data_changing_email)
    }

}

注射

@AndroidEntryPoint
class FragmentA : Fragment() {

    // here, context is requireContext(), 
    // lifecycleOwner is viewLifecylceOwner
    // and loginTitle is LoginDialog.LoginTitle.Login
    @Inject 
    @LoginTitleLogin
    lateinit var loginDialog: LoginDialog
}

好的,我已经通过创建一个刀柄模块并稍微更改构造函数来解决这个问题,这是解决方案:

依赖关系

class LoginDialog(
    private val fragment: Fragment,
    private val loginTitle: LoginTitle,
) : AlertDialog(fragment.requireContext(), R.style.LoginDialogTheme) {
    private var _binding: LoginLoadingScreenBinding? = null
    private val binding: LoginLoadingScreenBinding get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        initDialog()
        super.onCreate(savedInstanceState)
    }

    override fun show() {
        if (isShowing) return
        _binding = LoginLoadingScreenBinding.inflate(layoutInflater).apply { lifecycleOwner = fragment.viewLifecycleOwner }
        super.show()
    }

    override fun dismiss() {
        _binding = null
        super.dismiss()
    }

    /**
     * Calls show internally
     */
    fun onChangeIndicator(mText: String) {
        show()
        binding.indicator = mText
    }

    private fun initDialog() {
        setTitle(loginTitle.title)
        setCancelable(false)
        setView(binding.root)
    }

    sealed class LoginTitle(@StringRes val title: Int) {
        object Login : LoginTitle(R.string.loading_login_title)
        object Registration : LoginTitle(R.string.loading_registration_title)
        object ChangingEmail : LoginTitle(R.string.user_data_changing_email)
    }

}

模块

@Module
@InstallIn(FragmentComponent::class)
object FragmentModule {

    @LoginTitle
    @Provides
    fun provideLoginDialogWithLoginTitle(fragment: Fragment) = LoginDialog(
        fragment,
        LoginDialog.LoginTitle.Login
    )

    @RegistrationTitle
    @Provides
    fun provideLoginDialogWithRegistrationTitle(fragment: Fragment) = LoginDialog(
        fragment,
        LoginDialog.LoginTitle.Registration
    )

    @ChangingEmailTitle
    @Provides
    fun provideLoginDialogWithChangingEmailTitle(fragment: Fragment) = LoginDialog(
        fragment,
        LoginDialog.LoginTitle.ChangingEmail
    )

}

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class LoginTitle

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class RegistrationTitle

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class ChangingEmailTitle

用法

@AndroidEntryPoint
class MyFragment : Fragment() {


    @Inject
    @LoginTitle
    lateinit var loginDialog: LoginDialog
}