Android WebView: обработка изменений ориентации


147

Проблема заключается в производительности после ротации. WebView должен перезагрузить страницу, что может быть немного утомительно.

Каков наилучший способ обработки изменения ориентации без перезагрузки страницы из источника каждый раз?


3
Под «перезагрузкой из источника» вы подразумеваете, что она снова загружает страницу, или просто перерисовывает ее?
Джереми Логан

Решение, на которое ссылается Blackhex, решило мою проблему.
Итало Борссатто

6
Интересно, что, черт возьми, такого особенного в моем приложении, что ни один из этих ответов не работает ...
RobinJ

Ответы:


91

Если вы не хотите, чтобы WebView перезагружался при изменении ориентации, просто переопределите onConfigurationChanged в своем классе Activity:

@Override
public void onConfigurationChanged(Configuration newConfig){        
    super.onConfigurationChanged(newConfig);
}

И установите атрибут android: configChanges в манифесте:

<activity android:name="..."
          android:label="@string/appName"
          android:configChanges="orientation|screenSize"

Для получения дополнительной информации см .:
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

https://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges


4
Я тестировал, но обнаружил, что не работает, установить атрибут configChanges, как показано ниже, будет работать. android: configChanges = "клавиатура скрытая | ориентация"
virsir

18
делать это на самом деле не рекомендуется, как уже много раз упоминалось ранее
Матиас

3
Матиас: Это не совсем так - см. Javadoc для WebView.
кртек

Об этом решении следует отметить две вещи: 1) Если у вас есть абстрактное действие с веб-представлением, configChangesатрибут добавляется в подклассовое действие 2) Если ваше приложение зависит от нескольких проектов, configChangesатрибут добавляется в манифест одного из вершина дерева зависимостей (это может быть не проект, содержащий класс Activity).
Аманда С

4
Такой onConfigurationChangedметод переопределения бесполезен.
Miha_x64

69

Изменить: этот метод больше не работает, как указано в документации


Оригинальный ответ:

Это можно сделать, переписав onSaveInstanceState(Bundle outState)вашу активность и позвонив saveStateиз веб-просмотра:

   protected void onSaveInstanceState(Bundle outState) {
      webView.saveState(outState);
   }

Затем восстановите это в своем onCreate после того, как веб-представление было раздуто, конечно:

public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.blah);
   if (savedInstanceState != null)
      ((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}

26
Это не работает при изменении ориентации - отображается пустой экран. Методы saveState \ restoreState вызываются, но это не помогает.
Алексей Малованый

1
Вот фрагмент кода onCreate: setContentView (R.layout.webview); mWebView = (WebView) findViewById (R.id.webview); if (saveInstanceState == null) {mWebView.getSettings (). setJavaScriptEnabled (true); mWebView.setWebViewClient (новый SimpleWebViewClient ()); mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } else {mWebView.restoreState (saveInstanceState); }
Алексей Малованый

12
Из документации saveState: обратите внимание, что этот метод больше не сохраняет данные отображения для этого WebView. Предыдущее поведение может привести к утечке файлов ...
brillenheini

5
«Обратите внимание, что этот метод больше не сохраняет данные отображения для этого WebView» - developer.android.com/reference/android/webkit/WebView.html
Стивен Марк Форд

Кто-нибудь есть какие-либо предложения о том, что теперь делать, что «этот метод больше не хранит данные дисплея для этого WebView», чтобы предотвратить перезагрузку формы WebView?
Лукас П.

24

Лучшим ответом на это будет следующая документация Android, найденная здесь. В основном это предотвратит перезагрузку Webview:

<activity android:name=".MyActivity"
      android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection|uiMode"
      android:label="@string/app_name">

При желании вы можете исправить аномалии (если они есть), переопределив onConfigurationChangedдействие:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

6
Я уверен, вам не нужен метод onConfigurationChanged (), просто дополнительный атрибут в манифесте. Я предполагаю, что нативная поддержка для этого была предоставлена ​​WebView, и именно поэтому этот ответ сейчас является лучшим (потому что он не работал, когда первоначально задавался вопрос)
Booger

1
Я одобряю @Booger, вам не нужно переопределять метод onConfigurationChanged (). Все, что вам нужно, это добавить android: configChanges = "direction | screenSize" в файле manifest.xml.
Озануркан

5

Я попытался использовать onRetainNonConfigurationInstance (возвращая WebView ), затем вернуть его с getLastNonConfigurationInstance во время onCreate и переназначить его.

Кажется, пока не работает. Я не могу помочь, но думаю, что я действительно близко! Пока что я просто получаю пустой / белый фон вместо WebView . Размещать здесь в надежде, что кто-то может помочь протолкнуть этот за финишную черту.

Может быть, мне не следует передавать WebView . Возможно, объект из WebView ?

Другой метод, который я попробовал - не мой любимый - установить это в упражнении:

 android:configChanges="keyboardHidden|orientation"

... а потом ничего не делать здесь:

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  // We do nothing here. We're only handling this to keep orientation
  // or keyboard hiding from causing the WebView activity to restart.
}

Это работает, но это не может считаться лучшей практикой .

Между тем, у меня также есть один ImageView, который я хочу автоматически обновлять в зависимости от поворота. Это оказывается очень легко. Под моей resпапке, у меня есть drawable-landи drawable-portПРОВЕДЕТ вариации пейзаж / портрет, то я использую R.drawable.myimagenameдля ImageView «s источника и Android„делает правильно“- яй!

... кроме случаев, когда вы смотрите изменения конфигурации, тогда это не так. :(

Так что я в ссоре. Используйте onRetainNonConfigurationInstance, и ротация ImageView работает, но постоянство WebView не ... или используйте onConfigurationChanged, и WebView остается стабильным, но ImageView не обновляется. Что делать?

Последнее замечание: в моем случае форсирование ориентации не является приемлемым компромиссом. Мы действительно хотим изящно поддержать ротацию. Вроде как, как работает приложение Android Browser! ;)


7
Вы не должны возвращать никакие представления из onRetainNonConfigurationInstance. Виды привязаны к контексту действия, поэтому, если вы сохраняете вид, вы переносите весь этот багаж каждый раз, когда происходит изменение ориентации. Вид "утек". (См. Последний абзац здесь: developer.android.com/resources/articles/… ). Для onRetainNonConfigurationInstance рекомендуется сохранять данные, необходимые для представления, а не само представление.
Деклан Шанаги

3

Один компромисс - избежать вращения. Добавьте это, чтобы исправить действие только для книжной ориентации.

android:screenOrientation="portrait"

Это на самом деле работает во многих случаях и является решением, которое я решил реализовать :-)
Abdo

1
хе-хе, это изменение требований
Макс Ч.

3

Лучший способ обрабатывать изменения ориентации и предотвращать перезагрузку WebView при повороте.

@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}

Имея это в виду, чтобы предотвратить вызов onCreate () каждый раз, когда вы меняете ориентацию, вам нужно добавить android:configChanges="orientation|screenSize" to the AndroidManifest.

или просто ..

android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"`

3

Просто напишите следующие строки кода в вашем файле манифеста - больше ничего. Это действительно работает:

<activity android:name=".YourActivity"
  android:configChanges="orientation|screenSize"
  android:label="@string/application_name">

3

Я понимаю, что это немного поздно, однако это ответ, который я использовал при разработке своего решения:

AndroidManifest.xml

    <activity
        android:name=".WebClient"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize" <--- "screenSize" important
        android:label="@string/title_activity_web_client" >
    </activity>

WebClient.java

public class WebClient extends Activity {

    protected FrameLayout webViewPlaceholder;
    protected WebView webView;

    private String WEBCLIENT_URL;
    private String WEBCLIENT_TITLE;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_client);
        initUI();
    }

    @SuppressLint("SetJavaScriptEnabled")
    protected void initUI(){
        // Retrieve UI elements
        webViewPlaceholder = ((FrameLayout)findViewById(R.id.webViewPlaceholder));

        // Initialize the WebView if necessary
        if (webView == null)
        {
            // Create the webview
            webView = new WebView(this);
            webView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
            webView.getSettings().setSupportZoom(true);
            webView.getSettings().setBuiltInZoomControls(true);
            webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
            webView.setScrollbarFadingEnabled(true);
            webView.getSettings().setJavaScriptEnabled(true);
            webView.getSettings().setPluginState(android.webkit.WebSettings.PluginState.ON);
            webView.getSettings().setLoadsImagesAutomatically(true);

            // Load the URLs inside the WebView, not in the external web browser
            webView.setWebViewClient(new SetWebClient());
            webView.setWebChromeClient(new WebChromeClient());

            // Load a page
            webView.loadUrl(WEBCLIENT_URL);
        }

        // Attach the WebView to its placeholder
        webViewPlaceholder.addView(webView);
    }

    private class SetWebClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.web_client, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }else if(id == android.R.id.home){
            finish();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        if (webView.canGoBack()) {
            webView.goBack();
            return;
        }

        // Otherwise defer to system default behavior.
        super.onBackPressed();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig){
        if (webView != null){
            // Remove the WebView from the old placeholder
            webViewPlaceholder.removeView(webView);
        }

        super.onConfigurationChanged(newConfig);

        // Load the layout resource for the new configuration
        setContentView(R.layout.activity_web_client);

        // Reinitialize the UI
        initUI();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState){
        super.onSaveInstanceState(outState);

        // Save the state of the WebView
        webView.saveState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState){
        super.onRestoreInstanceState(savedInstanceState);

        // Restore the state of the WebView
        webView.restoreState(savedInstanceState);
    }

}

2

Вы можете попробовать использовать onSaveInstanceState()и onRestoreInstanceState()в своей деятельности для вызова saveState(...)и restoreState(...)на вашем экземпляре WebView.


2

Это 2015 год, и многие люди ищут решение, которое все еще работает на телефонах Jellybean, KK и Lollipop. После долгих попыток я нашел способ сохранить веб-вид без изменений после изменения ориентации. Моя стратегия заключается в том, чтобы хранить веб-представление в отдельной статической переменной в другом классе. Затем, если происходит ротация, я отсоединяю веб-представление от действия, ожидаю завершения ориентации и снова присоединяю веб-представление к действию. Например ... сначала поместите это в ваш манифест (клавиатура скрытая и клавиатура необязательны):

<application
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name="com.myapp.abc.app">

    <activity
            android:name=".myRotatingActivity"
            android:configChanges="keyboard|keyboardHidden|orientation">
    </activity>

В ОТДЕЛЬНОМ КЛАССЕ ПРИМЕНЕНИЯ положите:

     public class app extends Application {
            public static WebView webview;
            public static FrameLayout webviewPlaceholder;//will hold the webview

         @Override
               public void onCreate() {
                   super.onCreate();
    //dont forget to put this on the manifest in order for this onCreate method to fire when the app starts: android:name="com.myapp.abc.app"
                   setFirstLaunch("true");
           }

       public static String isFirstLaunch(Context appContext, String s) {
           try {
          SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
          return prefs.getString("booting", "false");
          }catch (Exception e) {
             return "false";
          }
        }

    public static void setFirstLaunch(Context aContext,String s) {
       SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(aContext);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString("booting", s);
            editor.commit();
           }
        }

В ДЕЯТЕЛЬНОСТЬ вкладывается:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(app.isFirstLaunch.equals("true"))) {
            app.setFirstLaunch("false");
            app.webview = new WebView(thisActivity);
            initWebUI("www.mypage.url");
        }
}
@Override
    public  void onRestoreInstanceState(Bundle savedInstanceState) {
        restoreWebview();
    }

public void restoreWebview(){
        app.webviewPlaceholder = (FrameLayout)thisActivity.findViewById(R.id.webviewplaceholder);
        if(app.webviewPlaceholder.getParent()!=null&&((ViewGroup)app.webview.getParent())!=null) {
            ((ViewGroup) app.webview.getParent()).removeView(app.webview);
        }
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
        app.webview.setLayoutParams(params);
        app.webviewPlaceholder.addView(app.webview);
        app.needToRestoreWebview=false;
    }

protected static void initWebUI(String url){
        if(app.webviewPlaceholder==null);
          app.webviewPlaceholder = (FrameLayout)thisActivity.findViewById(R.id.webviewplaceholder);
        app.webview.getSettings().setJavaScriptEnabled(true);       app.webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        app.webview.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
        app.webview.getSettings().setSupportZoom(false);
        app.webview.getSettings().setBuiltInZoomControls(true);
        app.webview.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
        app.webview.setScrollbarFadingEnabled(true);
        app.webview.getSettings().setLoadsImagesAutomatically(true);
        app.webview.loadUrl(url);
        app.webview.setWebViewClient(new WebViewClient());
        if((app.webview.getParent()!=null)){//&&(app.getBooting(thisActivity).equals("true"))) {
            ((ViewGroup) app.webview.getParent()).removeView(app.webview);
        }
        app.webviewPlaceholder.addView(app.webview);
    }

Наконец, простой XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".myRotatingActivity">
    <FrameLayout
        android:id="@+id/webviewplaceholder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</RelativeLayout>

В моем решении есть несколько вещей, которые можно улучшить, но я уже потратил много времени, например: более короткий способ проверки, был ли Activity запущен в первый раз вместо использования хранилища SharedPreferences. Этот подход сохраняет веб-просмотр без изменений (afaik), его текстовые поля, метки, пользовательский интерфейс, переменные javascript и состояния навигации, которые не отражаются в URL.


1
Зачем даже пытаться отсоединить и снова подключить WebView, если он никогда не разрушается, поскольку вы вручную обрабатываете изменения конфигурации?
Фред

@Fred Потому что я хочу сохранить точное состояние веб-просмотра и его содержимого без изменений, включая файлы cookie, а также состояние кнопок и флажков, реализованных с помощью HTML5 или JS внутри веб-страницы, загруженной веб-представлением. Единственная настройка, которую я делаю, это изменение размера.
Джош

Фред имел в виду, что вам не нужно отсоединять / повторно подключать веб-представление через статический класс, поскольку вы объявили configChanges в манифесте. Таким образом, ваши взгляды и действия не будут разрушены во время ротации в любом случае.
Евгений Картоев

2

Единственное, что вам нужно сделать, это добавить этот код в ваш файл манифеста:

<activity android:name=".YourActivity"
      android:configChanges="orientation|screenSize"
      android:label="@string/application_name">

2

Обновление: текущая стратегия состоит в том, чтобы переместить экземпляр WebView в класс приложения вместо сохраненного фрагмента, когда он отсоединен, и снова присоединить его к резюме, как это делает Джош. Чтобы предотвратить закрытие приложения, вы должны использовать службу переднего плана, если вы хотите сохранить состояние, когда пользователь переключается между приложениями.

Если вы используете фрагменты, вы можете использовать сохранить экземпляр WebView. Веб-представление будет сохранено как член экземпляра класса. Однако вы должны прикрепить веб-представление в OnCreateView и отсоединить перед OnDestroyView, чтобы предотвратить его уничтожение родительским контейнером.

class MyFragment extends Fragment{  

    public MyFragment(){  setRetainInstance(true); }

    private WebView webView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       View v = ....
       LinearLayout ll = (LinearLayout)v.findViewById(...);
       if (webView == null) {
            webView = new WebView(getActivity().getApplicationContext()); 
       }
       ll.removeAllViews();
       ll.addView(webView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

       return v;
    }

    @Override
    public void onDestroyView() {
        if (getRetainInstance() && webView.getParent() instanceof ViewGroup) {
           ((ViewGroup) webView.getParent()).removeView(webView);
        }
        super.onDestroyView();
    } 
}

PS Кредиты идут в kcoppock ответить

Что касается «SaveState ()», он больше не работает в соответствии с официальной документацией :

Обратите внимание, что этот метод больше не сохраняет данные дисплея для этого WebView. Предыдущее поведение может привести к утечке файлов, если restoreState (Bundle) никогда не вызывался.


Обратите внимание, что, хотя setRetainInstanceи сохраняет фрагмент, представление (и, следовательно, WebView) все еще разрушается.
Фред

1
@Fred Можете ли вы предоставить источник для этого заявления? Я проверил это в небольшом приложении, в котором есть фрагмент с setRetainInstance (true), который отображает страницу YouTube, и если я меняю ориентацию, вид, похоже, сохраняется, так как видео не прерывается. Не похоже, что веб-просмотр разрушается.
Пинкертон

@Rai Это было просто неправильное прочтение, с тех пор я немного отредактировал ответ (все еще нужны некоторые исправления формулировок). Если вас интересует текущее состояние дел - этот метод работает. Однако проблема в том, что Android убивает приложение, когда у него мало памяти. У меня есть важная форма ввода, в которой пользователь должен прочитать сообщение в другом приложении, поэтому мне пришлось использовать службу переднего плана с уведомлением, чтобы предотвратить прерывание процесса. Все же андроид все еще разрушает активность и, следовательно, сохраняемый фрейм. Но экземпляр класса Application сохраняется - поэтому я перехожу из WebView в Application.
Борис Треухов

1
Я также использую MutableContextWrapper в качестве основы WebView, я переключаю контексты на действия при подключении и отключении. Еще одна большая проблема в том, что в Chromium встроены элементы управления масштабированием, сохраняющие ссылку на старую активность, поэтому нет решения для масштабирования с приложением WebView к Application вместо Activity. TL; DR; если ваша форма не так важна, и вы можете смириться с тем фактом, что после переключения приложения ваш процесс может быть остановлен, а веб-просмотр не восстановлен - используйте решение с сохранением фреймов. PS Также я думаю, что сотрудники Google далеки от реальных проблем со всеми своими виджетами-гаджетами ..
Борис Треухов

1
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);    
}

@Override
protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);    
}

Эти методы могут быть переопределены для любого действия, оно просто позволяет вам сохранять и восстанавливать значения при каждом создании / уничтожении действия, когда при изменении ориентации экрана действие уничтожается и воссоздается в фоновом режиме, поэтому вы можете использовать эти методы для временного хранения / восстановления состояний во время изменения.

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

http://developer.android.com/reference/android/app/Activity.html


1

Лучшее решение, которое я нашел, чтобы сделать это без утечки предыдущей Activityссылки и без установки configChanges.., это использовать MutableContextWrapper .

Я реализовал это здесь: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java


Надежно ли это работает без побочных эффектов? Я не нашел много информации об этом методе.
craigrs84

1

Это единственное, что сработало для меня (я даже использовал состояние сохранения экземпляра, onCreateViewно это было не так надежно).

public class WebViewFragment extends Fragment
{
    private enum WebViewStateHolder
    {
        INSTANCE;

        private Bundle bundle;

        public void saveWebViewState(WebView webView)
        {
            bundle = new Bundle();
            webView.saveState(bundle);
        }

        public Bundle getBundle()
        {
            return bundle;
        }
    }

    @Override
    public void onPause()
    {
        WebViewStateHolder.INSTANCE.saveWebViewState(myWebView);
        super.onPause();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false); 
        ButterKnife.inject(this, rootView);
        if(WebViewStateHolder.INSTANCE.getBundle() == null)
        {
            StringBuilder stringBuilder = new StringBuilder();
            BufferedReader br = null;
            try
            {
                br = new BufferedReader(new InputStreamReader(getActivity().getAssets().open("start.html")));

                String line = null;
                while((line = br.readLine()) != null)
                {
                    stringBuilder.append(line);
                }
            }
            catch(IOException e)
            {
                Log.d(getClass().getName(), "Failed reading HTML.", e);
            }
            finally
            {
                if(br != null)
                {
                    try
                    {
                        br.close();
                    }
                    catch(IOException e)
                    {
                        Log.d(getClass().getName(), "Kappa", e);
                    }
                }
            }
            myWebView
                .loadDataWithBaseURL("file:///android_asset/", stringBuilder.toString(), "text/html", "utf-8", null);
        }
        else
        {
            myWebView.restoreState(WebViewStateHolder.INSTANCE.getBundle());
        }
        return rootView;
    }
}

Я сделал держатель Singleton для состояния WebView. Состояние сохраняется до тех пор, пока существует процесс приложения.

РЕДАКТИРОВАТЬ: loadDataWithBaseURLне было необходимости, он работал так же хорошо, просто

    //in onCreate() for Activity, or in onCreateView() for Fragment

    if(WebViewStateHolder.INSTANCE.getBundle() == null) {
        webView.loadUrl("file:///android_asset/html/merged.html");
    } else {
        webView.restoreState(WebViewStateHolder.INSTANCE.getBundle());
    }

Хотя я читаю, это не обязательно хорошо работает с куки.


Использование синглтона проблематично, поскольку предполагается, что у вас есть только один экземпляр, который вам нужно использовать.
Android-разработчик

@ androiddeveloper ах. Ну, если это не так в вашем случае, то это действительно проблема. У меня был только один экземпляр WebView, поэтому этот вопрос мне даже не подошел.
EpicPandaForce

1

попробуй это

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {

    private WebView wv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        wv = (WebView) findViewById(R.id.webView);
        String url = "https://www.google.ps/";

        if (savedInstanceState != null)
            wv.restoreState(savedInstanceState);
        else {
            wv.setWebViewClient(new MyBrowser());
            wv.getSettings().setLoadsImagesAutomatically(true);
            wv.getSettings().setJavaScriptEnabled(true);
            wv.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
            wv.loadUrl(url);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        wv.saveState(outState);
    }

    @Override
    public void onBackPressed() {
        if (wv.canGoBack())
            wv.goBack();
        else
            super.onBackPressed();
    }

    private class MyBrowser extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }

}

0

Эта страница решает мою проблему, но я должен внести небольшие изменения в исходную:

    protected void onSaveInstanceState(Bundle outState) {
       webView.saveState(outState);
       }

Эта часть имеет небольшую проблему для меня это. При втором изменении ориентации приложение завершается нулевым указателем

с помощью этого он работал для меня:

    @Override
protected void onSaveInstanceState(Bundle outState ){
    ((WebView) findViewById(R.id.webview)).saveState(outState);
}

кажется, точно так же. Почему второй работает, а предыдущий - нет?
Android-разработчик

0

Вы должны попробовать это:

  1. Создайте сервис, внутри этого сервиса создайте свой WebView.
  2. Запустите сервис из своей деятельности и привяжите к нему.
  3. В onServiceConnectedметоде получите WebView и вызовите setContentViewметод для визуализации вашего WebView.

Я протестировал его, и он работает, но не с другими WebViews, такими как XWalkView или GeckoView.


Здравствуй! Не могли бы вы объяснить это больше? Спасибо
Жако

1
Хорошо, получите ваш экземпляр webview из вашей Activity и попытайтесь поместить его ссылку на сервис, работающий в фоновом режиме. В следующий раз, когда вы откроете это действие, попробуйте сначала получить сохраненный веб-просмотр и отобразить его.
Рамдане Уалицен

0
@Override
    protected void onSaveInstanceState(Bundle outState )
    {
        super.onSaveInstanceState(outState);
        webView.saveState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {
        super.onRestoreInstanceState(savedInstanceState);
        webView.restoreState(savedInstanceState);
    }

Не могли бы вы добавить несколько строк объяснения к вашему ответу?
Yacc

-1

Мне нравится это решение http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

В соответствии с этим мы повторно используем тот же экземпляр WebView. Это позволяет сохранить историю навигации и положение прокрутки при изменении конфигурации.


Ссылка выше ведет к странице, которую нельзя просмотреть без установки какого-либо «плагина безопасности»; избежать.
Аллан Базинет
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.