Android Webview:在渲染完成时检测

时间:2014-01-08 15:59:54

标签: android android-webview snapshot

我想在加载WebView后对WebView进行快照。但是,返回的位图始终为null,因为即使我使用onPageFinished,渲染也未完成加载。 我在互联网上搜索,人们建议使用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("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();
        }
    }
}

7 个答案:

答案 0 :(得分:12)

您应该尝试使用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);
        }
    });

答案 1 :(得分:4)

您可以在WebView中执行此操作:

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

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

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

答案 2 :(得分:4)

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

webview.setWebViewClient(new WebViewClient(){

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

}

答案 3 :(得分:2)

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

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

感谢您的帮助。

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

答案 4 :(得分:0)

调用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.

            }
        }

答案 5 :(得分:-2)

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
    }
}

答案 6 :(得分:-2)

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")
        }
     }
 }