Kyle Angelo Gonzales
Kyle Angelo Gonzales

Reputation: 1007

How should I inject Fused Location Provider Client into ViewModel in MVVM (With Compose and Dagger-Hilt)

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

Answers (1)

Quốc Hùng
Quốc Hùng

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

Related Questions