Jetpack Compose:如何在非可组合函数(ViewModel)中获取Context
在ViewModel中获取Context的正确方式
ViewModel设计初衷是避免持有UI层引用(比如Activity/Fragment的Context),防止内存泄漏,但如果确实需要Context访问全局资源、SharedPreferences等,推荐以下两种安全方案:
1. 使用AndroidViewModel(推荐)
AndroidViewModel是ViewModel的子类,专为Android环境设计,构造函数接收Application实例——而Application本身就是全局Context,生命周期与应用一致,不会引发内存泄漏。
修改你的LoginViewModel代码,改为继承AndroidViewModel并获取Application Context:
import android.app.Application import android.content.Context import androidx.lifecycle.AndroidViewModel class LoginViewModel( application: Application, private val _global: GlobalServices = GlobalServices(), private val _login: LoginModel = LoginModel(), private val _loginService: LoginService = LoginService(), private val retrofitService: IRetrofitService = RetrofitService(), // 若Storage需要Context,直接传入Application级Context private val storage: Storage = Storage(application.applicationContext) ) : AndroidViewModel(application) { // 全局Context,随时可调用 private val appContext: Context get() = getApplication<Application>().applicationContext // 原有属性保持不变 val paddingMain = 10.dp val isChecked = mutableStateOf(false) val disabled = mutableStateOf(true) val iconSize = 150.dp val signInFail = mutableStateOf(false) val showSuccess = mutableStateOf(false) val global = _global val login = mutableStateOf(_login, policy = neverEqualPolicy()) fun setEmail(email: String) { login.value.correo = email refreshStateOfLogin() } fun setPassword(ppassword: String) { login.value.password = ppassword refreshStateOfLogin() } private fun refreshStateOfLogin() { // 示例:用Context访问资源 val errorMsg = appContext.getString(R.string.login_error) // 其他业务逻辑 } }
在Compose中创建ViewModel时,viewModel()会自动处理Application参数传递:
@Composable fun LoginScreen() { val viewModel: LoginViewModel = viewModel() // 你的Compose UI代码 }
2. 构造函数传入Application级Context(备选)
如果不想使用AndroidViewModel,可以在ViewModel构造中直接传入Application或applicationContext,但必须确保传入的是全局Context,绝对不能传入Activity/Fragment的Context(否则会因持有UI组件引用导致内存泄漏)。
修改后的ViewModel示例:
class LoginViewModel( private val appContext: Context, private val _global: GlobalServices = GlobalServices(), private val _login: LoginModel = LoginModel(), private val _loginService: LoginService = LoginService(), private val retrofitService: IRetrofitService = RetrofitService(), private val storage: Storage = Storage(appContext) ) : ViewModel() { // 原有属性和方法保持不变 // ... }
在Compose中创建时,从LocalContext获取Application实例:
@Composable fun LoginScreen() { val context = LocalContext.current val viewModel: LoginViewModel = remember { LoginViewModel(context.applicationContext) } // 你的Compose UI代码 }
关键注意事项
- 绝对不要在ViewModel中持有Activity或Fragment的Context,这类Context生命周期与UI组件绑定,ViewModel销毁时机晚于UI组件,会导致内存泄漏。
- 优先使用
AndroidViewModel,它是Jetpack提供的标准方案,能避免手动管理Context生命周期的风险。 - 若依赖(如
Storage)需要Context,尽量在构造时传入Application级Context,保持依赖清晰且安全。
内容的提问来源于stack exchange,提问作者sofnomic cr
相关产品推荐
相关产品推荐

