Android Webview:在渲染完成时检测

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21000566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:48:25  来源:igfitidea点击:

Android Webview: Detect when rendering is finished

androidandroid-webviewsnapshot

提问by lolyoshi

I want to snapshot the WebView after the WebView is loaded. However, the returned bitmap is always null because the render hasn't loaded completed even though I use onPageFinished. I search on Internet and people suggest to use WebView.PictureListener, but this function is deprecated in API 12.

我想在加载 WebView 后对 WebView 进行快照。但是,返回的位图始终为空,因为即使我使用onPageFinished. 我在 Internet 上搜索,人们建议使用WebView.PictureListener,但此功能在 API 12 中已弃用

Some codes

一些代码

public class MainActivity extends Activity {
    private WebView mButterflyWebView;

    /**
     * Gets html content from the assets folder.
     */
    private String getHtmlFromAsset() {
        InputStream is;
        StringBuilder builder = new StringBuilder();
        String htmlString = null;
        try {
            is = getAssets().open(getString(R.string.butterfly_html));
            if (is != null) {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(is));
                String line;
                while ((line = reader.readLine()) != null) {
                    builder.append(line);
                }

                htmlString = builder.toString();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return htmlString;
    }

    /**
     * Initializes views, controls...
     */ 

    private void init() {
        mButterflyWebView = (WebView) findViewById(R.id.butterfly_webview);

        mButterflyWebView.setWebChromeClient(new WebChromeClient() {
        public void onProgressChanged(WebView view, int newProgress) {


            if (newProgress == 100){
                if (capturePictureWebView() != null){
                    saveBitmapToFile(capturePictureWebView());
                }
            }
        }
    });

    }

    /**
     * Loads html page with the content.
     */
    private void loadHtmlPage() {
        String htmlString = getHtmlFromAsset();
        if (htmlString != null)
            mButterflyWebView.loadDataWithBaseURL(
                    "file:///android_asset/images/", htmlString, "text/html",
                    "UTF-8", null);

        else
            Toast.makeText(this, R.string.no_such_page, Toast.LENGTH_LONG)
                    .show();
    }

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        init();
        loadHtmlPage();
    }

    private Bitmap capturePictureWebView() {
        mButterflyWebView.measure(MeasureSpec.makeMeasureSpec(
                MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED),
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        mButterflyWebView.layout(0, 0, mButterflyWebView.getMeasuredWidth(),
                mButterflyWebView.getMeasuredHeight());
        mButterflyWebView.setDrawingCacheEnabled(true);
        mButterflyWebView.buildDrawingCache();

        if (mButterflyWebView.getMeasuredWidth() == 0 || mButterflyWebView.getMeasuredHeight() == 0){
            return null;
        }
        Bitmap bm = Bitmap.createBitmap(720, 1280, Bitmap.Config.ARGB_8888);

        System.out.println("width=" + mButterflyWebView.getMeasuredWidth());
        System.out.println("height=" + mButterflyWebView.getMeasuredHeight());
        Canvas bigcanvas = new Canvas(bm);
//        bigcanvas.scale(720/mButterflyWebView.getMeasuredWidth(), 1280/mButterflyWebView.getMeasuredHeight());
        Paint paint = new Paint();
        int iHeight = bm.getHeight();
        bigcanvas.drawBitmap(bm, 0, iHeight, paint);
        mButterflyWebView.draw(bigcanvas);
        return bm;
    }

    private void saveBitmapToFile(Bitmap bitmap) {
        try {

            FileOutputStream out = new FileOutputStream("/storage/sdcard0/a.png");
            bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

采纳答案by lolyoshi

Finally I got the very detailed for this problem. This explains why it always returns null bitmap.

最后我得到了这个问题的非常详细的信息。这解释了为什么它总是返回空位图。

Every change in my app are triggered by a user action so I came up with a modified version that only trigger invalidate() after a touchEvent

我的应用程序中的每个更改都是由用户操作触发的,因此我想出了一个修改版本,该版本仅在 touchEvent 之后触发 invalidate()

Thank for all your help.

感谢您的帮助。

Android WebView renders blank/white, view doesn't update on css changes or HTML changes, animations are choppy

Android WebView 呈现空白/白色,视图不会在 css 更改或 HTML 更改时更新,动画断断续续

回答by Andros

You should try to use a WebChromeClientand implement onProgressChanged:

您应该尝试使用 aWebChromeClient并实现onProgressChanged

http://developer.android.com/reference/android/webkit/WebChromeClient.html#onProgressChanged(android.webkit.WebView, int)

http://developer.android.com/reference/android/webkit/WebChromeClient.html#onProgressChanged(android.webkit.WebView, int)

mButterflyWebView.setWebChromeClient(new WebChromeClient() {

        @Override
        public void onProgressChanged(WebView view, int progress) {
           if (progress == 100) {
               // do screenshot
           }
        }
});

EDIT: to check if onPageStarted is loaded more than once :

编辑:检查 onPageStarted 是否加载不止一次:

mButterflyWebView.setWebViewClient(new WebViewClient() {

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
           Log.d("WebView", "onPageStarted " + url);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
           Log.d("WebView", "onPageFinished " + url);
        }
    });

回答by Daniel Novak

The best way to detect if a page has rendered is to use the onPageCommitVisiblecallback, available from API 23. onPageLoadFinishedis not suitable, since it's delivered too soon (when the HTML is processed, but not yet rendered).

检测页面是否已呈现的最佳方法是使用API 23 提供的onPageCommitVisible回调。onPageLoadFinished不合适,因为它交付得太快(处理 HTML 但尚未呈现时)。

webview.setWebViewClient(new WebViewClient() {

webview.setWebViewClient(new WebViewClient() {

    @Override
     public void onPageCommitVisible (WebView view, 
            String url)
    }

}

}

回答by Frank

You can do it like this, in your WebView:

你可以在你的 WebView 中这样做:

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

    if (getContentHeight() > 0) {
        // WebView has displayed some content and is scrollable.
    }
}

Thanks to: https://stackoverflow.com/a/14678910/1310343

感谢:https: //stackoverflow.com/a/14678910/1310343

回答by shreedhar

The renderer will not finish rendering when the OnPageFinshed method is called or the progress reaches 100% so both methods don't guarantee you that the view was completely rendered.

当调用 OnPageFinshed 方法或进度达到 100% 时,渲染器将不会完成渲染,因此这两种方法都不能保证视图已完全渲染。

But you can figure out from OnLoadResource method what has been already rendered and what is still rendering. And this method gets called several times.

但是您可以从 OnLoadResource 方法中找出已经呈现的内容以及仍在呈现的内容。这个方法被多次调用。

        @Override
        public void onLoadResource(WebView view, String url) {
            super.onLoadResource(view, url);
           // Log and see all the urls and know exactly what is being rendered and visible. If you wanna know when the entire page is completely rendered, find the last url from log and check it with if clause and implement your logic there.
            if (url.contains("assets/loginpage/img/ui/forms/")) {
                // loginpage is rendered and visible now.
               // your logic here.

            }
        }

回答by Martin

private class CfdWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        Log.v(TAG, "shouldOverrideUrlLoading: " + url);;
        return true;
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        Log.v(TAG, "onPageFinished: " + url);

        // do something
    }
}