Android WebView JellyBean -> 不应该发生:找不到基于矩形的测试节点

Posted

技术标签:

【中文标题】Android WebView JellyBean -> 不应该发生:找不到基于矩形的测试节点【英文标题】:Android WebView JellyBean -> Should not happen: no rect-based-test nodes found 【发布时间】:2012-08-18 22:13:13 【问题描述】:

我的应用程序正在使用许多 webviews,这些 webviews 位于 ViewPager 持有的片段中。

每当我在装有 Jellybean 的 Galaxy Nexus 上滑动应用程序时,我都会一次又一次地收到以下控制台消息:

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

谁能向我解释这里出了什么问题,以便我能够解决这个问题?

【问题讨论】:

“很多”是指大概有多少个 WebView? >256? >1024?我只是好奇。 大约40顶!每个片段 1 个。 也许这会有所帮助:***.com/questions/12364971/… 【参考方案1】:

出现此问题是因为在某些情况下 WebView 无法注意到其可见 rect 已更改,因此就 webkit 而言,页面仍然不可见。因此,所有的触摸都落在窗口之外,并被拒绝。

当你知道你的 WebView 的可见性已经改变时(例如响应来自 viewpager 的 setPrimaryItem 回调),最干净的解决方法是调用webview.onScrollChanged(webview.getScrollX(), webview.getScrollY());

您需要子类化 webview 以将受保护的 onScrollChanged 提升为公共方法。

【讨论】:

这是最清晰的解释和最干净的解决方案,应该是最佳答案。 这个答案让我走上了正轨。我将 public void applyAfterMoveFix() onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY()); 添加到我的 webview 子类中。【参考方案2】:

我有这个确切的问题。问题正是 Rahul Dole 在上面的回答中所说的。

我花了几天时间尝试了很多不同的事情。我注意到当方向改变时,可见的 WebView onLongClick 再次工作......所以我想出了这个小宝石。确实它非常 hacky,但它确实有效!

在扩展 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);

【讨论】:

直接调用onScrollChanged()也可以达到同样的效果。 工作就像一个魅力。【参考方案3】:

我遇到了完全相同的问题。在我的应用程序中,无论我在 jquery bind() 中使用 'touchend' 编码的点击事件,都会出现这个错误,并且它过去从不响应点击(点击)......并给人一种冻结的感觉。 所以我只是尝试在bind()中用'click'替换'touchend',它成功了!响应点击(点击),也没有显示 webcoreglue 的日志条目..

我也在android的webview代码中找到了这段代码..

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);
​

还有这个..

// 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...

注意到那里的日志消息了吗?我猜这个代码是用来识别在点击、点击或滑动时生成的 x 和 y 轴向量。 ​

【讨论】:

我不使用 jquery 的绑定。但是,尽管如此,您的回答可能会为问题所在提供一些方向。事实上,我使用 Zepto 而不是 Jquery,但也没有 Zepto bind´s。 你是在main.java文件的onDestroy()函数中做webView.destroy()吗? 不幸的是,我将 webview.destroy() 放入片段 onDestroy() 中,但没有成功。但问题可能与生命周期有关。当我在寻呼机上滑动时,就会出现消息。我使用 fragmentStatePagerAdapter。 click事件的使用并不是很完美,与touchend事件相比,它有400ms的延迟。你们知道这是Android的错误还是我们做错了什么??? 几天前,我遇到了 Android WebView 团队的工程师 John Reck。他确认这是一个错误——基本上是 webkit 布局引擎与 Android 布局不同步并开始将触摸事件映射到不正确的坐标系的竞争条件。在修复错误之前,调用 onScrollChanged() 重新同步布局似乎是最好的解决方法。【参考方案4】:

JellyBean 和 ViewPager + 包含 WebViews 的片段有同样的问题。在 Android 2.2 上运行相同的代码一切正常,所以我认为这是 JB WebView 实现中的一个错误。

在 JB 上,只有第一个显示的带有 WebView 的片段可以正常工作,日志中没有错误“不应发生 ..”,并且 getHitTestResult() 调用返回正确的值。滑动到下一页,我在日志中有错误,getHitTestResult() 只返回零和空值。

现在我发现只有一种解决方案可以使用空容器创建片段并创建 WebView,设置它们并仅在当前片段在 ViewPager 中处于活动状态时加载数据。在这种情况下,WebView 根据需要工作。但是,不幸的是,这完全打破了在 ViewPager 中平滑滑动页面的想法。

有了最后一个想法,明天将尝试将ViewPager的片段替换为复合视图。机会很小,但我会告诉你结果是否成功。

【讨论】:

抱歉延迟回答!正如我之前写的,当当前片段在 ViewPager 中变为活动状态时,我发现只有一种解决方法可以创建 WebView。【参考方案5】:

不知道它为什么起作用。我在 MainActivity.java 中添加了 onTouchEvent 监听器来解决这个问题。

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);
      
    

【讨论】:

【参考方案6】:

我在 Cordova + Sencha Touch 环境中工作时也遇到过这种情况。因为 CordovaActivity 没有类似 onScrollChanged() 的方法我无法应用上述任何解决方案。

在我的头撞到墙上几个小时后,我发现 Web 界面的某些部分在完全渲染之前已经被调用。在我的例子中,这些方法是由Ext.PanelView 中的activate 事件触发的。我用painted 替换了那个事件,从那以后一切都像魅力一样。

虽然它不是复制粘贴解决方案,但我希望它可以帮助某人节省调查时间。

【讨论】:

【参考方案7】:

另一种解决方案:

您不需要扩展 WebView 类来解决这个问题。我通过在加载 Web 视图内容后添加以下两行来解决这个问题 (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);

希望这会有所帮助(我测试了自己并且成功了)。

干杯

【讨论】:

【参考方案8】:

即使我在 ViewPager 中有 WebView,并通过扩展 webview 类覆盖 onTouchEvent() 来解决此问题。

这是我的代码:

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

干杯!!!

【讨论】:

以上是关于Android WebView JellyBean -> 不应该发生:找不到基于矩形的测试节点的主要内容,如果未能解决你的问题,请参考以下文章

Jelly Bean webview 应用程序无法完美响应 touchend 事件

更改 Android JellyBean 上的操作栏高度

Jellybean 中的 Android SQLite 数据库事务/锁定更改

run-as 包 'a.b.c' 未知 - Galaxy S4 Jellybean 或 Android 4.3

JellyBean 4.3 中的 GoogleTTSService 的名称是啥?

有没有办法在 Android JellyBean TimePickerDialog 中使用取消?