Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disjointed WebView drawing in ICS

I'm making an application which has a Webview inline with other elements, nested in a ScrollView. I've noticed that in ICS, testing on a Galaxy Nexus device, the WebView appears to be disjointed from the rest of the displayed elements when the page is flung, resulting in the WebView appearing to be floating because of a couple of ms worth of lag on drawing. This doesn't happen in 2.x versions of Android (not tested on 3.x). Here's a video of the floating effect http://www.youtube.com/watch?v=avfBoWmooM4 (you can see clearly if you set to fullscreen at 1080p)

Can anyone suggest why this may happen, or a fix?

I've setup a test project, below, to demonstrate:

package com.martynhaigh.floating_web_view;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

public class FloatingWebViewTestActivity extends FragmentActivity {
    public final int viewId = 0x12345678;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        FrameLayout frame = new FrameLayout(this);
        frame.setId(viewId);
        setContentView(frame, lp);

        FloatingWebViewICSFragment fragment = new FloatingWebViewICSFragment();
        getSupportFragmentManager().beginTransaction().add(viewId, fragment).commit();
    }

    public static class FloatingWebViewICSFragment extends Fragment {

        private final String htmlBody = "<html><body><p style=\"font-size:1.5em\">This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. This is a test document. </body></html>";

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

            TextView textView = new TextView(getActivity().getApplicationContext());
            textView.setText("Test Activity");

            WebView webView = new WebView(getActivity().getApplicationContext());
            webView.loadDataWithBaseURL("file:///android_asset/", htmlBody, "text/html", "UTF-8", "about:blank");
            webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
            webView.setScrollContainer(false);

            TextView textView2 = new TextView(getActivity().getApplicationContext());
            textView2.setText("Test Activity");

            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);

            LinearLayout layout = new LinearLayout(getActivity().getApplicationContext());
            layout.setLayoutParams(lp);
            layout.setOrientation(LinearLayout.VERTICAL);

            layout.addView(textView);
            layout.addView(webView);
            layout.addView(textView2);

            ScrollView scrollView = new ScrollView(getActivity().getApplicationContext());
            scrollView.setLayoutParams(lp);
            scrollView.addView(layout);

            return scrollView;
        }

    }
}
like image 805
Martyn Avatar asked Nov 13 '22 13:11

Martyn


1 Answers

I don't know how to fix it but I now the reason. Content of WebView is rendered by android.webkit.WebViewCore in its separate worker thread. They are communicating with each other. When WebView needs a re-render it sends a "please render" message to WebViewCore and when WVC is ready then sends back the result. The point is that their rendering is not in sync with the rendering of other UI elements - as it is done on a separate, non-ui thread.

I guess they wanted to avoid blocking the ui-thread with all the rendering effort. That is very kind. But it causes other problems... like yours.

like image 83
Zsolt Safrany Avatar answered Nov 16 '22 03:11

Zsolt Safrany