WebView取消文件选择对话框后无法再次打开问题求助
问题描述
文件选择对话框首次打开正常,上传功能可用,但取消退出对话框后无法再次打开,同时页面出现卡顿。本人每年仅使用Android Studio两次左右,对这类错误处理不熟悉,相关代码如下:
问题代码
package com.mobile.popit; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import com.mobile.pop.R; public class MainActivity extends Activity { private final static int FILECHOOSER_RESULTCODE = 1; private ValueCallback<Uri[]> mUploadMessage; WebView mainWebView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainWebView = findViewById(R.id.webView); mainWebView.setWebViewClient(new MyWebViewClient()); mainWebView.setWebChromeClient(new MyWebChromeClient()); mainWebView.getSettings().setJavaScriptEnabled(true); mainWebView.loadUrl("https://domain/Login.php"); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == FILECHOOSER_RESULTCODE) { if (null == mUploadMessage || intent == null || resultCode != RESULT_OK) { return; } Uri[] result = null; String dataString = intent.getDataString(); if (dataString != null) { result = new Uri[]{ Uri.parse(dataString) }; } mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } // ==================== // Web clients classes // ==================== private class MyWebViewClient extends WebViewClient { // permite la navegacion dentro del webview @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } } private class MyWebChromeClient extends WebChromeClient { // maneja la accion de seleccionar archivos @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { // asegurar que no existan callbacks if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); } mUploadMessage = filePathCallback; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); // set MIME type to filter MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FILECHOOSER_RESULTCODE ); return true; } } }
解决方案
问题根源在于文件选择取消后的回调未正确处理,以及WebView链接跳转逻辑不合理,导致页面卡顿和对话框无法重复调用。以下是具体修复方案:
修复文件选择回调逻辑
在onActivityResult中,无论用户是选择文件还是取消操作,都必须调用mUploadMessage.onReceiveValue()并清空引用。原代码仅在选中文件时处理,取消时直接返回,导致WebView认为文件选择流程仍在进行,无法再次触发对话框。优化WebView链接跳转
原shouldOverrideUrlLoading方法已过时,且强制所有链接通过loadUrl加载,会引发重复加载卡顿。改用新版方法,仅拦截非HTTP/HTTPS协议的链接(如电话、外部应用跳转),让WebView自行处理网页内跳转。增加资源清理
在Activity销毁时清空mUploadMessage,避免内存泄漏。
修改后的完整代码:
package com.mobile.popit; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; import com.mobile.pop.R; public class MainActivity extends Activity { private final static int FILECHOOSER_RESULTCODE = 1; private ValueCallback<Uri[]> mUploadMessage; WebView mainWebView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainWebView = findViewById(R.id.webView); mainWebView.setWebViewClient(new MyWebViewClient()); mainWebView.setWebChromeClient(new MyWebChromeClient()); mainWebView.getSettings().setJavaScriptEnabled(true); mainWebView.loadUrl("https://domain/Login.php"); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (requestCode == FILECHOOSER_RESULTCODE) { Uri[] result = null; // 处理选中文件的情况 if (resultCode == RESULT_OK && intent != null) { String dataString = intent.getDataString(); if (dataString != null) { result = new Uri[]{Uri.parse(dataString)}; } } // 无论是否选中文件,都必须回调并清空引用 if (mUploadMessage != null) { mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } } @Override protected void onDestroy() { super.onDestroy(); // 清理回调,避免内存泄漏 if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); mUploadMessage = null; } } private class MyWebViewClient extends WebViewClient { // 使用新版方法处理链接跳转 @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { Uri uri = request.getUrl(); // 仅拦截非HTTP/HTTPS协议的链接(如intent、tel等) if (uri.getScheme().startsWith("http") || uri.getScheme().startsWith("https")) { // 让WebView自行处理网页跳转,避免重复加载卡顿 return false; } else { // 处理其他协议,比如打开外部应用 Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); return true; } } } private class MyWebChromeClient extends WebChromeClient { @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { // 先清空之前未完成的回调 if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); mUploadMessage = null; } mUploadMessage = filePathCallback; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); return true; } } }
内容的提问来源于stack exchange,提问作者Ken Scott
相关产品推荐
相关产品推荐

