I have a question. At this time, the capturePicture of WebView is deprecated.
I want to ask if there is a way to replace the funct
Use draw()
method of WebView
Example :
ImageView imageview;
WebView webview;
class Background extends AsyncTask<Void, Void, Bitmap>
{
@Override
protected Bitmap doInBackground(Void... params)
{
try
{
Thread.sleep(2000);
Bitmap bitmap = Bitmap.createBitmap(webview.getWidth(), webview.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
webview.draw(canvas);
return bitmap;
}
catch (InterruptedException e){}
catch (Exception e){}
return null;
}
@Override
protected void onPostExecute(Bitmap result)
{
imageview.setImageBitmap(result);
}
}
webview.setWebChromeClient(new WebChromeClient()
{
public void onProgressChanged(WebView view, int progress)
{
if(progress==100)
new Background().execute();
}
});
Just extends BaseWebView
below:
public abstract class BaseWebView extends WebView {
private static final String TAG = "BaseWebView";
private static final int DELAY_MS_MAX = 1000;
private static final int DELAY_MS_DRAW = 100;
private static final long REQUEST_ID_INIT = 0;
public BaseWebView(Context context) {
super(context);
init();
}
public BaseWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BaseWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* to make sure to set {@link #loadDataFinished} to true at last
* in {@link #DELAY_MS_MAX} ms later.
*/
private static final int MSG_LOAD_DATA_FINISH_DEF = 0;
/**
* to set {@link #loadDataFinished} to true in {@link #DELAY_MS_DRAW} ms later.
*/
private static final int MSG_LOAD_DATA_FINISH_DRAW = 1;
private String description;
/**
* if load data finished
* <P><P>
* mark the status for load API {@link #loadData(String, String, String)}
* & {@link #loadDataWithBaseURL(String, String, String, String, String)}
* <p>
* <b>ignored:</b> {@link #loadUrl(String)}, {@link #loadUrl(String, Map)} and {@link #reload()}
*/
private AtomicBoolean loadDataFinished = new AtomicBoolean(true);
/**
* if progress reached 1000
* <P><P>
* mark the status for load API {@link #loadData(String, String, String)}
* & {@link #loadDataWithBaseURL(String, String, String, String, String)}
* <p>
* <b>ignored:</b> {@link #loadUrl(String)}, {@link #loadUrl(String, Map)} and {@link #reload()}
*/
private AtomicBoolean progressFinished = new AtomicBoolean(true);
/**
* the request id of load data
* <P><P>
* mark the status for load API {@link #loadData(String, String, String)}
* & {@link #loadDataWithBaseURL(String, String, String, String, String)}
* <p>
* <b>ignored:</b> {@link #loadUrl(String)}, {@link #loadUrl(String, Map)} and {@link #reload()}
*/
private AtomicLong loadDataTimestamp = new AtomicLong(REQUEST_ID_INIT);
private Handler handler = new MyHandler(this);
/**
* clear status for load API {@link #loadData(String, String, String)}
* & {@link #loadDataWithBaseURL(String, String, String, String, String)}, set to false.
* <p>
* <b>ignored:</b> {@link #loadUrl(String)}, {@link #loadUrl(String, Map)} and {@link #reload()}
* <p>
* <b>Usage:</b> call in load API {@link #loadData(String, String, String)}
* & {@link #loadDataWithBaseURL(String, String, String, String, String)}
*/
private void clearLoadDataStatus() {
DLog.d(TAG, "clearLoadDataStatus: set false, obj=" + this.hashCode());
loadDataFinished.set(false);
progressFinished.set(false);
// generates a new load request id
loadDataTimestamp.set(System.currentTimeMillis());
}
private void setLoadDataFinished(long requestId) {
DLog.d(TAG, "setLoadDataFinished: id=" + requestId
+ ", loadDataTimestamp=" + loadDataTimestamp.get() + ", obj=" + this.hashCode());
if (!progressFinished.get() || requestId != loadDataTimestamp.get()) {
return;
}
loadDataFinished();
}
private void loadDataFinished() {
DLog.d(TAG, "loadDataFinished: set true, obj=" + this.hashCode());
loadDataFinished.set(true);
// clear load request id
loadDataTimestamp.set(REQUEST_ID_INIT);
}
/**
* get status for load API {@link #loadData(String, String, String)}
* & {@link #loadDataWithBaseURL(String, String, String, String, String)}, set to false.
* <p>
* <b>ignored:</b> {@link #loadUrl(String)}, {@link #loadUrl(String, Map)} and {@link #reload()}
*/
public boolean isLoadDataFinished() {
return loadDataFinished.get();
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
private void handleLoadDataFinished(int what) {
if (loadDataTimestamp.get() == REQUEST_ID_INIT) {
// there is no load data actions
//DLog.w(TAG, "handleLoadDataFinished: there is no load data actions, obj="
// + this.hashCode());
return;
}
DLog.d(TAG, "handleLoadDataFinished: obj=" + this.hashCode());
int delay = 0;
long requestId = loadDataTimestamp.get();
if (what == MSG_LOAD_DATA_FINISH_DEF) {
delay = DELAY_MS_MAX;
} else if (what == MSG_LOAD_DATA_FINISH_DRAW) {
delay = DELAY_MS_DRAW;
}
handler.removeMessages(what);
handler.sendMessageDelayed(Message.obtain(handler, what, (Object) requestId), delay);
}
private void init() {
this.setWebChromeClient(new DefWebChromeClient());
this.setHorizontalScrollBarEnabled(false);
this.setVerticalScrollBarEnabled(false);
this.description = onGetDescription();
}
/**
* a description of this WebView
*/
abstract public String onGetDescription();
@Override
public void loadDataWithBaseURL(
@Nullable String baseUrl, String data, @Nullable String mimeType,
@Nullable String encoding, @Nullable String historyUrl) {
clearLoadDataStatus();
super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
@Override
public void loadData(String data, @Nullable String mimeType, @Nullable String encoding) {
clearLoadDataStatus();
super.loadData(data, mimeType, encoding);
}
@Override
public void stopLoading() {
super.stopLoading();
loadDataFinished();
}
@Override
public void setWebChromeClient(WebChromeClient client) {
if (!(client instanceof DefWebChromeClient)) {
throw new IllegalArgumentException(
"the WebChromeClient must be an instance of " + DefWebChromeClient.class);
}
super.setWebChromeClient(client);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//Log.d(TAG, "onDraw: " + this.hashCode());
if (progressFinished.get()) {
// set load data finished in DELAY_MS_DRAW.
// !!! Notice that the Runnable will not be exec if this WebView is not to show,
// and this will cause the `loadDataFinished` being `false` all the time,
// if you want that executing whatever, plz use `handle.post()`.
post(new Runnable() {
@Override
public void run() {
handleLoadDataFinished(MSG_LOAD_DATA_FINISH_DRAW);
}
});
}
}
class DefWebChromeClient extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if (newProgress == 100) {
progressFinished.set(true);
// set load data finished in DELAY_MS_MAX as def.
// !!! Notice that the Runnable will not be exec if this WebView is not to show,
// and this will cause the `loadDataFinished` being `false` all the time,
// if you want that executing whatever, plz use `handle.post()`.
post(new Runnable() {
@Override
public void run() {
handleLoadDataFinished(MSG_LOAD_DATA_FINISH_DEF);
}
});
}
Log.d(TAG, "onProgressChanged: " + newProgress
+ ", desc=" + description + ", obj=" + view.hashCode());
}
}
static class MyHandler extends Handler {
WeakReference<BaseWebView> mViewReference;
MyHandler(BaseWebView webView) {
mViewReference = new WeakReference<>(webView);
}
@Override
public void handleMessage(Message msg) {
final BaseWebView webView = mViewReference.get();
if (webView == null) {
return;
}
// handle msg
if (msg.what == MSG_LOAD_DATA_FINISH_DEF || msg.what == MSG_LOAD_DATA_FINISH_DRAW) {
webView.setLoadDataFinished((Long) msg.obj);
}
}
}
}
=== END ===
Notice that only loadData()
& loadDataWithBaseURL()
works above,
you can add loadUrl()
, reload()
by yourself if needed.
Demo:https://github.com/zhaoya188/completed-load-webview
I finally found out the solution.
Some of codes
public class WebViewActivity extends Activity {
private static WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);
webView = (WebView) findViewById(R.id.webView1);
webView.loadUrl("http://developer.android.com/reference/packages.html");
// webView.loadUrl("http://developer.android.com/training/basics/firstapp/creating-project.html");
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// do your stuff here
webView.measure(MeasureSpec.makeMeasureSpec(
MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
webView.layout(0, 0, webView.getMeasuredWidth(),
webView.getMeasuredHeight());
webView.setDrawingCacheEnabled(true);
webView.buildDrawingCache();
Bitmap bm = Bitmap.createBitmap(webView.getMeasuredWidth(),
webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas bigcanvas = new Canvas(bm);
Paint paint = new Paint();
int iHeight = bm.getHeight();
bigcanvas.drawBitmap(bm, 0, iHeight, paint);
webView.draw(bigcanvas);
System.out.println("1111111111111111111111="
+ bigcanvas.getWidth());
System.out.println("22222222222222222222222="
+ bigcanvas.getHeight());
if (bm != null) {
try {
String path = Environment.getExternalStorageDirectory()
.toString();
OutputStream fOut = null;
File file = new File(path, "/aaaa.png");
fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.PNG, 50, fOut);
fOut.flush();
fOut.close();
bm.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
}
The layout.xml
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>