Kotlin中无法创建SharedPrefViewModel实例问题求助
java.lang.RuntimeException: Cannot create an instance of class com.meetme.viewmodel.SharedPrefViewModel
相关代码
SharedPrefViewModel类
class SharedPrefViewModel(context: Context): ViewModel() { private var sharedPrefRepository: SharedPrefRepository = SharedPrefRepository(context.applicationContext) fun putString(name: String) { sharedPrefRepository.putString(name) } fun getString() : String? { return sharedPrefRepository.getString() // 错误发生在此处 } }
SharedPrefRepository类
class SharedPrefRepository(context: Context) { private val pref: SharedPreferences = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) var name: String? get() = pref.getString(PREF_LOGGED_IN, "") set(value) = pref.edit().putString(PREF_LOGGED_IN, value).apply() fun putString(name: String) { this.name = name } fun getString() : String? { return this.name } }
保存名称的Composable
@Composable fun BasicInfoScreen(navController: NavHostController) { var context = LocalContext.current.applicationContext val sharedPrefViewModel = SharedPrefViewModel(context) Column( modifier = Modifier .fillMaxSize() .background(Color.White) .padding(16.dp) ) { ... Button( onClick = { sharedPrefViewModel.putString("default") // 在此处调用 navController.navigate(RootGraphItem.Location.route) }, modifier = Modifier .fillMaxWidth() .height(50.dp) .background(Color(0xFF0090FF)), colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFF0090FF)) ) { Text(text = "Next", style = TextStyle(color = Color.White)) } } }
获取偏好值的Composable
@Composable fun LocationScreen(navController: NavHostController) { val sharedPrefViewModel: SharedPrefViewModel = viewModel() println(sharedPrefViewModel.getString()) // 获取名称 Column( modifier = Modifier .fillMaxSize() .background(Color.White) .padding(16.dp) ) { ... } }
问题原因
ViewModel实例化逻辑冲突:
- 在
BasicInfoScreen中手动通过构造函数创建SharedPrefViewModel实例,违背Jetpack ViewModel的管理规范; - 在
LocationScreen中使用viewModel()方法获取实例时,系统会尝试调用ViewModel的无参构造函数,但你的SharedPrefViewModel仅提供带Context参数的构造函数,导致实例化失败抛出异常。
- 在
ViewModel持有Context的风险:
ViewModel直接持有Context可能引发内存泄漏,不符合组件设计原则。
解决步骤
步骤1:修改ViewModel继承类
将SharedPrefViewModel改为继承AndroidViewModel,它自带Application上下文,无需手动传递:
class SharedPrefViewModel(application: Application) : AndroidViewModel(application) { private var sharedPrefRepository: SharedPrefRepository = SharedPrefRepository(application) fun putString(name: String) { sharedPrefRepository.putString(name) } fun getString() : String? { return sharedPrefRepository.getString() } }
步骤2:统一ViewModel获取方式
所有Composable中都使用viewModel()方法获取ViewModel实例,禁止手动构造:
修改BasicInfoScreen中的代码:
@Composable fun BasicInfoScreen(navController: NavHostController) { val sharedPrefViewModel: SharedPrefViewModel = viewModel() Column( modifier = Modifier .fillMaxSize() .background(Color.White) .padding(16.dp) ) { ... Button( onClick = { sharedPrefViewModel.putString("default") navController.navigate(RootGraphItem.Location.route) }, modifier = Modifier .fillMaxWidth() .height(50.dp) .background(Color(0xFF0090FF)), colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFF0090FF)) ) { Text(text = "Next", style = TextStyle(color = Color.White)) } } }
步骤3:优化Repository(可选)
去掉冗余的包装方法,直接使用属性访问简化代码:
class SharedPrefRepository(context: Context) { private val pref: SharedPreferences = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) var name: String? get() = pref.getString(PREF_LOGGED_IN, "") set(value) = pref.edit().putString(PREF_LOGGED_IN, value).apply() }
对应ViewModel可同步简化:
class SharedPrefViewModel(application: Application) : AndroidViewModel(application) { private val sharedPrefRepository = SharedPrefRepository(application) fun saveName(name: String) { sharedPrefRepository.name = name } fun getName() : String? { return sharedPrefRepository.name } }
内容的提问来源于stack exchange,提问作者Yunnane
相关产品推荐
相关产品推荐

