android - 使用一段时间后,我的应用程序在滚动 WebView 时卡住,显示 "could not lock surface"

标签 android webview android-webview

我的 Android 应用程序包含多个 Activity ,每个 Activity 负责一个 fragment (目前)。我的 fragment 通常是这样显示/附加的:

mTopicFragment = (TopicFragment)getSupportFragmentManager().findFragmentByTag("topic");
if(mTopicFragment == null)
    mTopicFragment = TopicFragment.newInstance(bid, page, pid);

if (savedInstanceState == null) {
    getSupportFragmentManager().beginTransaction()
            .add(R.id.content, mTopicFragment, "topic")
            .commit();
}

TopicFragment 包含一个显示一些 HTML 和 CSS/JS 内容的 WebView。在应用程序中浏览一段时间后,其中一个 TopicFragment WebViews 的滚动变得缓慢,最终,应用程序完全卡住。 ADB 日志显示以下异常:

12-12 22:49:33.931  12582-12582/com.mde.potdroid3 W/Adreno-EGLSUB﹕ <DequeueBuffer:606>: dequeue native buffer fail: Unknown error 2147483646, buffer=0x0, handle=0x0
12-12 22:49:33.941  12582-12582/com.mde.potdroid3 W/Adreno-EGLSUB﹕ <DequeueBuffer:606>: dequeue native buffer fail: Invalid argument, buffer=0x0, handle=0x0
12-12 22:49:33.941  12582-12582/com.mde.potdroid3 W/Adreno-ES20﹕ <gl2_surface_swap:43>: GL_OUT_OF_MEMORY
12-12 22:49:33.941  12582-12582/com.mde.potdroid3 W/Adreno-EGL﹕ <qeglDrvAPI_eglSwapBuffers:3597>: EGL_BAD_SURFACE
12-12 22:49:33.941  12582-12582/com.mde.potdroid3 W/HardwareRenderer﹕ EGL error: EGL_BAD_SURFACE
12-12 22:49:33.951  12582-12582/com.mde.potdroid3 W/HardwareRenderer﹕ Mountain View, we've had a problem here. Switching back to software rendering.

12-12 22:20:04.461  10081-10081/com.mde.potdroid3 E/Surface﹕ dequeueBuffer failed (Unknown error 2147483646)
12-12 22:20:04.461  10081-10081/com.mde.potdroid3 E/ViewRootImpl﹕ Could not lock surface
    java.lang.IllegalArgumentException
            at android.view.Surface.nativeLockCanvas(Native Method)
            at android.view.Surface.lockCanvas(Surface.java:243)
            at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2435)
            at android.view.ViewRootImpl.draw(ViewRootImpl.java:2409)
            at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2253)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1883)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
            at android.view.Choreographer.doCallbacks(Choreographer.java:574)
            at android.view.Choreographer.doFrame(Choreographer.java:544)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5081)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:781)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)

在互联网上,我只能找到有关此异常的信息,人们有自己的自定义 View 。这里发生了什么?它可能与我的应用程序的内存消耗有关吗?似乎每次我调用上面的代码时,都会实例化、显示一个新的 TopicFragment 并将其推送到后台堆栈。我该如何进一步调试此行为?


更多信息:当我在开发人员设置中启用覆盖时,应用程序似乎使用了大量 CPU。可能是当我离开时我的 fragment 没有正确分离并且由于某种原因继续在后台运行?


这是我使用 WebView 的方式:

mWebView = (WebView)getView().findViewById(R.id.topic_webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
mWebView.getSettings().setAllowFileAccess(true);
mWebView.addJavascriptInterface(mJsInterface, "api");
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.loadData("", "text/html", "utf-8");
mWebView.setBackgroundColor(0x00000000);

不是提到的内存泄漏 here .

最佳答案

我想我已经修好了。显然,有一个错误阻止了 WebView 的正确内存管理。当我在他们的 View 中使用 WebView 启动许多 Activity 时,WebViews 存在于内存中,当内存不足时, Activity 不会被正确终止。我在显示 WebViewTopicFragment 中使用以下代码解决了这个问题:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
    View v = super.onCreateView(inflater, container, saved);

    mActivity = (BaseActivity) getSupportActivity();

    // this is the framelayout which will contain our WebView
    mWebContainer = (FrameLayout) v.findViewById(R.id.web_container);

    return v;
}

public void onResume() {
    super.onResume();

    // create new WebView and set all its options.
    mWebView = new WebView(mActivity);
    mWebView....

    // add it to the container
    mWebContainer.addView(mWebView);

    // if data is available, display it immediately
    if(mTopic != null) {
        mWebView.loadDataWithBaseURL("file:///android_asset/", mTopic.getHtmlCache(),
                "text/html", "UTF-8", null);
    }
}

@Override
public void onPause() {
    super.onPause();

    // destroy the webview
    mWebView.destroy();
    mWebView = null;

    // remove the view from the container.
    mWebContainer.removeAllViews();
}

这样,WebViewonResumeonPause 中创建和删除。这是一些开销,并不完美,但它解决了内存问题,并且在性能等方面几乎没有引起注意。

关于android - 使用一段时间后,我的应用程序在滚动 WebView 时卡住,显示 "could not lock surface",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20554621/

相关文章:

android - 如何在android浏览器上打开嵌入在url中的音频和视频

android studio 错误 HAXM

java - 空白类型的 Android ClassCastException

android - 如何通过在鳍状肢中启用多点触控缩放来进行 webview 滑动手势检测

javascript - 在外部浏览器中打开链接

android - 如何在 KitKat 及以上版本的 android WebView 上设置 Referer

javascript - trigger.io - 关闭软键盘?

php - 我如何使用移动硬件组件,如 : MNotification, 摄像头、地理定位、加速度计?

Android:WebView 中的 Twitter - 通过回调返回 Activity

javascript - Android 警报 "Don' t 再次显示“Web View 中的复选框