Android WebView: xử lý thay đổi hướng


147

Vấn đề là hiệu suất sau khi luân chuyển. WebView phải tải lại trang, có thể hơi tẻ nhạt.

Cách tốt nhất để xử lý thay đổi định hướng mà không cần tải lại trang từ nguồn mỗi lần?


3
Bằng cách "tải lại từ nguồn", bạn có nghĩa là nó đang tải lại trang hoặc chỉ hiển thị lại?
Jeremy Logan

Giải pháp được tham chiếu bởi Blackhex đã giải quyết vấn đề của tôi.
Italo Borssatto

6
Tôi tự hỏi ứng dụng của tôi có gì đặc biệt đến nỗi không có câu trả lời nào trong số này hoạt động ...
RobinJ

Câu trả lời:


91

Nếu bạn không muốn WebView tải lại các thay đổi định hướng, chỉ cần ghi đè onConfigurationChanged trong lớp Activity của bạn:

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

Và đặt thuộc tính android: configChanges trong tệp kê khai:

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

để biết thêm thông tin, hãy xem:
http://developer.android.com/guide/topics/resource/r nb-changes.html#HandlingTheChange

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


4
Tôi đã thử nghiệm nhưng thấy không hoạt động, đặt thuộc tính configChanges như bên dưới sẽ hoạt động. android: configChanges = "keyboardHidden |
direction

18
làm điều đó trong thực tế không được khuyến khích, như đã được đề cập nhiều lần trước đây
Matthias

3
Matthias: Điều này không thực sự đúng - xem Javadoc cho WebView.
krtek

Hai điều cần lưu ý về giải pháp này: 1) Nếu bạn có Hoạt động trừu tượng với WebView, configChangesthuộc tính sẽ được thêm vào lớp con Hoạt động 2) Nếu ứng dụng của bạn phụ thuộc vào nhiều dự án, configChangesthuộc tính sẽ được thêm vào tệp kê khai của một tại đầu cây phụ thuộc (có thể không phải là dự án chứa lớp Activity).
Amanda S

4
Ghi onConfigurationChangedđè phương pháp như vậy là vô ích.
Miha_x64

69

Chỉnh sửa: Phương pháp này không còn hoạt động như đã nêu trong các tài liệu


Câu trả lời gốc:

Điều này có thể được xử lý bằng cách ghi đè onSaveInstanceState(Bundle outState)trong hoạt động của bạn và gọi saveStatetừ webview:

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

Sau đó phục hồi điều này trong onCreate của bạn sau khi webview đã được bơm lại tất nhiên:

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

26
Điều này không hoạt động trên thay đổi hướng - màn hình trống được hiển thị. Các phương thức saveState \ restoreState được gọi nhưng không giúp được gì.
Oleksii Malovanyi

1
Đây là đoạn mã onCreate: setContentView (R.layout.webview); mWebView = (WebView) findViewById (R.id.webview); if (yetInstanceState == null) {mWebView.getSinstall (). setJavaScriptEnabled (true); mWebView.setWebViewClient (SimpleWebViewClient ()); mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } other {mWebView.restoreState (yetInstanceState); }
Oleksii Malovanyi

12
Từ tài liệu của saveState: Xin lưu ý rằng phương pháp này không còn lưu trữ dữ liệu hiển thị cho WebView này. Hành vi trước đó có thể có khả năng rò rỉ các tệp ...
brillenheini

5
"Xin lưu ý rằng phương pháp này không còn lưu trữ dữ liệu hiển thị cho WebView này" - developer.android.com/reference/android/webkit/WebView.html
Steven Mark Ford

Có ai có bất cứ đề nghị nào về việc phải làm bây giờ rằng "phương pháp này không còn lưu trữ dữ liệu hiển thị cho WebView này" để ngăn tải lại biểu mẫu WebView không?
Lucas P.

24

Câu trả lời tốt nhất cho vấn đề này là theo tài liệu Android được tìm thấy ở đây Về cơ bản, điều này sẽ ngăn Webview tải lại:

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

Tùy chọn , bạn có thể khắc phục sự bất thường (nếu có) bằng cách ghi đè onConfigurationChangedtrong hoạt động:

@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
Bạn không cần phương thức onConfigurationChanged () Tôi khá chắc chắn, chỉ là thuộc tính bổ sung trong Bản kê khai. Tôi đoán là hỗ trợ riêng cho việc này được cung cấp bởi WebView và đây là lý do tại sao câu trả lời này là câu trả lời hay nhất (vì điều này không hiệu quả khi câu hỏi ban đầu được hỏi)
Booger

1
Tôi chấp nhận @Booger bạn không cần ghi đè phương thức onConfigurationChanged (). Tất cả những gì bạn cần là thêm android: configChanges = "direction | screenSize" trong tệp manifest.xml.
ozanurkan

5

Tôi đã thử sử dụng onRetainNonConfigurationInstance (trả lại WebView ), sau đó lấy lại bằng getLastNonConfigurationInstance trong khi onCreate và gán lại nó.

Có vẻ như chưa hoạt động. Tôi không thể giúp nhưng nghĩ rằng tôi thực sự gần gũi! Cho đến nay, tôi chỉ nhận được một WebView trống / nền trắng . Đăng ở đây với hy vọng ai đó có thể giúp đẩy cái này qua vạch đích.

Có lẽ tôi không nên vượt qua WebView . Có lẽ một đối tượng từ bên trong WebView ?

Phương pháp khác tôi đã thử - không phải sở thích của tôi - là đặt phương thức này trong hoạt động:

 android:configChanges="keyboardHidden|orientation"

... và sau đó không làm gì nhiều ở đây:

@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.
}

THAT hoạt động, nhưng nó có thể không được coi là một thực tiễn tốt nhất .

Trong khi đó, tôi cũng có một ImageView duy nhất mà tôi muốn cập nhật tự động tùy theo vòng quay. Điều này hóa ra rất dễ dàng. Trong resthư mục của tôi , tôi có drawable-landdrawable-portgiữ các biến thể ngang / R.drawable.myimagenamedọc , sau đó tôi sử dụng cho nguồn của ImageView và Android "thực hiện đúng" - yay!

... ngoại trừ khi bạn xem các thay đổi cấu hình, thì không. :

Vì vậy, tôi đang bất hòa. Sử dụng onRetainNonConfigurationInstance và xoay ImageView hoạt động, nhưng tính bền vững của WebView không ... hoặc sử dụng onConfigurationChangedWebView vẫn ổn định, nhưng ImageView không cập nhật. Phải làm sao

Một lưu ý cuối cùng: Trong trường hợp của tôi, việc ép buộc định hướng không phải là một sự thỏa hiệp chấp nhận được. Chúng tôi thực sự muốn duyên dáng hỗ trợ luân chuyển. Giống như cách ứng dụng Trình duyệt Android làm! ;)


7
Bạn không nên trả lại bất kỳ Lượt xem nào từ onRetainNonConfigurationInstance. Các chế độ xem được đính kèm với Bối cảnh hoạt động, vì vậy nếu bạn lưu chế độ xem, bạn sẽ mang theo tất cả hành lý đó mỗi khi có sự thay đổi định hướng. Quan điểm là "rò rỉ". (Xem đoạn cuối tại đây: developer.android.com/resource/articles/ trên ) Cách thực hành tốt nhất cho onRetainNonConfigurationInstance là lưu dữ liệu mà chế độ xem cần chứ không phải chính chế độ xem.
Declan Shanaghy

3

Một thỏa hiệp là để tránh xoay vòng. Thêm phần này để sửa hoạt động chỉ cho hướng Chân dung.

android:screenOrientation="portrait"

Điều này thực sự hoạt động trong nhiều trường hợp và là giải pháp tôi đã quyết định thực hiện :-)
Abdo

1
hehe, đây là một sự thay đổi yêu cầu
Max Ch

3

Cách tốt nhất để xử lý các thay đổi định hướng và Ngăn chặn tải lại WebView trên Xoay.

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

Với ý nghĩ đó, để ngăn chặn onCreate () được gọi mỗi khi bạn thay đổi hướng, bạn sẽ phải thêm android:configChanges="orientation|screenSize" to the AndroidManifest.

hoặc chỉ ..

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

3

Chỉ cần viết các dòng mã sau vào tệp Manifest của bạn - không có gì khác. Nó thật sự có hiệu quả:

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

3

Tôi đánh giá cao việc này hơi muộn, tuy nhiên đây là câu trả lời mà tôi đã sử dụng khi phát triển giải pháp của mình:

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

Bạn có thể thử sử dụng onSaveInstanceState()onRestoreInstanceState()trên Hoạt động của mình để gọi saveState(...)restoreState(...)trên phiên bản WebView của bạn.


2

Đó là năm 2015, và nhiều người đang tìm kiếm một giải pháp vẫn còn hiệu quả trên điện thoại Jellybean, KK và Lollipop. Sau nhiều lần vật lộn, tôi đã tìm ra cách giữ gìn webview nguyên vẹn sau khi bạn thay đổi định hướng. Chiến lược của tôi về cơ bản là lưu trữ webview trong một biến tĩnh riêng biệt trong một lớp khác. Sau đó, nếu xoay vòng xảy ra, tôi bỏ webview khỏi hoạt động, đợi cho hướng kết thúc và gắn lại webview trở lại hoạt động. Ví dụ ... trước tiên hãy đặt cái này lên MANIFEST của bạn (bàn phím và bàn phím là tùy chọn):

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

Trong một nhóm ứng dụng SEPARATE, đặt:

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

Trong HOẠT ĐỘNG đặt:

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

Cuối cùng, XML đơn giản:

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

Có một số điều có thể được cải thiện trong giải pháp của tôi, nhưng tôi đã dành nhiều thời gian, ví dụ: một cách ngắn hơn để xác thực nếu Hoạt động được khởi chạy lần đầu tiên thay vì sử dụng lưu trữ SharedPreferences. Cách tiếp cận này bảo vệ nguyên vẹn webview của bạn (afaik), hộp văn bản, nhãn, giao diện người dùng, biến javascript và trạng thái điều hướng không được phản ánh bởi url.


1
Tại sao thậm chí còn bận tâm tách rời và gắn lại WebView khi nó không bao giờ bị phá hủy ngay từ đầu vì bạn xử lý các thay đổi cấu hình theo cách thủ công?
Fred

@Fred Bởi vì tôi muốn giữ nguyên trạng thái chính xác của Webview và nội dung của nó, bao gồm cookie và trạng thái của các nút và hộp kiểm được triển khai với HTML5 hoặc JS bên trong trang web được tải bởi webview. Điều chỉnh duy nhất tôi làm là thay đổi kích thước.
Josh

Fred có nghĩa là bạn không cần phải tách / gắn lại webview thông qua một lớp tĩnh khi bạn khai báo configChanges trong tệp kê khai. Bằng cách này, quan điểm và hoạt động của bạn sẽ không bị phá hủy trong quá trình quay trong mọi trường hợp.
Eugene Kartoyev

2

Điều duy nhất bạn nên làm là thêm mã này vào tệp kê khai của mình:

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

2

Cập nhật: chiến lược hiện tại là chuyển phiên bản WebView sang lớp Ứng dụng thay vì giữ lại đoạn khi nó tách ra và gắn lại vào sơ yếu lý lịch như Josh làm. Để ngăn Ứng dụng đóng, bạn nên sử dụng dịch vụ nền trước, nếu bạn muốn giữ trạng thái khi người dùng chuyển đổi giữa các ứng dụng.

Nếu bạn đang sử dụng các đoạn, bạn có thể sử dụng phiên bản giữ lại của WebView. Chế độ xem web sẽ được giữ lại làm thành viên thể hiện của lớp. Tuy nhiên, bạn nên đính kèm chế độ xem web trong OnCreateView và tách ra trước OnDestroyView để ngăn chặn nó khỏi bị phá hủy với vùng chứa chính.

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

Tín dụng PS đi đến câu trả lời kcoppock

Đối với 'SaveState ()', nó không còn hoạt động theo tài liệu chính thức :

Xin lưu ý rằng phương pháp này không còn lưu trữ dữ liệu hiển thị cho WebView này. Hành vi trước đó có khả năng rò rỉ các tệp nếu restoreState (Gói) không bao giờ được gọi.


Lưu ý rằng mặc dù setRetainInstancevẫn giữ Fragment, nhưng khung nhìn (và do đó WebView) vẫn bị phá hủy.
Fred

1
@Fred Bạn có thể cung cấp một nguồn cho tuyên bố đó? Tôi đã thử nghiệm điều này trong một ứng dụng nhỏ có đoạn với setRetainInstance (true) hiển thị trang youtube và nếu tôi thay đổi hướng, chế độ xem dường như được giữ lại vì video không bị gián đoạn. Không có vẻ như webview đang bị phá hủy.
Pinkerton

@Rai Đó chỉ là một cách đọc sai, tôi đã chỉnh sửa một chút câu trả lời kể từ đó (nó vẫn cần một số sửa chữa từ ngữ). Nếu bạn quan tâm đến tình trạng hiện tại - phương pháp này hoạt động. Tuy nhiên, vấn đề là android giết ứng dụng khi bộ nhớ còn thấp. Tôi có một hình thức nhập quan trọng trong đó người dùng phải đọc một tin nhắn trong một ứng dụng khác, vì vậy tôi đã phải sử dụng dịch vụ nền trước với thông báo để ngăn quá trình bị giết. Tuy nhiên, Android vẫn phá hủy hoạt động và do đó khung được giữ lại. Nhưng thể hiện của lớp Ứng dụng được giữ nguyên - vì vậy tôi chuyển WebView sang Ứng dụng ngay bây giờ.
Boris Treukhov

1
Tôi cũng sử dụng MutableContextWrapper làm cơ sở của WebView, tôi chuyển ngữ cảnh sang các hoạt động trên đính kèm và tách ra. Một vấn đề lớn khác mà Chromium xây dựng trong điều khiển thu phóng lưu tham chiếu đến hoạt động cũ, do đó, không có giải pháp thu phóng nào với WebView được đính kèm với Ứng dụng thay vì Hoạt động. TL; DR; nếu biểu mẫu của bạn không quan trọng và bạn có thể sống với thực tế là sau khi chuyển đổi ứng dụng, quy trình của bạn có thể bị hủy và webview không được khôi phục đi với giải pháp khung giữ lại. PS tôi cũng nghĩ rằng các nhân viên của Google ở ​​rất xa các vấn đề thực tế trong cuộc sống với tất cả các vật dụng-tiện ích của họ ..
Boris Treukhov

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

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

Các phương thức này có thể được ghi đè trên bất kỳ hoạt động nào, về cơ bản nó chỉ cho phép bạn lưu và khôi phục các giá trị mỗi khi một hoạt động được tạo / hủy, khi hướng màn hình thay đổi, hoạt động bị hủy và được tạo lại trong nền, do đó bạn có thể sử dụng các phương thức này để lưu trữ tạm thời / khôi phục trạng thái trong quá trình thay đổi.

Bạn nên có cái nhìn sâu hơn về hai phương pháp sau và xem liệu nó có phù hợp với giải pháp của bạn không.

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


1

Giải pháp tốt nhất tôi đã tìm thấy để làm điều này mà không làm rò rỉ Activitytham chiếu trước đó và không cần thiết lập configChanges.. là sử dụng MutableContextWrapper .

Tôi đã thực hiện điều này tại đây: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/web


công việc này đáng tin cậy mà không có tác dụng phụ? Tôi chưa tìm thấy nhiều thông tin về phương pháp này.
craigrs84

1

Đây là điều duy nhất phù hợp với tôi (tôi thậm chí đã sử dụng trạng thái lưu trong trường hợp onCreateViewnhưng nó không đáng tin cậy).

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

Tôi đã tạo một chủ sở hữu Singleton cho trạng thái của WebView. Nhà nước được bảo tồn miễn là quá trình của ứng dụng tồn tại.

EDIT: loadDataWithBaseURLKhông cần thiết, nó cũng hoạt động tốt với chỉ

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

Mặc dù tôi đọc cái này không nhất thiết phải hoạt động tốt với cookie.


Sử dụng singleton là có vấn đề, vì nó giả sử bạn chỉ có một trường hợp mà bạn cần sử dụng.
nhà phát triển Android

@androiddeveloper ah. Chà, nếu điều đó không đúng trong trường hợp của bạn, thì đó thực sự là một vấn đề. Tôi chỉ có một phiên bản WebView, vì vậy câu hỏi này thậm chí không được đưa ra cho tôi.
EpicPandaForce 1/03/2015

1

thử cái này

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

Trang này giải quyết vấn đề của tôi nhưng tôi phải thay đổi một chút trong lần đầu tiên:

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

Phần này có một vấn đề nhỏ đối với tôi này. Trên hướng thứ hai thay đổi, ứng dụng kết thúc bằng con trỏ null

sử dụng cái này nó làm việc cho tôi:

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

dường như giống hệt nhau Tại sao cái thứ hai sẽ hoạt động trong khi cái trước sẽ không?
nhà phát triển Android

0

Bạn nên thử điều này:

  1. Tạo một dịch vụ, bên trong dịch vụ đó, tạo WebView của bạn.
  2. Bắt đầu dịch vụ từ hoạt động của bạn và liên kết với nó.
  3. Trong onServiceConnectedphương thức, lấy WebView và gọi setContentViewphương thức để hiển thị WebView của bạn.

Tôi đã thử nghiệm nó và nó hoạt động nhưng không hoạt động với các WebView khác như XWalkView hoặc GeckoView.


Chào! Bạn có thể giải thích nó nhiều hơn? Cảm ơn bạn
Jaco

1
Chà, lấy ví dụ webview của bạn từ mẫu Hoạt động của bạn và cố gắng đưa sự kết hợp của nó vào một dịch vụ đang chạy trong nền. Lần tới khi bạn mở hoạt động đó, hãy thử lấy webview đã lưu trước và hiển thị nó.
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);
    }

Bạn có thể thêm một số dòng giải thích cho câu trả lời của bạn?
yacc

-1

Tôi thích giải pháp này http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

Theo nó, chúng tôi sử dụng lại ví dụ tương tự của WebView. Nó cho phép lưu lịch sử điều hướng và vị trí cuộn khi thay đổi cấu hình.


Liên kết ở trên dẫn đến một trang không thể xem được mà không cài đặt một số 'plugin bảo mật'; tránh.
Allan Bazinet
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.