Android WebView: обробка змін орієнтації


147

Проблема полягає в продуктивності після обертання. WebView повинен перезавантажити сторінку, що може бути трохи нудно.

Який найкращий спосіб керувати зміною орієнтації, не оновлюючи сторінку з джерела кожного разу?


3
Під "перезавантаженням з джерела" ви маєте на увазі, що це знову завантаження сторінки або просто повторне надання?
Джеремі Логан

Рішення, на яке посилався Blackhex, вирішило мою проблему.
Italo Borssatto

6
Цікаво, що в моєму додатку настільки особливе, що жодна з цих відповідей не працює ...
RobinJ

Відповіді:


91

Якщо ви не хочете, щоб WebView перезавантажував зміни орієнтації, просто замініть onConfigurationChanged у вашому класі активності:

@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) Якщо у вас є абстрактна активність із WebView, configChangesатрибут додається до підкласу Активність 2) Якщо ваш додаток залежить від декількох проектів, configChangesатрибут додається до маніфесту цього в вгорі дерева залежностей (що може бути не проектом, що містить клас діяльності).
Amanda S

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 \ RestoState викликаються, але це не допомагає.
Олексій Мальований

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 (збереженийInstanceState); }
Олексій Мальований

12
З документації saveState: Зверніть увагу, що цей спосіб більше не зберігає відображувані дані для цього WebView. Попередня поведінка може потенційно витікати з файлів ...
brillenheini

5
"Зверніть увагу, що цей метод більше не зберігає дані відображення для цього веб-перегляду" - developer.android.com/reference/android/webkit/WebView.html
Стівен Марк Форд

Хтось має пропозиції щодо того, що робити зараз, щоб "цей метод більше не зберігає дані відображення для цього WebView", щоб запобігти перезавантаженню форми WebView?
Лукас П.

24

Найкраща відповідь на це - наступна документація на Android, яку ви знайдете тут. В основному це не дозволить переглядати веб-перегляд:

<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 (). Я впевнений, просто додатковий атрибут у Manifest. Я здогадуюсь, що підтримка цього веб-сайту була надана WebView, і саме тому ця відповідь зараз найкраща (тому що це не спрацювало, коли запитання спочатку було задано)
Booger

1
Я схвалюю @Booger, вам не потрібно переосмислювати метод onConfigurationChanged (). Все, що вам потрібно, це додати android: configChanges = "орієнтація | 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 - це збереження даних, необхідних перегляду, а не самого перегляду.
Declan Shanaghy

3

Один компроміс - уникати обертання. Додайте це, щоб виправити активність лише для орієнтації на портрет.

android:screenOrientation="portrait"

Це насправді спрацьовує у багатьох випадках і це рішення, яке я вирішив застосувати :-)
Абдо

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

Просто запишіть у свій файл Manifest наступні рядки коду - нічого іншого. Це дійсно працює:

<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. Після великої боротьби я знайшов спосіб зберегти веб-перегляд недоторканим після зміни орієнтації. Моя стратегія полягає в основному для зберігання веб-перегляду в окремій статичній змінній в іншому класі. Потім, якщо відбувається обертання, я відтягую веб-перегляд від активності, чекаю, поки орієнтація закінчиться, і повторно додаю веб-перегляд до активності. Наприклад ... спочатку покладіть це на свій MANIFEST (клавіатураHidden та клавіатура не є обов'язковою):

<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>

Є кілька речей, які можна було б покращити в моєму рішенні, але я вже витратив багато часу, наприклад: коротший спосіб перевірити, якщо Діяльність була запущена вперше, замість того, щоб використовувати сховище 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 до класу Application замість збереженого фрагмента, коли він від'єднується та повторно додається до резюме, як це робить Джош. Щоб запобігти закриттю програми, вам слід скористатися послугою переднього плану, якщо ви бажаєте зберегти стан, коли користувач перемикається між програмами.

Якщо ви використовуєте фрагменти, ви можете використовувати збережений екземпляр 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. Попередня поведінка може потенційно просочувати файли, якщо RestoState (Bundle) ніколи не викликався.


Зауважте, що поки setRetainInstanceзберігає фрагмент, подання (а отже, і WebView) все ще руйнується.
Фред

1
@Fred Чи можете ви надати джерело для цього твердження? Я перевірив це в невеликому додатку, у якому є фрагмент із setRetainInstance (true), який відображає сторінку youtube, і якщо я зміню орієнтацію, перегляд, схоже, буде збережено, оскільки відео не переривається. Не здається, що веб-перегляд руйнується.
Пінкертон

@Rai Це просто неправильне прочитання, я відтоді трохи відредагував відповідь (вона все ще потребує деяких виправлень формулювань). Якщо вас цікавить поточний стан справ - цей метод працює. Однак проблема полягає в тому, що андроїд вбиває додаток, коли мало пам'яті. У мене є важлива форма введення, де користувач повинен прочитати повідомлення в іншій програмі, тому мені довелося використовувати службу переднього плану з повідомленням, щоб запобігти вбиттю процесу. І все ж андроїд все ще руйнує активність, а отже, і збережений кадр. Але екземпляр класу Application зберігається - тому я переходжу WebView в додаток зараз.
Борис Треухов

1
Я також використовую MutableContextWrapper в якості бази WebView, я перемикаю контексти на дії з прикріплення та від'єднання. Ще одна велика проблема, пов’язана з тим, що Chromium створює засоби регулювання масштабування, економить посилання на стару активність, тому жодне рішення масштабування з WebView не додається до програми, а не активності. 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. Держава зберігається до тих пір, поки існує процес подання заявки.

EDIT: Це 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());
    }

Хоча я читаю, це не обов'язково добре працює з файлами cookie.


Використовувати синглтон є проблематичним, оскільки передбачає, що у вас є лише один екземпляр, який потрібно використовувати.
андроїд розробник

@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);
}

здається, точно так само. Чому другий працюватиме, коли попередній не буде?
андроїд розробник

0

Спробуйте це:

  1. Створіть службу всередині цієї служби, створіть свій веб-перегляд.
  2. Почніть послугу зі своєї діяльності та зв’яжіться з нею.
  3. У цьому onServiceConnectedметоді знайдіть WebView і зателефонуйте до setContentViewметоду для надання веб-перегляду.

Я перевірив це, і він працює, але не з іншими WebView, такими як XWalkView або GeckoView.


Привіт! Чи можете ви пояснити це більше? Дякую
Яко

1
Добре, заздалегідь отримайте форму екземпляра веб-перегляду "Активність" і спробуйте висловити свою послугу службі, яка працює у фоновому режимі. Наступного разу, коли ви відкриєте цю активність, спробуйте спочатку отримати збережений веб-перегляд та зробити його.
Ramdane Oualitsen

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.