Android WebView文件选择器注册Activity Result API报RESUMED错误如何解决
问题修复方案
报错根因
你遇到的报错
Attempting to register while current state is RESUMED
是因为 Activity Result API 强制要求必须在Activity生命周期进入CREATED状态之前完成注册。你将注册逻辑放在了独立文件的伴生对象属性中,触发初始化的时机晚于Activity的onCreate执行阶段,调用相关逻辑时Activity已经处于RESUMED状态,因此触发系统校验报错。
适配改造步骤
1. 调整MainActivity代码,提前完成结果回调注册
将所有Activity Result的注册逻辑移到MainActivity的类成员属性位置,保证在onCreate执行前就完成注册,同时兼容取消选择的边界场景:
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding // 图片选择+拍照统一结果回调 val imagePickLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> when (result.resultCode) { RESULT_OK -> { // 优先处理拍照结果,其次处理文件选择结果 val uri = result.data?.data ?: Global.photoURI uri?.let { Global.webView.loadUrl("javascript:showResponse()") Global.filePathCallback?.onReceiveValue(arrayOf(it)) } } // 用户取消选择时回传null,避免Web端文件选择器卡住 RESULT_CANCELED -> Global.filePathCallback?.onReceiveValue(null) } // 用完清空回调避免内存泄漏 Global.filePathCallback = null } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Global.context = baseContext Global.activity = this binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) Global.webView = binding.webView WebListener.initiate() WebSettings.setUp() } }
2. 新增Global全局变量存储临时数据
在你的Global单例类中新增两个字段,用于存储Web回调和拍照临时Uri:
object Global { // 原有字段保留,新增以下两个字段 var filePathCallback: ValueCallback<Array<Uri>>? = null var photoURI: Uri? = null }
3. 修改WebListener的onShowFileChooser逻辑
删除原有的直接销毁filePathCallback的代码,先将回调保存到全局:
override fun onShowFileChooser( webView: WebView, filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams ): Boolean { Util.displayMessage("selected") // 保存Web端的文件选择回调 Global.filePathCallback = filePathCallback // 原有权限校验逻辑保留 if (ContextCompat.checkSelfPermission( Global.context, Manifest.permission.CAMERA ) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( Global.activity, arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), 0 ) } FileChooser.create() return true }
4. 修改FileChooser的启动逻辑
用MainActivity中提前注册好的Launcher启动选择器,替换原有的startActivity调用:
interface FileChooser { companion object { fun create() { val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) takePictureIntent.resolveActivity(Global.activity.packageManager)?.also { try { Global.photoURI = ImageUri.create() takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Global.photoURI) } catch (ex: Exception) { Util.displayMessage(ex.message.toString()) } } val intentArray: Array<Intent?> = arrayOf(takePictureIntent) val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "image/*" } val chooserIntent = Intent(Intent.ACTION_CHOOSER).apply { putExtra(Intent.EXTRA_INTENT, contentSelectionIntent) putExtra(Intent.EXTRA_TITLE, "Image Chooser") putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray) } // 用提前注册好的launcher启动选择器 (Global.activity as MainActivity).imagePickLauncher.launch(chooserIntent) } } }
5. 清理无用代码
直接删除CamResult.kt和SelectorResult.kt两个文件,原有注册逻辑不符合API要求,不再需要。
可选优化
可以将权限申请逻辑也替换为Activity Result API的RequestPermissions合约实现,替换已废弃的requestPermissions方法,逻辑和上述结果注册逻辑一致,提前在MainActivity中完成注册即可。
内容的提问来源于stack exchange,提问作者Hasan A Yousef
相关产品推荐
相关产品推荐

