You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 21:23:14