Я использую WebView для отображения данных, данные увеличиваются с помощью функции JS.Он работает нормально, пока устройство не будет повернуто.Использование ViewModel для сохранения данных страницы и их восстановления после изменения конфигурации казалось правильной идеей, но я столкнулся с проблемами, страница не была восстановлена.Я сократил свой код до минималистского примера, включенного здесь (без макета XML)
Класс 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();
}
}
Простой класс веб-представления, переопределяющий WebView
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);
}
}
И, наконец, сам MainActivity
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);
}
}
Идея заключалась в том, чтобы сохранить данные в ViewModel и восстановить их во время создания.Мне понадобилось время, чтобы понять, почему это не работает.DataStore сохраняется во время ротации (я вижу все данные истории в объекте DataStore), но, хотя я вижу, что код восстановления выполняется, он никогда не отображается в SimpleWebView.
Причина в том, что покаФункция JavaScript правильно записывается на страницу, я вызываю restore () из MainActivity.OnCreate до , когда страница действительно отображается.Функция JS вызывается и быстро игнорируется, потому что страница, на самом деле, не существует в том, что касается WebView (я думаю).Удивительно, но на самом деле это работало на большинстве симуляторов, которые я использую - теперь я думаю, что это не должно, и я понятия не имею, почему это произошло - пока я не запустил его на физическом устройстве (Galaxy S7), где восстановление было проигнорировано
Моим решением было дать моему SimpleWebView новый WebViewClient и переопределить его метод OnPageFinished и восстановить в нем содержимое страницы после загрузки страницы.Конструктор SimpleView (логический флаг 'firstView' в приведенном ниже коде становится недействительным после первой перезагрузки представления после ротации устройства):
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();
}
}
});
.
.
Веб-страница теперь восстанавливается из постоянных данных после ротации устройства/ разделить окно.Кажется, это работает хорошо, без какой-либо заметной задержки загрузки (сейчас я имею дело с относительно небольшим набором данных).
Я искал решения, я действительно не хочу сохранять и восстанавливать содержимое строки ввся страница в OnSaveInstanceState / onRestoreInstanceState, потому что в этом случае это не принесет мне никакой пользы - у меня будут данные, но мне все еще нужно восстановить их после страница будет обработана
Мудрые слова, которые я ищу в коллективе:
- Правильный ли мой анализ?
- Есть ли лучшие способы справиться с этим?
- Есть что-то (неприятное производствонеожиданность кода и т. д. - я новичок в Android), за которым мне следует следить?
Спасибо, Джири