Javascript 在设备旋转/拆分视图后使用ViewModel还原Android WebView页面
我使用WebView显示数据,数据通过JS函数得到增强。在设备旋转之前,它可以正常工作。使用ViewModel保存页面数据并在配置更改后恢复它似乎是正确的想法,但我遇到了问题,页面没有恢复。我将代码简化为一个简单的示例,包括在这里(无XML布局)Javascript 在设备旋转/拆分视图后使用ViewModel还原Android WebView页面,javascript,android,webview,rotation,viewmodel,Javascript,Android,Webview,Rotation,Viewmodel,我使用WebView显示数据,数据通过JS函数得到增强。在设备旋转之前,它可以正常工作。使用ViewModel保存页面数据并在配置更改后恢复它似乎是正确的想法,但我遇到了问题,页面没有恢复。我将代码简化为一个简单的示例,包括在这里(无XML布局) DataStore类存储数据,覆盖ViewModel,只需在列表中存储一些字符串 package com.automationce.labyrinth.webview; import android.arch.lifecycle.ViewModel
DataStore类存储数据,覆盖ViewModel,只需在列表中存储一些字符串
package com.automationce.labyrinth.webview;
import android.arch.lifecycle.ViewModel;
import java.util.ArrayList;
import java.util.List;
/* The idea is to use ViewModel to store page data
* so it can be restored on device rotate/split view */
public final class DataStore extends ViewModel {
public List<String> records = new ArrayList<>();
public DataStore() {
super();
}
}
其想法是在ViewModel中保存数据,并在创建过程中恢复数据。我花了一段时间才明白为什么它不起作用。数据存储在旋转期间确实会被保留(我可以看到数据存储对象中的所有历史数据),但尽管我看到正在执行的恢复代码,但它从未在SimpleWebView中呈现
原因是,虽然JavaScript函数确实正确写入了页面,但我在页面实际呈现之前从MainActivity.OnCreate调用restore()。JS函数被调用并很快被忽略,因为实际上,就WebView而言,页面并不存在(我认为)。令人惊讶的是,这实际上在我使用的大多数模拟器上都起了作用——现在我认为它不应该起作用,我也不知道它为什么起作用——直到我在一个物理设备(Galaxy S7)上运行它,在那里恢复被忽略了
我的解决方案是为我的SimpleWebView提供一个新的WebViewClient并重写其OnPageFinished方法,并在该方法中在页面加载完成后恢复页面内容。SimpleView构造函数(“以下代码中的firstView”布尔标志在设备旋转后首次重新加载视图后失效): 在设备旋转/拆分窗口之后,现在可以从持久数据重建网页。它似乎工作得很好,没有任何明显的负载延迟(我现在处理的是相对较小的数据集) 我一直在寻找解决方案,我真的不想在OnSaveInstanceState/onRestoreInstanceState中保存和还原整个页面的字符串内容,因为在这种情况下,这对我没有任何好处-我会有数据,但在呈现页面后仍需要还原它 我从集体中寻求智慧的话语:
- 我的分析正确吗
- 有没有更好的处理方法
- 是否有什么事情(令人不快的生产代码惊喜,等等——我对Android很陌生)需要我注意
package com.automationce.labyrinth.webview;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.webkit.WebView;
public final class SimpleWebView extends WebView {
// Use to keep and restore data between config changes
// (not related to browser history by any means)
private DataStore dataStore;
public SimpleWebView(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.LTGRAY);
getSettings().setJavaScriptEnabled(true);
setWebContentsDebuggingEnabled(true);
// Define style, write JS function(s)
String content = "<!DOCTYPE html><html><head>" +
"<style>" +
"span { font-size: " +
0.875 +
"em; } " +
"</style>" +
"</head><body id=\"body\">" +
jsFunctions() + "</body></html>";
loadDataWithBaseURL(null, content, "text/html", "utf-8", null);
}
// JS function(s) as written to the page
private String jsFunctions() {
return "<script>" +
"function append (string) { " +
"var body = document.getElementById('body');" +
"var block = document.createElement('span');" +
"var text = document.createTextNode(string);" +
"var br = document.createElement('br'); " +
"block.appendChild(text);" +
"block.appendChild(br); " +
"body.appendChild(block);" +
"block.scrollIntoView();" +
" }" +
"</script>";
}
public void setHistory (final DataStore storedData) {
dataStore = storedData;
}
// Restore page from DataStore data
public void restore() {
for(String record : dataStore.records) {
evaluateJavascript("append ('" + record + "');", null);
}
}
// Append new data to existing page
public void append(final String string) {
dataStore.records.add(string);
evaluateJavascript("append ('" + string + "');", null);
}
}
package com.automationce.labyrinth.webview;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private SimpleWebView pageView;
private Button appendButton;
private int counter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DataStore storedData = ViewModelProviders.of(this).get(DataStore.class);
appendButton = findViewById(R.id.button);
pageView = findViewById(R.id.webView);
pageView.setHistory(storedData);
pageView.restore();
appendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
append();
}
});
}
private void append() {
counter++;
pageView.append("Some kind of new text " + counter);
}
}
public SimpleWebView(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.LTGRAY);
getSettings().setJavaScriptEnabled(true);
setWebContentsDebuggingEnabled(true);
setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.v("PAGE", "finished");
if (firstView) {
((SimpleWebView)view).restore();
}
}
});
.
.