Android WebView JellyBean -> Should not happen: no rect-based-test nodes found
Asked Answered
W

8

47

My application is using a lot of webviews which are lying in fragments which are hold by a ViewPager.

Whenever i swipe through the app on my Galaxy Nexus with Jellybean on it i get the following console message again and again:

08-23 13:44:03.374: E/webcoreglue(21690): Should not happen: no rect-based-test nodes found

Can anyone explain to me what is going wrong here so that i might be able to fix the issue?

Winnah answered 23/8, 2012 at 11:50 Comment(3)
By "a lot" means roughly how many WebViews? >256? >1024? I'm just curious.Sanitation
About 40 tops! 1 for each Fragment.Winnah
Maybe this can help: #12365471Encyclopedist
C
22

The issue occurs because in some scenarios WebView fails to notice that its visible rect has changed, so as far as webkit is concerned the page is still not visible. Thus all touches fall outside of the window, and get rejected.

The cleanest fix is when you know the visibility of your WebView has changed (such as in response to a setPrimaryItem callback from a viewpager), call webview.onScrollChanged(webview.getScrollX(), webview.getScrollY());

You will need to subclass the webview to promote the protected onScrollChanged to a public method.

Chanukah answered 19/4, 2013 at 1:38 Comment(2)
This is the clearest explanation and cleanest solution, should be the top answer.Acatalectic
This answer put me on the right track. I added public void applyAfterMoveFix() { onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY()); } to my webview subclass.Geest
Q
18

I had this exact issue. The problem is exactly what Rahul Dole said in his answer above.

I spend a few days on this trying tons of different things. I noticed that when the orientation changed that the visible WebView onLongClick worked again...so I came up with this little gem. Indeed its very hacky but it works!

Use this in your class that extends WebView:

@Override
public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN){

        int temp_ScrollY = getScrollY();
        scrollTo(getScrollX(), getScrollY() + 1);
        scrollTo(getScrollX(), temp_ScrollY);

    }

    return super.onTouchEvent(event);
}
Quant answered 1/3, 2013 at 8:15 Comment(2)
You can get the same effect by calling onScrollChanged() directly.Derry
Worked like a charm.Luck
F
16

I faced exactly the same problem. In my app wherever i had click events coded using 'touchend' in jquery bind(), this error was coming up and it used to never respond to clicks (taps).. and gave a frozen kind of feel. So I just tried replacing 'touchend' with 'click' in bind(), and it worked! responded to clicks (Taps) and also didn't show that log entry of webcoreglue..

I also found this piece of code in Android's webview code..

HTMLElement* WebViewCore::retrieveElement(int x, int y,
    const QualifiedName& tagName)
{
    HitTestResult hitTestResult = m_mainFrame->eventHandler()
        ->hitTestResultAtPoint(IntPoint(x, y), false, false,
        DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
        IntSize(1, 1));
    if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
        LOGE("Should not happen: no in document Node found");
        return 0;
    }
    const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
    if (list.isEmpty()) {
        LOGE("Should not happen: no rect-based-test nodes found");
        return 0;
    }
    Node* node = hitTestResult.innerNode();
    Node* element = node;
    while (element && (!element->isElementNode()
        || !element->hasTagName(tagName))) {
        element = element->parentNode();
    }
    DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node,
        element, x, y, node->nodeName().utf8().data(),
        element ? ((Element*) element)->tagName().utf8().data() : "<none>");
    return static_cast<WebCore::HTMLElement*>(element);
}​

and this too..

// get the highlight rectangles for the touch point (x, y) with the slop
Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
{
    Vector<IntRect> rects;
    m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
    HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
            false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
    if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
        LOGE("Should not happen: no in document Node found");
        return rects;
    }
    const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
    if (list.isEmpty()) {
        LOGE("Should not happen: no rect-based-test nodes found");
        return rects;
    }
//Rest of the part is omitted here...

Notice that log message there? I am guessing this code is for identifying the x and y axis vectors generated on clicks or taps or swipes.. ​

Fluidics answered 7/9, 2012 at 11:51 Comment(10)
I dont use make use of jquery´s bind. But notherless your answer might give some direction where the problem might be. In fact i use Zepto instead of Jquery but also no Zepto bind´s.Winnah
Are you doing webView.destroy() in the onDestroy() function in main.java file?Fluidics
No i dont, i dont use the destroy method of webview.Winnah
try it, might help. probably all the webviews.Fluidics
I put the webview.destroy() into the fragments onDestroy() unfortunaly with no success. But the problem could be related to the lifecycle. as i swipe through the pager the message occurs. I use a fragmentStatePagerAdapter.Winnah
Thats close enough for me! Thanks!Winnah
The use of the click event is not really perfect as it has a delay of 400ms compared to the touchend event. Do you guys know if it's a bug in Android or us who are doing something wrong ???Wastage
to me it looks like a bug in android apparently, or maybe they have made some change and didn't declare it in change log. Not sure.Fluidics
I'm not a big fan of this answer either, using click instead of touchend introduces a delay and makes the app seem slow...Cosimo
I met with John Reck, an engineer on the Android WebView team, a couple of days ago. He confirmed that this is a bug--basically a race condition where the webkit layout engine gets out of sync with the Android layout and starts mapping touch events to an incorrect coordinate system. Until the bug is fixed, calling onScrollChanged() to resync the layouts seems to be the best workaround.Derry
P
1

Have the same problem with JellyBean and ViewPager + fragments that contains WebViews. And all OK with the same code running on Android 2.2, so I think this is a bug in JB WebView implementation.

On JB only the first shown fragment with WebView works right, without errors "Should not happen .." in the log, and getHitTestResult() calls returns correct values. Swiping to the next pages, I got errors in log and getHitTestResult() returns only zeroes and nulls.

Now I found only one solution to create fragments with empty containers and create WebViews, setup they and load data only when current fragment becomes active in the ViewPager. In this case WebView works as needed. But, unfortunately, this completely breaks an idea of smooth swiping pages in the ViewPager.

Have the last idea, tomorrow will try to replace ViewPager's fragments to compound views. Little chances, but I'll let you know if results will be successful.

Planography answered 4/12, 2012 at 22:32 Comment(1)
Sorry for delayed answer! As I wrote earlier, I found only one workaround to create WebView when current fragment becomes active in the ViewPager.Planography
R
1

Don't have a clue why it worked. I added onTouchEvent listener into my MainActivity.java to fix this issue.

public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
        public class MyWebView extends WebView {

          public MyWebView(Context context) {
            super(context);
      }

      public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
      }

      @Override
      public boolean onTouchEvent(MotionEvent event) {
        onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY());
        return super.onTouchEvent(event);
      }
    }
Rubber answered 25/3, 2015 at 0:10 Comment(0)
A
0

It also happened to me when I was working in Cordova + Sencha Touch environment. Because CordovaActivity does not have anything like onScrollChanged() method I could not apply any of the above solutions.

After hours of banging my head against the wall I discovered that some parts of web interface had been called before this was completely rendered. In my case those methods were triggered by activate event in Ext.PanelView. I replaced that event with painted and since then everything works like a charm.

Although it is not copy-paste solution I hope it may help someone to save time on investigation.

Aerodontia answered 3/6, 2014 at 0:20 Comment(0)
W
0

Another solution:

You don't need to extend the WebView class to fix that.. I've got that fixed by adding the following two lines right after loading the web view content (myWebView.loadUrl("..."):

wv.loadUrl("your url here");

//Add the following two lines
myWebView.scrollTo(myWebView.getScrollX(), myWebView.getScrollY()+1);
myWebView.scrollTo(myWebView.getScrollX(), myWebView.getScrollY()-1);

Hope this will help (I tested myself and it worked).

Cheers

Willodeanwilloughby answered 13/6, 2015 at 15:56 Comment(0)
L
-1

Even I have WebView inside a ViewPager, and fixed this problem by overriding onTouchEvent() by extending webview class.

Here is my code:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {       
            requestFocusFromTouch();
        }
        return super.onTouchEvent(event);
    }

Cheers !!!

Llovera answered 2/12, 2014 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.