如何使用 Hilt 绑定/提供 Activity 或 Fragment?

Dan*_*nny 6 android dependency-injection kotlin dagger-hilt

我正在尝试在 Android 应用程序上实现 Hilt,虽然与 Dagger 相比,它很容易实现并删除了很多样板代码,但我想念一些东西,比如构建我自己的组件并自己确定它们的范围,所以我将有我自己的hirerchy。

重点: 示例:假设我有一个简单的应用程序,其中包含一个 RecyclerView、Adapter、Acitivity 和嵌套在我的 Adapter 中的回调,我将它传递到我的 Adapter 构造函数中以检测点击或其他任何东西,并且我让我的活动实现那个回调,当然我想注入适配器。

class @Inject constructor (callBack: Callback): RecyclerView.Adapter...
Run Code Online (Sandbox Code Playgroud)

当我让 Hilt 知道我想注入我的适配器时,我需要让 Hilt 知道如何提供所有适配器依赖项 - 回调。

在 Dagger 中,我能够通过将 Activity 绑定到我的模块之一中的回调来实现这一点:

@Binds fun bindCallback(activity: MyActivity): Adapter.Callback
Run Code Online (Sandbox Code Playgroud)

Dagger 知道如何绑定 Activity(或任何 Activity/Fragment),然后将其链接到该回调,但是使用 Hilt 它不起作用。

我怎样才能做到这一点?如何使用 Hilt 提供或绑定 Activity 或 Fragment?

Dan*_*nny 7

解决方法很简单。

所以几天前我回来看我的问题才发现仍然没有新的解决方案,所以我尝试了 Bartek 解决方案,但无法使其工作,即使它确实工作,干净的 Hilt 代码变得太乱了,所以我做了一点调查并玩了一点,发现解决方案实际上非常简单。

它是这样的:

应用程序:

@HiltAndroidApp
class MyApp: Application()
Run Code Online (Sandbox Code Playgroud)

活动:(实现回调)

@AndroidEntryPoint
class MainActivity : AppCompatActivity(), SomeClass.Callback {

    @Inject
    lateinit var someClass: SomeClass

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)  
    }

    override fun onWhatEver() {
        // implement
    }
}
Run Code Online (Sandbox Code Playgroud)

SomeClass:(带有内部回调)

class SomeClass @Inject constructor(
    private val callback: Callback
) {

    fun activateCallback(){
        callback.onWhatEver()
    }

    interface Callback{
        fun onWhatEver()
    }
}
Run Code Online (Sandbox Code Playgroud)

SomeModule:(提供/绑定活动到回调)

@Module
@InstallIn(ActivityComponent::class)
object SomeModule{

    @Provides
    fun provideCallback(activity: Activity) =
        activity as SomeClass.Callback
    
}
Run Code Online (Sandbox Code Playgroud)

这就是我们所需要的。我们不能使用@Bind 将活动绑定到回调,因为它需要明确提供并转换为回调,以便应用程序可以构建。

该模块安装在 ActivityComponent 中并且知道一个通​​用的“活动”,如果我们将其转换为回调,则 Hilt 是内容并且活动绑定到回调,并且只要其在,Hilt 就会知道如何提供回调具体活动范围。

多个活动/片段

应用程序:

@HiltAndroidApp
class MyApp: Application()
Run Code Online (Sandbox Code Playgroud)

图书活动:

@AndroidEntryPoint
class BooksActivity : AppCompatActivity(), BooksAdapter.Callback{

        @Inject
        lateinit var adapter: BooksAdapter

        ...

        override fun onItemClicked(book: Book) {...}
    }
}
Run Code Online (Sandbox Code Playgroud)

作者活动:

@AndroidEntryPoint
class AuthorsActivity : AppCompatActivity(), AuthorsAdapter.Callback{

    @Inject
    lateinit var adapter: AuthorsAdapter

    ...

    override fun onItemClicked(author: Author) {...}
}
Run Code Online (Sandbox Code Playgroud)

书籍适配器

class BooksAdapter @Inject constructor (
    val callback: Callback
) ... {

    ...

    interface Callback{
        fun onItemClicked(book: Book)
    }
}
Run Code Online (Sandbox Code Playgroud)

作者适配器

class AuthorsAdapter @Inject constructor (
    val callback: Callback
) ... {

    ...

    interface Callback{
        fun onItemClicked(auhtor: Auhtor)
    }
}
Run Code Online (Sandbox Code Playgroud)

作者模块

@Module
@InstallIn(ActivityComponent::class)
object AuthorsModule {
    @Provides
    fun provideCallback(activity: Activity) =
        activity as AuthorsAdapter.Callback
}
Run Code Online (Sandbox Code Playgroud)

图书模块

@Module
@InstallIn(ActivityComponent::class)
object BooksModule {
    @Provides
    fun provideCallback(activity: Activity) =
        activity as BooksAdapter.Callback
}
Run Code Online (Sandbox Code Playgroud)

模块可以毫无问题地加入一个模块,只需更改函数的名称。

这当然适用于更多活动和/或多个片段......适用于所有逻辑情况。

  • 很高兴您为您的案例解决了这个问题!恭喜!我的两分钱:我会采用更复杂但明确的依赖组件结构,而不是一周中的每一天都深埋在“模块”结构中的运行时、未经检查的转换。在任何具有多个“活动”的项目中,您的方法只是自找麻烦。 (3认同)

Bar*_*ski 6

Hilt 可以提供泛型的实例Activity(就此而言)作为(和分别)Fragment内的依赖项。它只是无法提供您的特定实例ActivityComponentFragmentComponentMyActivity.

您仍然可以在 Hilt 中创建您自己的Component。您只需component自行管理实例即可。添加MyActivity作为组件生成器的种子数据,您应该能够毫无问题地进行@Bind操作。Callback

  • 创建自定义组件的示例? (2认同)