WebView渲染HTML屏幕&了解内容何时完全呈现

时间:2014-11-29 05:26:16

标签: android html webview

我在WebView关闭屏幕上渲染了一些非常简单的HTML(只是一些文本和一个小图像)(未设置为活动的内容视图),因此我可以根据内容创建一个位图。

了解内容何时完全呈现的方法我基于此answer

final AtomicBoolean rendered = new AtomicBoolean(false);
final WebView view = new WebView(this) {
    @Override
    public void invalidate() {
        if (getProgress() == 100 && getContentHeight() > 0) {
            if (! rendered.get()) {
                rendered.set(true);
                // Content should be fully rendered
            }
        }
        super.invalidate();
    }
};

// Load and lay out content
view.loadUrl(url);
view.setInitialScale(100);
view.layout(0, 0, 240, 420);

我已经在4.1.2,4.2.2,4.4.2和5.0上成功测试了这一点。但是对于4.0.3,似乎永远不会调用invalidate()

在尝试各种各样的事情时,我发现显示Toast并对invalidate()进行延迟(1秒)调用可以解决问题:

@Override
public void onPageFinished(final WebView view, final String url) {
        Toast.makeText(MainActivity.this, "Page loaded", Toast.LENGTH_SHORT).show();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (! rendered.get()) {
                    view.invalidate();
                }
            }
        }, 1000);
}

当然,我不认为这是一个有效的解决方案,但是对invalidate()的延迟调用对我来说是有道理的,我真的很想知道Toast的副作用是什么。是否会造成一些损坏导致重绘或类似的东西?

3 个答案:

答案 0 :(得分:1)

很抱歉,我不能帮助你,因为我想对你做同样的操作(从离线webview控件获取屏幕截图)但在我的情况下,我无法在webview离线之前收到invalidate()事件。如果我通过插入主窗口设置为可见,则会生成invalidate(),但是在脱机(不可见)的情况下,不会生成invalidate()调用。您为获得此类结果而开发的代码只是您在此处发布的代码段,或者还有一些额外的功能可以让webview在离线模式下处于“活动状态”吗?

关于您的问题我可以建议覆盖其他invalidate()定义,如:

public void invalidate(Rect dirty)
public void invalidate(int l, int t, int r, int b)

因为在我的测试中我注意到这些最后一次被称为。

谢谢

答案 1 :(得分:0)

经过对不同(虚拟)设备的大量测试后,这是迄今为止对我来说可靠的方式。请注意,我原始问题中提到的4.0.3的“hack”仍然适用,但不包含在此处。

覆盖invalidate()并未证明在所有测试版本上始终可靠,因此我使用PictureListener.onNewPicture(WebView view, Picture picture)即使它已被弃用。

在我的活动中:

final WebView view = new WebView(this);    

// Zooming in can improve font quality
final float scale = 2.0;
// Unfortunately, there is no method view.getContentWidth()
final int contentWidth = 240;

view.setPictureListener(new PictureListener() {

    @Override
    public void onNewPicture(final WebView view, final Picture picture) {
        if (view.getProgress() == 100 && view.getContentHeight() > 0) {
            view.setPictureListener(null);
            // Content is now fully rendered
            final int width = Math.round(contentWidth * scale);
            final int height = Math.round(view.getContentHeight() * scale);
            final Bitmap bitmap = getBitmap(view, width, height);
            // Display or print bitmap...
        }
    }
});

view.loadUrl(url);
view.setInitialScale(Math.round(scale * 100));
// Width and height must be at least 1
view.layout(0, 0, 1, 1);

getBitmap()方法:

private Bitmap getBitmap(
        final WebView view, final int width, final int height) {
    final Bitmap bitmap = Bitmap.createBitmap(
            width, height, Bitmap.Config.ARGB_8888);
    final Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);

    return bitmap;
}

这是我能提供的最好的。该应用程序尚未经过广泛测试,但到目前为止,它始终无法正确呈现包含小型GIF图像的小文档。

答案 2 :(得分:0)

感谢您的建议。我可以确认PictureListener方式是否仍然工作,如果depecrated(测试到Android 5版本),因为如果我发现的第一个解决方案。不幸的是,这个听众有一个问题,在每个建议之间引入延迟,这意味着你没有立即建议变化。如果在你的情况下这不是一个问题,那么听众解决方案对你来说没问题,但在我的情况下,我需要被建议"立即了解页面中的任何更改,以获取更新的屏幕截图。