Обработка поворота экрана в WebView
мое веб-приложение отлично работает в Chrome, который обрабатывает изменения конфигурации (например, поворот экрана) отлично. Все прекрасно сохранилось.
При загрузке моего веб-приложения в WebView
в моем Android-приложении веб-приложение теряет состояние при изменении ориентации экрана. Это частично сохранить состояние, то есть сохранить данные <input>
элементы формы, однако все переменные JavaScript и манипуляции DOM получают потерянный.
я хотел бы, чтобы мой WebView вел себя так, как Chrome, т. е. полностью сохраняя состояние, включая любые переменные JavaScript. Следует отметить, что в то время как Chrome и WebView происходят из одной и той же базы кода, Chrome не использует WebView.
что происходит при изменении ориентации экрана, так это то, что активность (и любые возможные фрагменты) уничтожается, а затем воссоздается. WebView
наследует от View
и переопределяет методы onSaveInstanceState
и onRestoreInstanceState
для обработки изменений конфигурации, следовательно, он автоматически сохраняет и восстанавливает содержимое любых элементов формы HTML, а также состояние истории навигации назад/вперед. Однако состояние переменных JavaScript и DOM не сохраняется и не восстанавливается.
предлагаемые решения
было предложено несколько решений. Все они нерабочие, только сохраняя частичное состояние или другими способами субоптимальный.
присвоение WebView идентификатора
WebView
наследует от View
, который был методом setId
, которая также может быть объявлен в XML-файл макета с помощью android:id
атрибут в объявлении <WebView>
элемент. Это необходимо для сохранения и восстановления состояния, однако состояние восстанавливается только частично. Это восстанавливает входные элементы формы, но не переменные JavaScript и состояние DOM.
onRetainNonConfigurationInstance и getLastNonConfigurationInstance
и onRetainNonConfigurationInstance
are устаревший начиная с уровня API 13.getLastNonConfigurationInstance
принудительная ориентация экрана
активность может иметь свою ориентацию экрана принудительно, установив screenOrientation
на <Activity>
в элементе AndroidManifest.xml
файл или через setRequestedOrientation
метод. Это нежелательно, так как это нарушает ожидание вращения экрана. Это также касается только изменения ориентации экрана, а не других изменений конфигурации.
сохранение экземпляра фрагмента
не работает. Вызов метода setRetainInstance
на фрагменте сохраняет фрагмент (он не разрушается), следовательно, все переменные экземпляра фрагмента сохраняются, однако это тут уничтожить вид фрагмента отсюда WebView
does разрушается.
ручная обработка изменений конфигурации
на configChanges
атрибут может быть объявлен для Activity
на как android:configChanges="orientation|screenSize"
обработки изменения конфигурации по их предотвращению. Это работает, это предотвращает разрушение активности, следовательно,WebView
и его содержимое полностью сохраняется. Однако это было обескуражено и, как говорят, используется только в крайнем случае, так как это может привести к разрыву приложения тонкими способами и получить багги. Метод onConfigurationChanged
вызывается, когда установлен.
MutableContextWrapper
я слышал MutableContextWrapper
можно использовать, но я не оценил этот подход.
saveState () и restoreState ()
WebView
методы saveState
и restoreState
. Примечание accoriding к документации saveState
метод больше не хранит данные отображения для WebView, что бы это ни значило. В любом случае эти методы, похоже, не полностью сохраняют состояние WebView.
WebViewFragment
на WebViewFragment
это просто удобный фрагмент, который обертывает WebView
для вас, так что вы можете легко получить с меньшим шаблонным кодом, как ListFragment
. Он не делает никакого дополнительного сохранения состояния, чтобы полностью сохранить государство.
вопрос
есть ли какое-либо реальное решение проблемы WebView
разрушается и теряет свое состояние при изменении конфигурации? (например, вращение экрана)
решение полностью сохраняет все состояние, включая переменные JavaScript и манипуляции DOM. Решение, которое является чистым и не построено на взломах или устаревших методах.
4 ответов
после исследования и опробования различных подходов я обнаружил, что я пришел к выводу, что это оптимальное решение.
он использует setRetainInstance
чтобы сохранить экземпляр фрагмента вместе с addView
и removeView
на onCreateView
и onDestroyView
методы профилактики WebView
от получения разрушенный.
MainActivity.java
public class MainActivity extends Activity {
private static final String TAG_FRAGMENT = "webView";
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebViewFragment fragment = (WebViewFragment) getFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment == null) {
fragment = new WebViewFragment();
}
getFragmentManager().beginTransaction().replace(android.R.id.content, fragment, TAG_FRAGMENT).commit();
}
}
WebViewFragment.java
public class WebViewFragment extends Fragment {
private WebView mWebView;
public WebViewFragment() {
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_webview, container, false);
LinearLayout layout = (LinearLayout)v.findViewById(R.id.linearLayout);
if (mWebView == null) {
mWebView = new WebView(getActivity());
setupWebView();
}
layout.removeAllViews();
layout.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return v;
}
@Override
public void onDestroyView() {
if (getRetainInstance() && mWebView.getParent() instanceof ViewGroup) {
((ViewGroup) mWebView.getParent()).removeView(mWebView);
}
super.onDestroyView();
}
private void setupWebView() {
mWebView.loadUrl("https:///www.example.com/");
}
}
я бы посоветовал вам перерисовать все это снова. Я искал некоторое время, и я не мог найти чистое готовое решение. Все там говорится, что вы позволяете веб-странице повторно визуализировать изменение ориентации.
но если вам действительно нужно сохранить ваши переменные JS, вы можете имитировать то, что saveState
и restoreState
сделал. То, что эти методы идеально делают, это сохранить и восстановить материал в WebView
использование действия onSaveInstanceState()
и onRestoreInstanceState()
соответственно. Эти методы ничего не делают. они сделали это из-за потенциальных утечек памяти.
Итак, все, что вам нужно сделать, это создать свой собственный webview (MyWebView extends WebView
). В этом есть два метода: saveVariableState()
и restoreVariableState()
. В saveVariableState()
просто сохраните каждую переменную, которую вы хотите в комплекте, и верните ее (public Bundle saveVariableState(){}
). Теперь в onSaveInstanceState()
на Activity
, называют MyWebView.saveVariableState
и сохраните пакет, который он возвращает. Как только ориентация изменится, вы получите пакет из onRestoreInstanceState
или onCreate
и передать его в MyWebView
через конструктор или restoreVariableState
.
это не хак, но обычный способ сохранить материал данных других представлений. В случае WebView
, вместо сохранения данных представления, вы собираетесь сохранить переменные JS.
следующий код манифеста объявляет действие, которое обрабатывает изменение ориентации экрана и изменение доступности клавиатуры: этот код:
<activity android:name=".MyActivity">
будет :
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name">
здесь вы только добавляете: screenSize, тогда он работает нормально.
ссылка: https://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject
простая вещь, которую вы могли бы сделать, это что-то вроде:
WebView webView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_webview, container, false);
webView = v.findViewById(R.id.webView);
if(savedInstanceState != null){
webView.restoreState(savedInstanceState);
} else {
loadUrl();
}
return v;
}
private void loadUrl(){
webView.loadUrl("someUrlYouWant");
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
webView.saveState(outState);
}
Примечание: не пробовал этот код, просто написал его, но думаю, что он должен работать.