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

Moto G5+(Android7/Chrome63)ViewPager+WebView内存崩溃修复咨询

问题描述

我在使用ViewPager搭配FragmentStatePagerAdapter加载包含<img>标签与富文本的HTML文本列表时,仅在搭载**Android 7系统、Chrome版本为63.0.3239.111的Moto G5+**设备上出现崩溃:滚动页面数秒后触发WebView内存不足崩溃,相关崩溃日志如下:

W/Adreno-GSL: <sharedmem_gpuobj_alloc:2021>: sharedmem_gpumem_alloc: mmap failed errno 12 Out of memory
E/Adreno-GSL: <gsl_memory_alloc_pure:2125>: GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.
E/chromium: [ERROR:texture_manager.cc(3408)] [.RenderWorker-0x6df0a000]GL ERROR :GL_OUT_OF_MEMORY : glTexImage2D:
E/chromium: [ERROR:gles2_cmd_decoder.cc(5409)] Error: 5 for Command kTexImage2D
[ERROR:gles2_cmd_decoder.cc(9881)] [GroupMarkerNotSet(crbug.com/242999)!:50082280]RENDER WARNING: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering.
A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x4 in tid 9665 (RenderThread)

现寻求该崩溃问题的修复方案。


修复方案

这个问题在旧版WebView(Chrome 63)搭配Android 7的Adreno GPU设备上很常见,核心是WebView的内存管理和图片渲染逻辑在特定硬件/系统版本下存在缺陷。结合你的ViewPager+富文本场景,我整理了几个针对性的修复方案:

1. 强制WebView资源回收,避免内存泄漏

旧版WebView在Fragment中极易出现内存泄漏,尤其是配合ViewPager时,必须确保Fragment销毁时WebView被彻底清理:

  • 在Fragment的onDestroyView中手动销毁WebView,不要依赖系统自动回收:
    @Override
    public void onDestroyView() {
        if (webView != null) {
            // 先移除父布局引用
            ViewParent parent = webView.getParent();
            if (parent != null) {
                ((ViewGroup) parent).removeView(webView);
            }
            // 停止加载并清空所有资源
            webView.stopLoading();
            webView.clearHistory();
            webView.clearCache(true);
            webView.removeAllViews();
            // 最终销毁WebView实例
            webView.destroy();
            webView = null;
        }
        super.onDestroyView();
    }
    
  • 针对该设备禁用WebView硬件加速:旧版Adreno GPU处理WebView硬件加速时存在内存管理bug,可单独对Moto G5+关闭硬件加速:
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N && "Moto G5+".equals(Build.MODEL)) {
        webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }
    

2. 优化HTML图片加载,降低内存占用

日志中的GL内存错误几乎都是图片加载导致的,可通过以下方式压缩图片内存:

  • 拦截图片请求并压缩尺寸:用WebViewClient拦截图片URL,将图片压缩到屏幕宽度后再返回给WebView:
    webView.setWebViewClient(new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            String url = request.getUrl().toString();
            if (url.matches(".*\\.(png|jpg|jpeg)$")) {
                try {
                    InputStream is = new URL(url).openStream();
                    Bitmap originalBitmap = BitmapFactory.decodeStream(is);
                    int screenWidth = getResources().getDisplayMetrics().widthPixels;
                    // 按屏幕宽度等比例缩放图片
                    float scale = (float) screenWidth / originalBitmap.getWidth();
                    Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, screenWidth, (int)(originalBitmap.getHeight()*scale), true);
                    // 将压缩后的Bitmap转为InputStream返回
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);
                    return new WebResourceResponse("image/jpeg", "UTF-8", new ByteArrayInputStream(baos.toByteArray()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return super.shouldInterceptRequest(view, request);
        }
    });
    
  • 开启WebView图片自适应:让WebView自动缩放图片适配屏幕,避免加载原始大图:
    WebSettings settings = webView.getSettings();
    settings.setLoadWithOverviewMode(true);
    settings.setUseWideViewPort(true);
    

3. 调整ViewPager缓存策略,减少同时加载的WebView数量

FragmentStatePagerAdapter虽会销毁不可见Fragment,但可进一步优化缓存逻辑:

  • 减少预加载页面数:默认ViewPager会预加载左右各1个页面,可设置为0(牺牲一点滚动流畅度换内存):
    viewPager.setOffscreenPageLimit(0);
    
  • 页面切换时暂停/恢复WebView:不可见的页面暂停加载,释放内存:
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            // 恢复当前页面WebView
            Fragment currentFrag = getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + position);
            if (currentFrag instanceof WebContentFragment) {
                ((WebContentFragment) currentFrag).resumeWebView();
            }
            // 暂停其他页面WebView
            for (int i = 0; i < viewPager.getAdapter().getCount(); i++) {
                if (i != position) {
                    Fragment frag = getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + i);
                    if (frag instanceof WebContentFragment) {
                        ((WebContentFragment) frag).pauseWebView();
                    }
                }
            }
        }
        @Override public void onPageScrolled(int position, float offset, int offsetPixels) {}
        @Override public void onPageScrollStateChanged(int state) {}
    });
    
    // 在WebContentFragment中实现对应方法
    public void pauseWebView() {
        if (webView != null) {
            webView.pauseTimers();
            webView.stopLoading();
        }
    }
    public void resumeWebView() {
        if (webView != null) {
            webView.resumeTimers();
        }
    }
    

4. 旧版WebView专属优化

Chrome 63存在不少已知内存问题,可通过以下设置降低内存占用:

  • 禁用不必要的JavaScript:如果你的富文本不需要JS交互,直接关闭:
    settings.setJavaScriptEnabled(false);
    
  • 禁用WebView缓存:旧版WebView的缓存可能存在泄漏,直接关闭:
    settings.setAppCacheEnabled(false);
    settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
    

内容的提问来源于stack exchange,提问作者Sheetal Suryan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:31:22