保存网页的四种方式
當我們使用瀏覽器瀏覽網頁時,常常想保存內容,目的可能是離線閱讀或者是收藏。之前的一個項目用到一些,一并總結。
方式一,Snapshot
4.0支持此方法saveViewState(),方法源碼如下
/*** Saves the view data to the output stream. The output is highly* version specific, and may not be able to be loaded by newer versions* of WebView.* @param stream The {@link OutputStream} to save to* @return True if saved successfully* @hide*/public boolean saveViewState(OutputStream stream) {try {return ViewStateSerializer.serializeViewState(stream, this);} catch (IOException e) {Log.w(LOGTAG, "Failed to saveViewState", e);}return false;}4.0原生瀏覽器其實是把網頁的內容存入到BLOB中,缺陷很明顯,網頁一大就保存不了,查了下源碼,BLOB保存的數據有大小限制。4.0上,超過2M大小的網頁就沒法保存,源碼截圖如下:
但是4.1上,saveViewState() 更新了參數,增加了回調。方法源碼如下:
4.1原生瀏覽器去snapshot的處理更好了,明白了這個限制之后,網頁的data不存數據庫了,改存文件了,所以網頁太大不能保存的問題就解決了。
考慮到大部分的網頁都比較小的情況下,且實現上快速,采用4.0的方法。
主代碼采用反射調用4.0 的saveViewState()方法,方法名改為mySaveViewState(),代碼如下:
方式二,Stream(file)
因為2.3上不支持saveViewState()方法,所以采用SavePicture(),SavePicture()方法其實來自SaveState(),在webview前進后退后者其他操作時,會保存相應的狀態。
方法源碼如下:
/*** Save the state of this WebView used in* {@link android.app.Activity#onSaveInstanceState}. Please note that this* method no longer stores the display data for this WebView. The previous* behavior could potentially leak files if {@link #restoreState} was never* called. See {@link #savePicture} and {@link #restorePicture} for saving* and restoring the display data.* @param outState The Bundle to store the WebView state.* @return The same copy of the back/forward list used to save the state. If* saveState fails, the returned list will be null.* @see #savePicture* @see #restorePicture*/public WebBackForwardList saveState(Bundle outState) {if (outState == null) {return null;}// We grab a copy of the back/forward list because a client of WebView// may have invalidated the history list by calling clearHistory.WebBackForwardList list = copyBackForwardList();final int currentIndex = list.getCurrentIndex();final int size = list.getSize();// We should fail saving the state if the list is empty or the index is// not in a valid range.if (currentIndex < 0 || currentIndex >= size || size == 0) {return null;}outState.putInt("index", currentIndex);// FIXME: This should just be a byte[][] instead of ArrayList but// Parcel.java does not have the code to handle multi-dimensional// arrays.ArrayList<byte[]> history = new ArrayList<byte[]>(size);for (int i = 0; i < size; i++) {WebHistoryItem item = list.getItemAtIndex(i);if (null == item) {// FIXME: this shouldn't happen// need to determine how item got set to nullLog.w(LOGTAG, "saveState: Unexpected null history item.");return null;}byte[] data = item.getFlattenedData();if (data == null) {// It would be very odd to not have any data for a given history// item. And we will fail to rebuild the history list without// flattened data.return null;}history.add(data);}outState.putSerializable("history", history);if (mCertificate != null) {outState.putBundle("certificate",SslCertificate.saveState(mCertificate));}return list;}/*** Save the current display data to the Bundle given. Used in conjunction* with {@link #saveState}.* @param b A Bundle to store the display data.* @param dest The file to store the serialized picture data. Will be* overwritten with this WebView's picture data.* @return True if the picture was successfully saved.*/public boolean savePicture(Bundle b, final File dest) {if (dest == null || b == null) {return false;}final Picture p = capturePicture();// Use a temporary file while writing to ensure the destination file// contains valid data.final File temp = new File(dest.getPath() + ".writing");new Thread(new Runnable() {public void run() {FileOutputStream out = null;try {out = new FileOutputStream(temp);p.writeToStream(out);// Writing the picture succeeded, rename the temporary file// to the destination.temp.renameTo(dest);} catch (Exception e) {// too late to do anything about it.} finally {if (out != null) {try {out.close();} catch (Exception e) {// Can't do anything about that}}temp.delete();}}}).start();// now update the bundleb.putInt("scrollX", mScrollX);b.putInt("scrollY", mScrollY);b.putFloat("scale", mActualScale);b.putFloat("textwrapScale", mTextWrapScale);b.putBoolean("overview", mInZoomOverview);return true;}具體實現上,我們需要傳入一個bundle,保存相應的狀態。
方式三: png
保存成圖片的缺陷很大,放縮的失真,不能編輯。Webview有capturePicture()方法支持。源碼中此方法的實現如下:
/*** Return a new picture that captures the current display of the webview.* This is a copy of the display, and will be unaffected if the webview* later loads a different URL.** @return a picture containing the current contents of the view. Note this* picture is of the entire document, and is not restricted to the* bounds of the view.*/public Picture capturePicture() {if (null == mWebViewCore) return null; // check for out of memory tabreturn mWebViewCore.copyContentPicture();}傳入picture,具體實現如下:
//FIXME draw on canvas can not run in a non-ui threadboolean saveAsPng(Context ctx, ContentValues values, Picture picture){String path = UUID.randomUUID().toString();OutputStream outs = null;try {if (null == picture)return false;String png = path + ".png";outs = ctx.openFileOutput(png, Context.MODE_PRIVATE);PictureDrawable pictureDrawable = new PictureDrawable(picture);Bitmap bitmap = null;bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(),pictureDrawable.getIntrinsicHeight(),Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);canvas.drawPicture(pictureDrawable.getPicture());bitmap.compress(Bitmap.CompressFormat.PNG, 100, outs);outs.flush();outs.close();bitmap.recycle();bitmap = null;values.put(SavedPageColumns.TYPE, SavedPage.TYPE_PNG);values.put(SavedPageColumns.PATH, png);} catch (Exception e) {Log.w(LOGTAG, "Failed to save page ", e);if (outs != null) {try {outs.close();} catch (IOException ignore) {}}File file = ctx.getFileStreamPath(path);if (file != null && file.exists() && !file.delete()) {file.deleteOnExit();}return false;}return true;}方法四: 保存html網頁
直接將url給下載管理器即可。
轉載于:https://blog.51cto.com/mikewang/1206701
總結
- 上一篇: php调色板快捷键,ps常用的调色快捷键
- 下一篇: wechat 6.6 .3android