如何保存和恢复android WebView';什么是WebBackForwardList?

如何保存和恢复android WebView';什么是WebBackForwardList?,android,webview,android-webview,Android,Webview,Android Webview,我正在尝试使用android studio的WebView实现一个简单的web浏览器应用程序。我想将我的WebView状态(例如WebBackForwardList)保存到内部存储,并在重新启动应用程序时将其还原。我不想只加载上次访问的url,相反,我还希望在调用WebView的goBack()或goForward()方法时,我希望它从内部存储中恢复以前和下次访问的链接 我目前已经实现了我自己的WebView、WebViewClient和WebChromeClient,并将访问的链接作为字符串保

我正在尝试使用android studio的WebView实现一个简单的web浏览器应用程序。我想将我的WebView状态(例如WebBackForwardList)保存到内部存储,并在重新启动应用程序时将其还原。我不想只加载上次访问的url,相反,我还希望在调用WebView的
goBack()
goForward()
方法时,我希望它从内部存储中恢复以前和下次访问的链接

我目前已经实现了我自己的WebView、WebViewClient和WebChromeClient,并将访问的链接作为字符串保存到内部存储器中,以便在还原时通过调用
goBack()
goForward()
的覆盖方法中的
loadUrl()
来加载它们。但这使得页面加载速度比WebView自己的
goBack()
goForward()
方法慢,而且它也不会恢复滚动位置、缩放等

所以我有两个问题,

有一种方法可以通过调用
copyBackForwardList()
方法来获取WebView的WebBackForwardList,但是有没有一种方法可以设置/编辑WebBackForwardList


如果没有,我如何在重启应用程序后保存和恢复它?

这不是最好的解决方案,但我为这种情况实施了一种解决方法。简单地说,我正在将WebBackForwardList项目的URL从零保存到当前索引,保存到名为
backStack
堆栈,从当前索引加上一个到最后一个索引保存到
forwardStack
。然后我将这些堆栈和当前项目的URL保存到内部存储器中

重新启动应用程序时,WebView将加载当前项目URL。当用户想要返回或前进时,我首先检查WebView是否可以返回或前进。如果可以,我调用WebView的
goBack()
方法。如果不能,那么我从保存到内部存储器的堆栈中弹出并加载URL

但当从
backStack
加载URL时,我必须将当前WebBackForwardList的项目URL推送到
forwardStack
并清除WebView历史记录。这是必要的,因为WebView将上次加载的URL保存到WebBackForwardList的最后一个索引。这会扭曲WebBackForwardList,因为我正在加载前一项


它目前运行良好,但正如我所说,这不是最好的解决方案。

您应该使用
restoreState
saveState
来实现保存和恢复

class AppWebTab extents WebView{
    long unique_tab_id;
   
    public void boolean load(){
        File stackpath = new File(getContext().getExternalCacheDir(), "webstack"+unique_tab_id);

        if(stackpath.exists()) {
            Parcel parcel = Parcel.obtain();
            byte[] data = ...//read file as Byte Array
            parcel.unmarshall(data, 0, data.length); 
            parcel.setDataPosition(0);
            Bundle bundle = new Bundle();
            bundle.readFromParcel(parcel);
            parcel.recycle();
            
            WebBackForwardList stacks = restoreState(bundle);
            
            if(stacks!=null && stacks.getSize()>0) {
                return true;
            }
        }
        
        return false;
    }

    public void save(){
        File stackpath = new File(getContext().getExternalCacheDir(), "webstack"+unique_tab_id);
        
        Bundle bundle = new Bundle();
        
        WebBackForwardList stacks = saveState(bundle);

        if(stacks!=null&&stacks.getSize()>0) {
            Parcel parcel = Parcel.obtain();
            parcel.setDataPosition(0);
            bundle.writeToParcel(parcel, 0);
            byte[] bytes = parcel.marshall();
            parcel.recycle();
           ...//save Byte Array Data to file
        } else {
            stackpath.delete();
        }
    }
}

由于chromium的努力,当设备离线但本地缓存可用时,保存的BackForwardList甚至可以导航

但不能直接修改WebBackForwardList。因此,如果您有多个Web视图代表一个浏览器选项卡(豪华但有时很有用),则很难将多个BackForwardList合并并保存为一个,这是一个遗憾


正如@j_um所说,系统升级和格式更改可能会导致此方法失败。经过测试,WebView(
WebView\u Chromiu\u STATE
)的数据具有一定的向下兼容性,而包裹则没有

在测试中,使用Parcel存储的数据不能跨越Android版本。因此,我必须使用
ObjectOutputStream
来实现我自己的序列化方法,这几乎是相同的。因此,使用ObjectOutputStream保存的数据在从Android 4.4到Android 9的更新中幸存了下来,可以通过解析成功恢复页面


必须考虑数据格式兼容性,尤其是在不同版本的android设备上同步选项卡时

现在使用这项技术+webdav服务器并安装了相同版本的webview.apk,我可以让用户从android 9->android 6共享浏览状态,反之亦然


如果webview.apk的版本不同,或者根本没有安装,那么您将遇到前向兼容性问题,网页将显示为空白(未观察到崩溃)。但是向后兼容性仍然可以。

这种方式非常合理,可以正确地存储webview的状态(甚至滚动位置)。但是,如果捆绑包大小超过2048kb,应用程序将崩溃。希望有一种方法可以优化捆绑包数据,使其正常工作(我认为存储在捆绑包中的webview状态有很多东西我们不需要存储)。您不会达到这个数字。历史堆栈将自动调整到200kb左右。
Parcelable
格式应该只用于IPC,而不是持久存储。任何Android更新都可能引入不兼容的更改,最好的情况下会丢失您的历史记录,最坏的情况下会导致您的应用程序抛出异常,如果您不准备捕获它,则会导致应用程序崩溃。相反,您应该在包的键上循环并自己存储每个值。它比使用
地块
的代码要多,但它具有实际工作的优势。因此,Parcelable和webview的数据格式可能会更改,导致此方法失败。我想知道这次失败的可能性是否很大?失败会使我的应用程序崩溃吗?