Android WebView: menangani perubahan orientasi

147

Masalahnya adalah kinerja setelah rotasi. WebView harus memuat ulang halaman, yang bisa sedikit membosankan.

Apa cara terbaik menangani perubahan orientasi tanpa memuat ulang halaman dari sumber setiap kali?

glennanthonyb
sumber
3
Dengan "memuat ulang dari sumber" maksud Anda mengunduh laman lagi, atau hanya merender ulang?
Jeremy Logan
Solusi yang dirujuk oleh Blackhex memecahkan masalah saya.
Italo Borssatto
6
Saya ingin tahu apa yang istimewa dari aplikasi saya sehingga tidak ada jawaban yang berfungsi ...
RobinJ

Jawaban:

91

Jika Anda tidak ingin WebView memuat ulang pada perubahan orientasi cukup timpa onConfigurationChanged di kelas Aktivitas Anda:

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

Dan atur atribut android: configChanges di manifes:

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

untuk info lebih lanjut, lihat:
http://developer.android.com/guide/topics/resources/runtime-changes.html#MenanganiTheChange

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

Totach
sumber
4
Saya diuji tetapi ternyata tidak berfungsi, atur atribut configChanges seperti di bawah ini akan berfungsi. android: configChanges = "keyboardHidden | orientasi"
virsir
18
melakukan hal itu sebenarnya tidak dianjurkan, seperti yang telah disebutkan berkali-kali sebelumnya
Matthias
3
Matthias: Ini tidak sepenuhnya benar - lihat Javadoc untuk WebView.
krtek
Dua hal yang perlu diperhatikan tentang solusi ini: 1) Jika Anda memiliki Aktivitas abstrak dengan WebView, configChangesatribut ditambahkan ke subclass Activity 2) Jika aplikasi Anda bergantung pada beberapa proyek, configChangesatribut akan ditambahkan ke manifes yang ada di di atas pohon dependensi (yang mungkin bukan proyek yang mengandung kelas Activity).
Amanda S
4
Seperti onConfigurationChangedmetode override tidak berguna.
Miha_x64
69

Sunting: Metode ini tidak lagi berfungsi sebagaimana dinyatakan dalam dokumen


Jawaban asli:

Ini dapat ditangani dengan menulis ulang onSaveInstanceState(Bundle outState)dalam aktivitas Anda dan menelepon saveStatedari tampilan web:

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

Kemudian pulihkan ini di onCreate Anda setelah tampilan web dipompa kembali tentu saja:

public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.blah);
   if (savedInstanceState != null)
      ((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
KWright
sumber
26
Ini tidak berfungsi pada perubahan orientasi - layar kosong ditampilkan. Metode saveState \ restoreState dipanggil tetapi tidak membantu.
Oleksii Malovanyi
1
Berikut ini cuplikan kode onCreate: setContentView (R.layout.webview); mWebView = (WebView) findViewById (R.id.webview); if (SavedInstanceState == null) {mWebView.getSettings (). setJavaScriptEnabled (true); mWebView.setWebViewClient (SimpleWebViewClient ()) baru; mWebView.loadUrl (Consts.URL_AUTHORIZATION_OAUTH); } else {mWebView.restoreState (disimpanInstanceState); }
Oleksii Malovanyi
12
Dari dokumentasi saveState: Harap dicatat bahwa metode ini tidak lagi menyimpan data tampilan untuk WebView ini. Perilaku sebelumnya berpotensi bocor file ...
brillenheini
5
"Harap perhatikan bahwa metode ini tidak lagi menyimpan data tampilan untuk WebView ini" - developer.android.com/reference/android/webkit/WebView.html
Steven Mark Ford
Adakah yang punya saran tentang apa yang harus dilakukan sekarang bahwa "metode ini tidak lagi menyimpan data tampilan untuk WebView ini" untuk mencegah reload formulir WebView?
Lucas P.
24

Jawaban terbaik untuk ini adalah mengikuti dokumentasi Android yang ditemukan di sini. Pada dasarnya ini akan mencegah Webview dari reload:

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

Secara opsional , Anda dapat memperbaiki anomali (jika ada) dengan mengesampingkan onConfigurationChangeddalam aktivitas:

@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();
    }
}
Tinashe
sumber
6
Anda tidak memerlukan metode onConfigurationChanged () Saya cukup yakin, hanya atribut tambahan di Manifest. Dugaan saya adalah bahwa dukungan asli untuk ini disediakan oleh WebView, dan inilah mengapa jawaban ini sekarang adalah yang terbaik (karena ini tidak berfungsi ketika pertanyaan awalnya diajukan)
Booger
1
Saya menyetujui @Booger Anda tidak perlu mengganti metode onConfigurationChanged (). Semua yang Anda butuhkan adalah menambahkan android: configChanges = "orientasi | screenSize" di file manifest.xml.
ozanurkan
5

Saya sudah mencoba menggunakan onRetainNonConfigurationInstance (mengembalikan WebView ), kemudian mendapatkannya kembali dengan getLastNonConfigurationInstance selama onCreate dan menetapkan ulang.

Sepertinya belum berfungsi. Saya tidak dapat membantu tetapi berpikir saya benar-benar dekat! Sejauh ini, saya hanya mendapatkan WebView kosong / latar belakang putih sebagai gantinya. Posting di sini dengan harapan bahwa seseorang dapat membantu mendorong yang ini melewati garis finish.

Mungkin saya seharusnya tidak melewati WebView . Mungkin objek dari dalam WebView ?

Metode lain yang saya coba - bukan favorit saya - adalah mengaturnya di aktivitas:

 android:configChanges="keyboardHidden|orientation"

... dan kemudian tidak melakukan apa-apa di sini:

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

ITU bekerja, tetapi itu mungkin tidak dianggap sebagai praktik terbaik .

Sementara itu, saya juga memiliki ImageView tunggal yang ingin saya perbarui secara otomatis tergantung pada rotasi. Ini ternyata sangat mudah. Di bawah resfolder saya , saya memiliki drawable-landdan drawable-portmenahan variasi lanskap / potret, kemudian saya gunakan R.drawable.myimagenameuntuk sumber ImageView dan Android "melakukan hal yang benar" - yay!

... kecuali ketika Anda melihat perubahan konfigurasi, maka tidak. :(

Jadi saya berselisih. Gunakan onRetainNonConfigurationInstance dan rotasi ImageView berfungsi, tetapi kegigihan WebView tidak ... atau gunakan onConfigurationChanged dan WebView tetap stabil, tetapi ImageView tidak memperbarui. Apa yang harus dilakukan?

Satu catatan terakhir: Dalam kasus saya, memaksakan orientasi bukanlah kompromi yang dapat diterima. Kami benar-benar ingin mendukung rotasi dengan anggun. Agak suka bagaimana aplikasi Browser Android tidak! ;)

Joe D'Andrea
sumber
7
Anda tidak boleh mengembalikan Tampilan apa pun dari onRetainNonConfigurationInstance. Tampilan terlampir pada Konteks Aktivitas jadi jika Anda menyimpan tampilan Anda membawa semua bagasi itu setiap kali ada perubahan orientasi. Pandangan "bocor". (Lihat paragraf terakhir di sini: developer.android.com/resources/articles/… ) Praktik terbaik untuk onRetainNonConfigurationInstance adalah menyimpan data yang dibutuhkan tampilan, bukan tampilan itu sendiri.
Declan Shanaghy
3

Salah satu kompromi adalah menghindari rotasi. Tambahkan ini untuk memperbaiki aktivitas hanya untuk orientasi Potret.

android:screenOrientation="portrait"
Jacques René Mesrine
sumber
Ini sebenarnya berfungsi dalam banyak kasus dan merupakan solusi yang saya putuskan untuk diterapkan :-)
Abdo
1
hehe, ini adalah perubahan persyaratan
Max Ch
3

Cara terbaik untuk menangani perubahan orientasi dan Mencegah pemuatan ulang WebView di Rotate.

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

Dengan mengingat hal itu, untuk mencegah onCreate () dipanggil setiap kali Anda mengubah orientasi, Anda harus menambahkan android:configChanges="orientation|screenSize" to the AndroidManifest.

atau hanya ..

android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"`
Amit raj
sumber
3

Cukup tulis baris kode berikut dalam file Manifest Anda - tidak ada yang lain. Ini benar-benar berfungsi:

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

Saya menghargai ini agak terlambat, namun ini adalah jawaban yang saya gunakan ketika mengembangkan solusi saya:

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

}
David Passmore
sumber
2

Anda dapat mencoba menggunakan onSaveInstanceState()dan onRestoreInstanceState()pada Aktivitas Anda untuk memanggil saveState(...)dan restoreState(...)pada contoh WebView Anda.

deltaearl
sumber
2

Ini tahun 2015, dan banyak orang mencari solusi yang masih dapat digunakan pada ponsel Jellybean, KK dan Lollipop. Setelah banyak kesulitan saya menemukan cara untuk mempertahankan tampilan web utuh setelah Anda mengubah orientasi. Strategi saya pada dasarnya adalah untuk menyimpan tampilan web dalam variabel statis yang terpisah di kelas lain. Kemudian, jika rotasi terjadi, saya melepaskan tampilan web dari aktivitas, menunggu orientasi selesai, dan pasang kembali tampilan web kembali ke aktivitas. Misalnya ... pertama-tama letakkan ini di MANIFEST Anda (keyboardHidden dan keyboard adalah opsional):

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

Dalam KELAS APLIKASI TERPISAH, masukkan:

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

Dalam ACTIVITY cantumkan:

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

Akhirnya, XML sederhana:

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

Ada beberapa hal yang dapat ditingkatkan dalam solusi saya, tetapi saya sudah menghabiskan banyak waktu, misalnya: cara yang lebih singkat untuk memvalidasi jika Kegiatan telah diluncurkan untuk pertama kalinya alih-alih menggunakan penyimpanan SharedPreferences. Pendekatan ini menjaga Anda tetap utuh tampilan web (afaik), kotak teks, label, UI, variabel javascript, dan negara navigasi yang tidak tercermin oleh url.

Josh
sumber
1
Mengapa repot-repot melepaskan dan memasang kembali WebView ketika itu tidak pernah dihancurkan sejak Anda menangani perubahan konfigurasi secara manual?
Fred
@Fred Karena saya ingin menjaga kondisi persis dari tampilan Web dan kontennya tetap utuh, termasuk cookie, dan status tombol dan kotak centang diimplementasikan dengan HTML5 atau JS di dalam halaman web yang dimuat oleh tampilan web. Satu-satunya penyesuaian yang saya lakukan adalah mengubah ukuran.
Josh,
Fred berarti Anda tidak perlu melepaskan / memasang kembali tampilan web melalui kelas statis saat Anda mendeklarasikan konfigurasi di manifes. Dengan cara ini, pandangan dan aktivitas Anda tidak akan hancur selama rotasi.
Eugene Kartoyev
2

Satu-satunya hal yang harus Anda lakukan adalah menambahkan kode ini ke file manifes Anda:

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

Pembaruan: strategi saat ini adalah untuk memindahkan instance WebView ke kelas Aplikasi alih-alih dipertahankan fragmen ketika dilepaskan dan pasang kembali pada resume seperti yang dilakukan Josh. Untuk mencegah aplikasi menutup, Anda harus menggunakan layanan latar depan, jika Anda ingin mempertahankan status ketika pengguna beralih di antara aplikasi.

Jika Anda menggunakan fragmen, Anda bisa menggunakan instance retensi dari WebView. Tampilan web akan dipertahankan sebagai anggota kelas contoh. Namun Anda harus melampirkan tampilan web di OnCreateView dan lepaskan sebelum OnDestroyView untuk mencegahnya rusak dengan wadah induk.

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

Kredit PS pergi ke jawaban kcoppock

Adapun 'SaveState ()' tidak lagi berfungsi sesuai dengan dokumentasi resmi :

Harap perhatikan bahwa metode ini tidak lagi menyimpan data tampilan untuk WebView ini. Perilaku sebelumnya berpotensi bocor file jika restoreState (Bundle) tidak pernah dipanggil.

Boris Treukhov
sumber
Perhatikan bahwa sementara setRetainInstancemempertahankan Fragmen tampilan (dan karenanya WebView) masih dihancurkan.
Fred,
1
@ Fred Bisakah Anda memberikan sumber untuk pernyataan itu? Saya telah menguji ini di aplikasi kecil yang memiliki fragmen dengan setRetainInstance (true) yang menampilkan halaman youtube dan jika saya mengubah orientasi, tampilan tampaknya dipertahankan karena video tidak terganggu. Sepertinya tampilan web tidak hancur.
Pinkerton
@Rai Itu hanya salah baca, saya telah mengedit sedikit jawabannya sejak saat itu (masih membutuhkan beberapa perbaikan kata-kata). Jika Anda tertarik dengan keadaan saat ini - metode ini berfungsi. Namun masalahnya adalah Android membunuh aplikasi saat kehabisan memori. Saya memiliki formulir input penting di mana pengguna harus membaca pesan di aplikasi lain, jadi saya harus menggunakan layanan foreground dengan pemberitahuan untuk mencegah proses terbunuh. Namun android masih menghancurkan aktivitas dan karenanya frame dipertahankan. Tetapi instance dari kelas Aplikasi dipertahankan - jadi saya memindahkan WebView ke Aplikasi sekarang.
Boris Treukhov
1
Saya juga menggunakan MutableContextWrapper sebagai basis dari WebView, saya mengalihkan konteks ke aktivitas di attach dan detach. Masalah besar lainnya yang kontrol zoom bawaan Chromium menyimpan referensi ke aktivitas lama, jadi tidak ada solusi zoom in dengan WebView yang terpasang pada Aplikasi alih-alih Activity. TL; DR; jika formulir Anda tidak begitu penting, dan Anda dapat hidup dengan fakta bahwa setelah pengalihan aplikasi proses Anda dapat dimatikan dan tampilan web tidak dipulihkan dengan solusi bingkai yang dipertahankan. PS juga saya pikir bahwa karyawan Google jauh, jauh dari masalah kehidupan nyata dengan semua widget-gadget mereka ..
Boris Treukhov
1
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);    
}

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

Metode ini dapat ditimpa pada aktivitas apa pun, itu hanya pada dasarnya memungkinkan Anda untuk menyimpan dan mengembalikan nilai setiap kali aktivitas dibuat / dihancurkan, ketika orientasi layar mengubah aktivitas akan dihancurkan dan diciptakan kembali di latar belakang, sehingga Anda dapat menggunakan metode ini untuk menyimpan sementara / mengembalikan negara selama perubahan.

Anda harus melihat lebih dalam pada dua metode berikut dan melihat apakah itu cocok dengan solusi Anda.

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

Chiwai Chan
sumber
1

Solusi terbaik yang saya temukan untuk melakukan ini tanpa membocorkan Activityreferensi sebelumnya dan tanpa mengatur configChanges.. adalah dengan menggunakan MutableContextWrapper .

Saya telah menerapkan ini di sini: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java

Simon
sumber
apakah ini dapat diandalkan tanpa efek samping? Saya belum menemukan banyak informasi tentang metode ini.
craigrs84
1

Ini adalah satu-satunya hal yang bekerja untuk saya (saya bahkan menggunakan save instance state onCreateViewtetapi tidak bisa diandalkan).

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

Saya membuat pemegang Singleton untuk status WebView. Keadaan dipertahankan selama proses aplikasi ada.

EDIT: Itu loadDataWithBaseURLtidak perlu, itu berfungsi dengan baik hanya dengan

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

Meskipun saya membaca ini tidak selalu berhasil dengan cookie.

EpicPandaForce
sumber
Menggunakan singleton bermasalah, karena mengasumsikan Anda hanya memiliki satu contoh yang perlu Anda gunakan.
Pengembang Android
@androiddeveloper ah. Nah, jika itu tidak benar dalam kasus Anda, maka memang itu masalah. Saya hanya punya satu contoh WebView, jadi pertanyaan ini bahkan tidak muncul untuk saya.
EpicPandaForce
1

coba ini

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

}
Anwar SE
sumber
0

Halaman ini menyelesaikan masalah saya, tetapi saya harus membuat sedikit perubahan di awal:

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

Bagian ini memiliki sedikit masalah bagi saya ini. Pada perubahan orientasi kedua aplikasi diakhiri dengan null pointer

menggunakan ini bekerja untuk saya:

    @Override
protected void onSaveInstanceState(Bundle outState ){
    ((WebView) findViewById(R.id.webview)).saveState(outState);
}
gyanu
sumber
tampaknya persis sama. Mengapa yang kedua bekerja sementara yang sebelumnya tidak?
Pengembang Android
0

Anda harus mencoba ini:

  1. Buat layanan, di dalam layanan itu, buat WebView Anda.
  2. Mulai layanan dari aktivitas Anda dan ikat padanya.
  3. Dalam onServiceConnectedmetode ini, dapatkan WebView dan panggil setContentViewmetode tersebut untuk merender WebView Anda.

Saya mengujinya dan berfungsi tetapi tidak dengan WebViews lain seperti XWalkView atau GeckoView.

Ramdane Oualitsen
sumber
Hai! Bisakah Anda menjelaskannya lebih lanjut? Terima kasih
Jaco
1
Nah, dapatkan contoh tampilan web Anda dari Aktivitas Anda dan cobalah untuk menempatkan referensi ke layanan yang berjalan di latar belakang. Lain kali Anda membuka aktivitas itu, cobalah untuk mendapatkan tampilan web yang disimpan terlebih dahulu dan render.
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);
    }
RealDEV
sumber
Bisakah Anda menambahkan beberapa baris penjelasan ke jawaban Anda?
yacc