Android WebView: अभिविन्यास परिवर्तन से निपटने


147

समस्या रोटेशन के बाद का प्रदर्शन है। WebView को पृष्ठ को फिर से लोड करना है, जो थोड़ा थकाऊ हो सकता है।

हर बार स्रोत से पृष्ठ पुनः लोड किए बिना अभिविन्यास परिवर्तन को संभालने का सबसे अच्छा तरीका क्या है?


3
"स्रोत से पुनः लोड करने" से क्या आपका मतलब है कि यह पृष्ठ को फिर से डाउनलोड कर रहा है, या बस इसे फिर से प्रस्तुत कर रहा है?
जेरेमी लोगन

ब्लैकहेक्स द्वारा संदर्भित समाधान ने मेरी समस्या को हल किया।
इटालो बोर्साट्टो

6
मुझे आश्चर्य है कि मेरे ऐप के बारे में नरक कितना खास है कि इनमें से कोई भी जवाब काम नहीं करता है ...
रॉबिनजे

जवाबों:


91

यदि आप नहीं चाहते कि WebView अभिविन्यास परिवर्तनों पर पुनः लोड हो, तो केवल आपकी गतिविधि वर्ग में onConfigurationChanged ओवरराइड करें:

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

और एंड्रॉइड सेट करें: कॉन्फिगरेशन में कॉन्फिगरेशन विशेषता:

<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
मैंने परीक्षण किया लेकिन पाया कि काम नहीं कर रहा है, नीचे की तरह कॉन्फिगरेशन विशेषता सेट करेगा। Android: configChanges = "कीबोर्डहेड | ओरिएंटेशन"
virsir

18
ऐसा करना वास्तव में हतोत्साहित करता है, जैसा कि पहले भी कई बार उल्लेख किया गया है
मथायस

3
मैथियस: यह वास्तव में सच नहीं है - वेबव्यू के लिए जावदोक देखें।
क्रेटा

इस समाधान के बारे में ध्यान देने योग्य दो बातें: 1) यदि आपके पास एक WebView के साथ एक अमूर्त गतिविधि है, तो configChangesविशेषता उपवर्ग गतिविधि 2 में जुड़ जाती है) यदि आपका ऐप कई परियोजनाओं पर निर्भर करता है, तो configChangesविशेषता एक के प्रकट होने के साथ जुड़ जाती है। निर्भरता पेड़ के ऊपर (जो गतिविधि वर्ग युक्त परियोजना नहीं हो सकती है)।
अमांडा एस

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 (सच); mWebView.setWebViewClient (नया SimpleWebViewClient ()); mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } और {mWebView.restoreState (saveInstanceState); }
ओलेक्सी मालोवैनी

12
SaveState के प्रलेखन से: कृपया ध्यान दें कि यह विधि अब इस WebView के लिए प्रदर्शन डेटा संग्रहीत नहीं करती है। पिछला व्यवहार संभावित रूप से फ़ाइलों को लीक कर सकता है ...
प्रतिभाशाली

5
"कृपया ध्यान दें कि यह विधि अब इस WebView के प्रदर्शन डेटा को संग्रहीत नहीं करती है" - developer.android.com/reference/android/webkit/WebView.html
स्टीवन मार्क फोर्ड

क्या किसी के पास कोई सुझाव है कि अब क्या करना है कि "यह तरीका अब इस WebView के लिए प्रदर्शन डेटा संग्रहीत नहीं करता है" ताकि कोई WebView फ़ॉर्म पुनः लोड होने से रोका जा सके?
लुकास पी।

24

इसका सबसे अच्छा उत्तर एंड्रॉइड प्रलेखन यहाँ पाया जा रहा है मूल रूप से यह वेबव्यू को फिर से लोड होने से रोकेगा:

<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 () मेथड को ओवरराइड करने की आवश्यकता नहीं है। आप सभी को एंड्रॉइड: configChanges = "ओरिएंटेशन | स्क्रीनसेज़" को मैनिफ़ेस्ट। Xml फ़ाइल में जोड़ने की आवश्यकता है।
ओज़नकुरन

5

मैं का उपयोग कर की कोशिश की है onRetainNonConfigurationInstance (लौटने WebView ), तो यह हो रही है के साथ वापस आ getLastNonConfigurationInstance दौरान onCreate और यह फिर से बताए।

बस अभी तक काम करने के लिए प्रतीत नहीं होता है। मैं मदद नहीं कर सकता, लेकिन लगता है कि मैं वास्तव में करीब हूँ! अब तक, मुझे इसके बजाय केवल एक खाली / सफ़ेद पृष्ठभूमि वाला वेबव्यू मिलता है । यहाँ इस उम्मीद में पोस्ट कर रहा हूँ कि कोई इस फिनिश लाइन को पार करने में मदद कर सकता है।

हो सकता है कि मुझे 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 Yay - के स्रोत और एंड्रॉयड "सही काम करता है"!

... जब आप कॉन्फ़िगर परिवर्तनों को देखते हैं, तब इसे छोड़कर नहीं। :(

तो मैं मुश्किलों में हूँ। OnRetainNonConfigurationInstance और ImageView रोटेशन कार्यों का उपयोग करें , लेकिन WebView दृढ़ता का उपयोग नहीं करता है ... या onConfigurationChanged और WebView का उपयोग स्थिर रहता है, लेकिन ImageView अपडेट नहीं करता है। क्या करें?

एक आखिरी नोट: मेरे मामले में, अभिविन्यास मजबूर करना स्वीकार्य समझौता नहीं है। हम वास्तव में सुंदर रूप से रोटेशन का समर्थन करना चाहते हैं। Android ब्राउज़र ऐप कैसे करता है जैसे किंडा! ;)


7
आपको onRetainNonConfigurationInstance से किसी भी दृश्य को वापस नहीं करना चाहिए। एक्टिविटी कॉनटेक्स्ट से विचार जुड़े होते हैं इसलिए यदि आप उस दृश्य को सहेजते हैं जो हर बार उस सामान को ले जाता है जिसमें ओरिएंटेशन चेंज होता है। दृश्य "लीक" है। (अंतिम पैराग्राफ यहां देखें: developer.android.com/resources/articles/… ) onRetainNonConfigurationInstance के लिए सबसे अच्छा अभ्यास डेटा को देखने के लिए सहेजना है, न कि केवल दृश्य।
दक्खन शनाघि

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

अपनी मैनिफ़ेस्ट फ़ाइल में बस निम्नलिखित कोड लाइनें लिखें - और कुछ नहीं। यह सचमुच काम करता है:

<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 है, और कई लोग एक समाधान की तलाश कर रहे हैं जो अभी भी जेलीबीन, केके और लॉलीपॉप फोन पर काम करता है। बहुत संघर्ष करने के बाद मैंने आपको अभिविन्यास बदलने के बाद वेबव्यू बरकरार रखने का एक तरीका मिल गया। मेरी रणनीति मूल रूप से एक अलग वर्ग में एक अलग स्थिर चर में वेब स्टोर को स्टोर करने के लिए है। फिर, यदि रोटेशन होता है, तो मैं गतिविधि से वेबव्यू को अलग कर देता हूं, ओरिएंटेशन समाप्त होने की प्रतीक्षा करता हूं, और वेबव्यू को फिर से गतिविधि पर रीटच करता हूं। उदाहरण के लिए ... पहले इसे अपने मैनिफ़ेस्ट पर डालें (कीबोर्डहेड और कीबोर्ड वैकल्पिक हैं):

<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 भंडारण का उपयोग करने के बजाय गतिविधि पहली बार शुरू की गई है, तो इसे सत्यापित करने का एक छोटा तरीका है। यह दृष्टिकोण आपको webview बरकरार (afaik), इसके टेक्स्टबॉक्स, लेबल, UI, जावास्क्रिप्ट चर और नेविगेशन राज्यों को संरक्षित करता है जो कि url द्वारा परिलक्षित नहीं होते हैं।


1
जब आप मैन्युअल रूप से कॉन्फ़िगरेशन परिवर्तन को हैंडल करते हैं, तब भी WebView को अलग करने और पुन: उपयोग करने से परेशान क्यों होता है?
फ्रेड

@ क्योंकि मैं वेबव्यू और उसकी सामग्री की सटीक स्थिति को बरकरार रखना चाहता हूं, जिसमें कुकीज़, और एचटीएमएल 5 या जेएस के साथ लागू किए गए बटन और चेकबॉक्स की स्थिति को वेबव्यू द्वारा लोड किया गया है। मेरे द्वारा किया जाने वाला एकमात्र समायोजन आकार परिवर्तन है।
जोश

फ्रेड का मतलब है कि आपको वेबस्टॉक को एक स्थिर वर्ग के माध्यम से अलग करने / रिआटैच करने की आवश्यकता नहीं है क्योंकि आपने घोषणा को विन्यास में घोषित किया है। इस तरह, किसी भी मामले में रोटेशन के दौरान आपके विचार और गतिविधि नष्ट नहीं होती हैं।
यूजीन कार्तोयेव

2

केवल एक चीज जो आपको करनी चाहिए वह है इस कोड को अपनी मैनिफ़ेस्ट फ़ाइल में जोड़ना:

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

2

अद्यतन: वर्तमान रणनीति यह है कि जब अलग हो जाए और फिर से शुरू जोश करता है तो फिर से शुरू करने के बजाय वेबव्यू इंस्टेंस को अनुप्रयोग वर्ग में ले जाएं। एप्लिकेशन को बंद होने से रोकने के लिए, आपको अग्रभूमि सेवा का उपयोग करना चाहिए, यदि आप एप्लिकेशन के बीच उपयोगकर्ता स्विच करते समय स्थिति को बनाए रखना चाहते हैं।

यदि आप टुकड़े का उपयोग कर रहे हैं, तो आप 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 के लिए प्रदर्शन डेटा संग्रहीत नहीं करती है। यदि रिस्टोरस्ट (बंडल) को कभी नहीं बुलाया गया तो पिछला व्यवहार संभावित रूप से फ़ाइलों को लीक कर सकता है।


ध्यान दें कि जब setRetainInstanceतक फ्रैगमेंट दृश्य को बनाए रखता है (और इसलिए WebView) अभी भी नष्ट हो जाता है।
फ्रेड

1
@ क्या आप उस कथन के लिए स्रोत प्रदान कर सकते हैं? मैंने इसका परीक्षण एक छोटे से ऐप में किया है, जिसमें setRetainInstance (सत्य) के साथ एक टुकड़ा है, जो एक यूट्यूब पेज प्रदर्शित करता है और यदि मैं अभिविन्यास को बदल देता हूं, तो दृश्य को बनाए रखा जाता है क्योंकि वीडियो बाधित नहीं होता है। ऐसा नहीं लगता कि वेबव्यू नष्ट हो रहा है।
पिंकर्टन

@ राई यह सिर्फ एक गलत प्रचार था, मैंने तब से थोड़ा सा जवाब संपादित किया है (यह अभी भी कुछ शब्दों को ठीक करने की आवश्यकता है)। यदि आप मामलों की वर्तमान स्थिति में रुचि रखते हैं - यह विधि काम करती है। हालाँकि समस्या यह है कि Android स्मृति पर कम होने पर एप्लिकेशन को मार देता है। मेरे पास एक महत्वपूर्ण इनपुट फॉर्म है जहां उपयोगकर्ता को किसी अन्य एप्लिकेशन में एक संदेश पढ़ना है, इसलिए मुझे प्रक्रिया के लिए अग्रभूमि सेवा का उपयोग करना पड़ा ताकि प्रक्रिया को मार डाला जा सके। फिर भी एंड्रॉइड अभी भी गतिविधि को नष्ट कर देता है और इसलिए बनाए रखा फ्रेम। लेकिन अनुप्रयोग वर्ग का उदाहरण संरक्षित है - इसलिए मैं WebView को अब अनुप्रयोग पर ले जाता हूं।
बोरिस ट्रेखोव

1
मैं भी WebView के आधार के रूप में MutableContextWrapper का उपयोग करता हूं, मैं संदर्भों को संलग्न और अलग करने वाली गतिविधियों पर स्विच करता हूं। एक अन्य बड़ी समस्या जो जूम नियंत्रण में क्रोमियम का निर्माण करती है, वह पुरानी गतिविधि के संदर्भ को बचाती है, इसलिए गतिविधि के बजाय वेबव्यू के साथ समाधान में कोई ज़ूम नहीं जुड़ा होता है। टी एल; डॉ; यदि आपका फॉर्म उतना महत्वपूर्ण नहीं है, और आप इस तथ्य के साथ रह सकते हैं कि ऐप स्विच करने के बाद आपकी प्रक्रिया को मार दिया जा सकता है और वेबव्यू को बनाए रखा फ्रेम समाधान के साथ बहाल नहीं किया जाता है। 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.. एक MutableContextWebpper का उपयोग करना है

मैंने इसे यहाँ लागू किया है: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925942cfb/WebWrapper/src/com/example/webwrapper/BrowserA


क्या यह कार्य बिना साइड-इफ़ेक्ट के मज़बूती से होता है? मुझे इस विधि के बारे में अधिक जानकारी नहीं मिली है।
क्रेगर्स84

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

मैंने 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());
    }

हालाँकि मैंने पढ़ा है कि यह जरूरी नहीं है कि कुकीज़ के साथ अच्छा काम करें।


सिंगलटन का उपयोग करना समस्याग्रस्त है, क्योंकि यह मानता है कि आपके पास केवल एक उदाहरण है जिसे आपको उपयोग करने की आवश्यकता है।
एंड्रॉइड डेवलपर

@androiddeveloper आह। ठीक है, अगर यह आपके मामले में सच नहीं है, तो वास्तव में यह एक समस्या है। मेरे पास केवल एक WebView उदाहरण था, इसलिए यह प्रश्न मेरे लिए भी नहीं आया।
एपिकपांडफर्सेस

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

इस हिस्से को मेरे लिए थोड़ी समस्या है। दूसरे ओरिएंटेशन पर null पॉइंटर के साथ समाप्त एप्लिकेशन को बदल दें

यह प्रयोग मेरे लिए काम किया:

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

बिल्कुल वैसा ही लगता है। दूसरा काम क्यों करेगा जबकि पहले वाला नहीं था?
एंड्रॉइड डेवलपर

0

आपको यह कोशिश करनी चाहिए:

  1. उस सेवा के अंदर एक सेवा बनाएँ, अपना वेबव्यू बनाएँ।
  2. अपनी गतिविधि से सेवा शुरू करें और इसे बांधें।
  3. में onServiceConnectedविधि, WebView हो और फोन setContentViewअपने WebView रेंडर करने के लिए विधि।

मैंने इसका परीक्षण किया और यह काम करता है लेकिन अन्य वेबव्यू जैसे कि XWalkView या GeckoView के साथ नहीं।


नमस्ते! आप इसे और अधिक समझा सकते हैं? धन्यवाद
जैको

1
ठीक है, अपने वेबव्यू उदाहरण को आप गतिविधि के रूप में प्राप्त करें और पृष्ठभूमि में चल रही सेवा के लिए इसकी वापसी करने का प्रयास करें। अगली बार जब आप उस गतिविधि को खोलते हैं, तो पहले सहेजे गए वेबव्यू को प्राप्त करने का प्रयास करें और उसे रेंडर करें।
रामादेन ओउलित्सन

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

क्या आप अपने उत्तर में स्पष्टीकरण की कुछ पंक्तियाँ जोड़ सकते हैं?
याकूब

-1

मुझे यह समाधान पसंद है http://www.devahead.com/blog/2012/01/presinating-the-state-of-an-android-webview-on-screen-orientation-change/

इसके अनुसार हम WebView के उसी उदाहरण का पुन: उपयोग करते हैं। यह कॉन्फ़िगरेशन इतिहास को बचाने और कॉन्फ़िगरेशन परिवर्तन पर स्क्रॉल करने की अनुमति देता है।


लिंक ऊपर एक पृष्ठ पर जाता है जिसे कुछ 'सुरक्षा प्लगइन' स्थापित किए बिना नहीं देखा जा सकता है; से बचें।
एलन बाजिनेट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.