Reputation: 1007
Context of the Problem
I'm currently learning how to use the MVVM pattern with Compose and dependency injection with Dagger-Hilt.
I need to create a FusedLocationProviderClient so I can update the location state of my GoogleMap Composable from my View Model.
Considerations
I believe that the FusedLocationProviderClient should be created from the Main Activity since it is an android-specific operation (and it requires an activity context). I also don't want to be passing my activity context to my view models because they cause memory leaks.
At the same time, since I am using Dagger-Hilt, I don't need to create my ViewModels in the Activity since they can easily be injected into my composable screens with:
@Composable
fun MainScreen(viewModel : MainViewModel = hiltViewModel()) {/*UI logic*/}
In my MainActivity
, the only composable in setContent{}
is a function that has the NavHost
and the NavGraphBuilder
:
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private lateinit var navController: NavHostController
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private var latitude = 0.0
private var longitude = 0.0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
setContent {
MyTheme {
navController = rememberAnimatedNavController()
Navigation(navController)
}
}
}
Problem
So, while following MVVM principles, how can I inject the FusedLocationProviderClient
into my ViewModel if the ViewModel doesn't have to be created in the MainActivity?
Thanks!
Note: I'm also trying to avoid using AndroidViewModel to get context since it will be more difficult to unit test.
Upvotes: 1
Views: 1228
Reputation: 451
If you are using hilt, you can provide the FusedLocationProviderClient
via module like:
@Module
@InstallIn(SingletonComponent::class)
class LocationModule {
@Provides
fun provideFusedLocationProviderClient(
@ApplicationContext context: Context
): FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
}
And then just inject the FusedLocationProviderClient in your view model that need to be used:
@HiltViewModel
class MainViewModel @Inject constructor(
private val locationClient: FusedLocationProviderClient
) : ViewModel() {
...
}
As I see the LocationServices.getFusedLocationProviderClient() just required Context parameter, not Activity so I think you can use the SingletonComponent for the module and @ApplicationContext for the context, but if it only requires the activity context, you can try to use the ActivityRetainedComponent for the module and @ActivityContext for the context, it will get the context of the activity for the getFusedLocationProviderClient() method
Upvotes: 3