The solution is quite simple.
So a few days ago I came back to look at my question only to see that there was still no new solution, so I tried Bartek solution and wasn't able to make it work, and even if it did work, the clean Hilt code was becoming too messy, so I did a little investigation and played a little and discovered that the solution is actually stupidly easy.
It goes like this:
App:
@HiltAndroidApp
class MyApp: Application()
Activity: (implements callback)
@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
}
}
SomeClass: (with inner callback)
class SomeClass @Inject constructor(
private val callback: Callback
) {
fun activateCallback(){
callback.onWhatEver()
}
interface Callback{
fun onWhatEver()
}
}
SomeModule: (providing/binding the activity to the callback)
@Module
@InstallIn(ActivityComponent::class)
object SomeModule{
@Provides
fun provideCallback(activity: Activity) =
activity as SomeClass.Callback
}
And that's all we need.
We cannot bind the activity to the callback with @Bind because it needs to be explicitly provided and cast to the callback so that the app can build.
The module is installed in ActivityComponent and is aware of a generic 'activity', if we cast it to the callback, Hilt is content and the activity is bound to the callback, and Hilt will know how to provide the callback as long as its in the specific activity scope.
Multiple Activities/Fragments
App:
@HiltAndroidApp
class MyApp: Application()
BooksActivity:
@AndroidEntryPoint
class BooksActivity : AppCompatActivity(), BooksAdapter.Callback{
@Inject
lateinit var adapter: BooksAdapter
...
override fun onItemClicked(book: Book) {...}
}
}
AuthorsActivity:
@AndroidEntryPoint
class AuthorsActivity : AppCompatActivity(), AuthorsAdapter.Callback{
@Inject
lateinit var adapter: AuthorsAdapter
...
override fun onItemClicked(author: Author) {...}
}
BooksAdapter
class BooksAdapter @Inject constructor (
val callback: Callback
) ... {
...
interface Callback{
fun onItemClicked(book: Book)
}
}
AuthorsAdapter
class AuthorsAdapter @Inject constructor (
val callback: Callback
) ... {
...
interface Callback{
fun onItemClicked(auhtor: Auhtor)
}
}
AuhtorsModule
@Module
@InstallIn(ActivityComponent::class)
object AuthorsModule {
@Provides
fun provideCallback(activity: Activity) =
activity as AuthorsAdapter.Callback
}
BooksModule
@Module
@InstallIn(ActivityComponent::class)
object BooksModule {
@Provides
fun provideCallback(activity: Activity) =
activity as BooksAdapter.Callback
}
The Modules can be joined to one module with no problem, just change the names of the functions.
This is offcourse applicable for more activities and/or multiple fragments.. for all logical cases.