Восстановление страницы Android WebView с помощью ViewModel после поворота устройства / разделения просмотра - PullRequest
0 голосов
/ 02 июня 2018

Я использую 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), за которым мне следует следить?

Спасибо, Джири

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...