如何将DestinationsNavigator注入ViewModel依赖的Navigator类
实现导航逻辑从Composable到ViewModel的迁移(基于Compose Destinations + Hilt)
下面提供两种可行方案,分别适用于复杂解耦场景和简单快速实现场景:
方案一:基于AssistedInject的解耦实现(推荐复杂项目使用)
这种方案让ViewModel完全依赖自定义导航接口,不直接绑定Compose导航实现,解耦性更强。
1. 添加依赖
确保模块级build.gradle中包含以下依赖:
plugins { id 'kotlin-kapt' id 'dagger.hilt.android.plugin' } dependencies { // Hilt核心 implementation "com.google.dagger:hilt-android:2.44" kapt "com.google.dagger:hilt-android-compiler:2.44" // Hilt导航Compose支持 implementation "androidx.hilt:hilt-navigation-compose:1.0.0" // AssistedInject implementation "com.google.dagger:hilt-assisted-inject:2.44" kapt "com.google.dagger:hilt-compiler:2.44" }
2. 定义导航接口
封装所有导航操作,让ViewModel依赖抽象而非具体实现:
interface Navigator { fun navigateToProfile(userParam: String) fun navigateBack() // 根据需求添加其他导航方法 }
3. 实现导航接口
创建具体实现类,通过AssistedInject接收Compose Destinations的导航实例:
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import dagger.assisted.Assisted import dagger.assisted.AssistedInject class NavigatorImpl @AssistedInject constructor( @Assisted private val navigator: DestinationsNavigator ) : Navigator { override fun navigateToProfile(userParam: String) { // 替换为你的实际Destination参数逻辑 navigator.navigate(ProfileDestination(userParam)) } override fun navigateBack() { navigator.navigateUp() } // 提供工厂类用于创建实例 @AssistedFactory interface Factory { fun create(navigator: DestinationsNavigator): NavigatorImpl } }
4. 修改ViewModel使用AssistedInject
让ViewModel通过AssistedInject注入自定义Navigator:
import androidx.lifecycle.ViewModel import dagger.assisted.Assisted import dagger.assisted.AssistedInject import dagger.assisted.AssistedFactory class WelcomeViewModel @AssistedInject constructor( private val navigator: Navigator ) : ViewModel() { fun onProfileButtonClick(userParam: String) { // 直接调用导航方法,无需处理事件流 navigator.navigateToProfile(userParam) } fun onBackClick() { navigator.navigateBack() } // ViewModel工厂类 @AssistedFactory interface Factory { fun create(navigator: Navigator): WelcomeViewModel } companion object { // 提供ViewModelProvider.Factory,供Composable调用 fun provideFactory( factory: Factory, navigator: Navigator ): ViewModelProvider.Factory = object : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>): T { return factory.create(navigator) as T } } } }
5. 简化Composable代码
Composable仅负责创建实例和传递UI事件,不再处理导航逻辑:
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootNavGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.viewmodel.compose.viewModel @RootNavGraph(start = true) @Destination @Composable fun Welcome( navController: DestinationsNavigator, navigatorFactory: NavigatorImpl.Factory = hiltViewModel(), welcomeViewModelFactory: WelcomeViewModel.Factory = hiltViewModel() ) { val navigator = navigatorFactory.create(navController) val viewModel = viewModel<WelcomeViewModel>( factory = WelcomeViewModel.provideFactory(welcomeViewModelFactory, navigator) ) // 仅传递UI交互事件给ViewModel WelcomeView( onProfileClick = { userParam -> viewModel.onProfileButtonClick(userParam) }, onBackClick = { viewModel.onBackClick() } ) }
6. 配置Hilt基础
确保Application类添加注解:
import dagger.hilt.android.HiltAndroidApp @HiltAndroidApp class MyApp : Application()
Activity添加注解:
import dagger.hilt.android.AndroidEntryPoint import androidx.activity.compose.setContent @AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyAppTheme { DestinationsNavHost(navGraph = NavGraphs.root) } } } }
方案二:基于SharedFlow的简单实现(适合小型项目)
这种方式无需额外依赖,通过单例类传递导航命令,实现快速迁移。
1. 定义导航命令密封类
sealed class NavigationCommand { data class NavigateToProfile(val param: String) : NavigationCommand() object NavigateBack : NavigationCommand() }
2. 创建单例导航类
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow object Navigator { private val _commands = MutableSharedFlow<NavigationCommand>() val commands = _commands.asSharedFlow() fun navigateToProfile(param: String) { _commands.tryEmit(NavigationCommand.NavigateToProfile(param)) } fun navigateBack() { _commands.tryEmit(NavigationCommand.NavigateBack) } }
3. 修改ViewModel
import androidx.lifecycle.ViewModel class WelcomeViewModel : ViewModel() { fun onProfileButtonClick(param: String) { Navigator.navigateToProfile(param) } fun onBackClick() { Navigator.navigateBack() } }
4. 简化Composable
仅保留一次Flow收集逻辑,不再处理ViewModel的事件流:
@RootNavGraph(start = true) @Destination @Composable fun Welcome( navController: DestinationsNavigator, viewModel: WelcomeViewModel = hiltViewModel() ) { LaunchedEffect(key1 = true) { Navigator.commands.collect { command -> when (command) { is NavigationCommand.NavigateToProfile -> { navController.navigate(ProfileDestination(command.param)) } NavigationCommand.NavigateBack -> { navController.navigateUp() } } } } WelcomeView( onProfileClick = { param -> viewModel.onProfileButtonClick(param) }, onBackClick = { viewModel.onBackClick() } ) }
内容的提问来源于stack exchange,提问作者Oleh Kuchura
相关产品推荐
相关产品推荐

