Android Webview:检测渲染何时完成

Posted

技术标签:

【中文标题】Android Webview:检测渲染何时完成【英文标题】:Android Webview: Detect when rendering is finished 【发布时间】:2014-01-26 20:14:54 【问题描述】:

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

一些代码

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("/storage/sdcard0/a.png");
            bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
            out.close();
         catch (Exception e) 
            e.printStackTrace();
        
    

【问题讨论】:

【参考方案1】:

Kotlin 解决方案

第一个解决方案

class MainActivity : AppCompatActivity() 
  override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val webView : WebView = findViewById(R.id.webView)
    webView.webViewClient = MyWebViewClient()
 

private class MyWebViewClient : WebViewClient() 
    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) 
        println("Load Started")
    
    override fun onPageFinished(view: WebView, url: String) 
        println("Load Finished")
    
  

第二个解决方案

class MainActivity : AppCompatActivity() 
  override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val webView : WebView = findViewById(R.id.webView)
    webView.webViewClient = object : WebViewClient() 
        override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) 
            println("Load Started")
        
        override fun onPageFinished(view: WebView, url: String) 
            println("Load Finished")
        
     
 

【讨论】:

【参考方案2】:

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

但是你可以从 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.

            
        

【讨论】:

【参考方案3】:

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

webview.setWebViewClient(new WebViewClient()

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

【讨论】:

我不同意。我发现触发了以下序列:onPageCommitVisible -> onProgressChanged -> onPageFinished【参考方案4】:

您可以在 WebView 中这样做:

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

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

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

【讨论】:

【参考方案5】:

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

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

感谢您的所有帮助。

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

【讨论】:

为什么这个答案没有显示您的问题和解决方案?【参考方案6】:
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
    

【讨论】:

当我写下我的答案时,上面没有其他答案。所以我们都给了你相同的答案:)【参考方案7】:

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

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

编辑:检查 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);
        
    );

【讨论】:

不起作用,虽然newProgress = 100,但渲染还没有完成。还有什么? 您的 onPageFinished 和/或 onPageStarted 是多次调用还是只调用一次? 我不会覆盖这些函数。看看我上面的代码 然后覆盖它们并检查它们是否被多次调用。您可以为同一个 WebView 使用 WebChromeClient 和 WebViewClient。 你能解释更多吗?

以上是关于Android Webview:检测渲染何时完成的主要内容,如果未能解决你的问题,请参考以下文章

如何检测 Cordova WebView 何时完全完成加载?

如何检测 ListView 或任何控件何时完成渲染?

如何判断 UIWebView 何时完成渲染(未加载)?

Android检测webview URL更改

检测 webview 视频何时在 ios8 上变为全屏

Android:检测何时安装应用程序