Search code examples
androidkotlinandroid-webview

When loading WebView with html code, when exactly is the result rendered?


I am loading my html to WebView using loadDataWithBaseURL. I am setting webViewClient for the WebView object, and in its onPageCommitVisible function, trying to convert the result - loaded page - to bitmap.

But sometimes, this callback is invoked too early - function measure and the following measuredHeight is zero - in such case I need to wait some time and repeat the measurement later. What is the correct place, in WebView, where the html is already loaded and I can measure its rendered height?

override fun onPageCommitVisible(view: WebView?, url: String?) {
    // needed there to measure real height
    myWebView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))

    var counter = 0

    // TODO treatment is busy waiting - but I don't know how to handle it correctly...
    while (myWebView.measuredHeight <= 0) {
        counter ++
        if (counter > 10) {
            Logger.e(TAG, "measuredHeight is still ${myWebView.measuredHeight}")
            Logger.e(TAG, "skipped")

            return
        }

        // sleep and try to measure again
        Logger.e(TAG, "measuredHeight is ${myWebView.measuredHeight}")
        Thread.sleep(200)

        myWebView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
    }

    Logger.d(TAG, "measuredHeight: ${myWebView.measuredHeight}")
}

I have tried to work with onPageFinished - but that one is actually invoked (on real device with Android v9/10) around 10ms before onPageCommitVisible.

Is there some way without the busy waiting?

============= UPDATE ==============

Even the busy waiting mentioned above is not the solution.

I have from time to time a situation, where the webpage is not processed completely, but is cutted. Updated the logging at the end:

Logger.d(TAG, "measuredHeight: ${myWebView.measuredHeight}")

// sleep and try to measure again
Thread.sleep(1000)

myWebView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
Logger.d(TAG, "measuredHeight: ${myWebView.measuredHeight}")

Result is for example:

measuredHeight is 826
measuredHeight is 1056

This means that something is displayed, height is more than zero, but it is not yet final... Any idea?


Solution

  • Changing from the following:

    myWebView.webViewClient = object : WebViewClient() {
        override fun onPageCommitVisible(view: WebView?, url: String?) {
    

    To the following callback:

    myWebView.webChromeClient = object : WebChromeClient() {
        override fun onProgressChanged(view: WebView?, newProgress: Int) {
    

    It looks like this does the trick. onProgressChanged is invoked several time, in my case twice with newProgress=100. I am starting the measurement in the first occurence of value 100 and it seems to work. At least so far.