Android/Kotlin中EasyPermissions.requestPermissions调用参数错误问题
错误信息
None of the following functions can be called with the arguments supplied:
public open fun requestPermissions(host: Activity, rationale: String, requestCode: Int, vararg perms: String!): Unit defined in pub.devrel.easypermissions.EasyPermissions
public open fun requestPermissions(host: Fragment, rationale: String, requestCode: Int, vararg perms: String!): Unit defined in pub.devrel.easypermissions.EasyPermissions
原问题代码
@HiltViewModel class HomeViewModel @Inject constructor(): ViewModel() { private fun requestPermissions(context: Context) { if(TrackingUtility.hasLocationPermissions(context)) { return } if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { EasyPermissions.requestPermissions( host = this, rationale = "You need to accept location permissions to use this app.", requestCode = REQUEST_CODE_LOCATION_PERMISSIONS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION ) } else { } } }
问题原因
你在ViewModel中调用EasyPermissions.requestPermissions时传入host = this,但该方法要求host必须是Activity或Fragment类型——ViewModel属于业务逻辑层,不属于UI组件范畴,因此触发参数类型不匹配错误。更关键的是,ViewModel直接持有Activity/Fragment引用会引发内存泄漏,违反MVVM架构设计原则。
解决方案
通过事件通知实现ViewModel与UI层的通信,让对应的Activity/Fragment执行权限申请操作,具体实现如下:
1. 修改ViewModel,发送权限请求事件
用MutableSharedFlow定义权限请求事件,当需要申请权限时发送事件通知UI层:
@HiltViewModel class HomeViewModel @Inject constructor(): ViewModel() { // 定义权限请求事件,用于通知UI层发起申请 private val _requestLocationPermissions = MutableSharedFlow<Unit>() val requestLocationPermissions = _requestLocationPermissions.asSharedFlow() fun checkAndRequestPermissions(context: Context) { if(TrackingUtility.hasLocationPermissions(context)) { return } if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { // 发送事件,触发UI层的权限申请 viewModelScope.launch { _requestLocationPermissions.emit(Unit) } } else { // 处理Android Q及以上的位置权限逻辑 } } // 接收UI层传递的权限申请结果 fun onLocationPermissionsGranted() { // 权限通过后的业务逻辑处理 } }
2. 在Activity/Fragment中监听事件并申请权限
在UI层观察ViewModel的事件,触发时调用EasyPermissions.requestPermissions,并处理权限结果:
@AndroidEntryPoint class HomeActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks { private val viewModel: HomeViewModel by viewModels() private companion object { const val REQUEST_CODE_LOCATION_PERMISSIONS = 1001 } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) // 监听ViewModel的权限请求事件 lifecycleScope.launch { viewModel.requestLocationPermissions.collect { EasyPermissions.requestPermissions( host = this@HomeActivity, rationale = "You need to accept location permissions to use this app.", requestCode = REQUEST_CODE_LOCATION_PERMISSIONS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION ) } } } // 处理权限申请结果,委托给EasyPermissions override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this) } // 权限申请成功回调 @AfterPermissionGranted(REQUEST_CODE_LOCATION_PERMISSIONS) fun handleLocationPermissionGranted() { viewModel.onLocationPermissionsGranted() // 执行权限通过后的UI逻辑 } // 权限申请失败回调 override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) { // 处理权限拒绝逻辑,比如弹出提示引导用户去设置开启 } override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) { // 可选:直接处理成功逻辑,或者用@AfterPermissionGranted注解 } }
注意事项
- 禁止在ViewModel中持有Activity/Fragment的强引用,避免内存泄漏
- 用Jetpack协程Flow或LiveData实现跨层通信,符合MVVM架构规范
- 必须在UI层实现
EasyPermissions.PermissionCallbacks接口,处理权限申请的成功/失败逻辑
内容的提问来源于stack exchange,提问作者xMaster

