Het probleem is de uitvoering na rotatie. De Webview moet de pagina opnieuw laden, die een beetje vervelend kan zijn.
Wat is de beste manier om een geaardheidsverandering te verwerken zonder de pagina van de bron telkens opnieuw te laden?
1, Autoriteit 100%
Als u niet wilt dat de WebView opnieuw wordt geladen op oriëntatiewijzigingen, negeert u eenvoudig op ConfigurationChanged in uw activiteitenklasse:
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
en stel de Android in: Configureer attribuut in het manifest:
<activity android:name="..."
android:label="@string/appName"
android:configChanges="orientation|screenSize"
Voor meer info Zie:
http://developer.android.com/guide/topics/resources /runtime-changes.html#HandlingThechange
https://developer.android.com/reference/android/ app / activiteit.html # configurationChanges
2, Autoriteit 77%
EDIT: deze methode werkt niet langer zoals vermeld in de Docs
origineel antwoord:
Dit kan worden afgehandeld door het overschrijven van onSaveInstanceState(Bundle outState)
in uw activiteit en bellen saveState
van de Webview:
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
Herstel dit dan in uw oncreate nadat de Webview natuurlijk is opgeplant:
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blah);
if (savedInstanceState != null)
((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
3, Autoriteit 26%
Het beste antwoord hierop volgt Android-documentatie gevonden HIER
In principe verhindert dit Webview van herladen:
<activity android:name=".MyActivity"
android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection|uiMode"
android:label="@string/app_name">
EDIT (1/4/2020): U hebt deze optionele code niet nodig, het kenmerk Manifest is alles wat u nodig hebt, waardoor hier een optionele code achterblijft om het antwoord compleet te houden.
Eventueel , u kunt anomalieën (indien aanwezig) repareren door door te halen onConfigurationChanged
in de activiteit:
@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();
}
}
4, Autoriteit 5%
Ik heb geprobeerd OnretainNonConfigurationInstance (teruggeven aan de Webview ), en dan terug krijgen met GetlastnonconfigurationInstance Tijdens Oncreate en het opnieuw toewijzen.
Het lijkt nog niet te werken. Ik kan het niet helpen, maar denk dat ik er heel dichtbij ben! Tot nu toe krijg ik gewoon een WebViewmet een lege/witte achtergrond. Ik post hier in de hoop dat iemand kan helpen deze over de finish te krijgen.
Misschien moet ik de WebViewniet passeren. Misschien een object uit de WebView?
De andere methode die ik heb geprobeerd – niet mijn favoriet – is om dit in de activiteit in te stellen:
android:configChanges="keyboardHidden|orientation"
… en dan hier vrijwel niets doen:
@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.
}
DAT werkt, maar het kan niet worden beschouwd als een best practice.
Ondertussen heb ik ook een enkele ImageViewdie ik automatisch wil bijwerken, afhankelijk van de rotatie. Dit blijkt heel eenvoudig te zijn. In mijn map res
heb ik drawable-land
en drawable-port
om landschaps-/portretvariaties te bewaren, dan gebruik ik R.drawable.myimagename
voor de bron van ImageViewen Android “doet het juiste” – yay!
… behalve als je let op configuratiewijzigingen, dan gebeurt dat niet. 🙁
Dus ik sta op gespannen voet. Gebruik onRetainNonConfigurationInstanceen de ImageView-rotatie werkt, maar WebView-persistentie werkt niet … of gebruik onConfigurationChangeden de WebViewblijft stabiel, maar de ImageViewwordt niet bijgewerkt. Wat te doen?
Nog een laatste opmerking: in mijn geval is het forceren van oriëntatie geen acceptabel compromis. We willen rotatie echt sierlijk ondersteunen. Een beetje zoals hoe de Android Browser-app doet! 😉
Antwoord 5, autoriteit 4%
De beste manier om met oriëntatiewijzigingen om te gaan en te voorkomen dat WebView opnieuw wordt geladen bij Rotate.
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
Om te voorkomen dat onCreate() wordt aangeroepen telkens wanneer u de oriëntatie wijzigt, moet u daarom android:configChanges="orientation|screenSize" to the AndroidManifest.
of gewoon ..
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"`
Antwoord 6, autoriteit 4%
Ik stel het op prijs dat dit een beetje laat is, maar dit is het antwoord dat ik heb gebruikt bij het ontwikkelen van mijn oplossing:
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);
}
}
7, Autoriteit 3%
Eén compromis is om rotatie te voorkomen.
Voeg dit toe om alleen de activiteit voor portretoriëntatie op te lossen.
android:screenOrientation="portrait"
8, Autoriteit 3%
Schrijf gewoon de volgende codelijnen in uw manifest-bestand – niets anders. Het werkt echt:
<activity android:name=".YourActivity"
android:configChanges="orientation|screenSize"
android:label="@string/application_name">
9, Autoriteit 2%
Het is 2015, en veel mensen zijn op zoek naar een oplossing die nog steeds werkt op Jellybean, KK en Lollipop-telefoons.
Na Veel worstelen Ik vond ik een manier om de WebView intact te behouden nadat je de oriëntatie hebt gewijzigd.
Mijn strategie is eigenlijk om de webview op te slaan in een aparte statische variabele in een andere klasse. Als er vervolgens rotatie plaatsvindt, koppel ik de webview los van de activiteit, wacht ik tot de oriëntatie is voltooid en koppel ik de webview weer aan de activiteit.
Bijvoorbeeld… plaats dit eerst op uw MANIFEST (keyboardHidden en keyboard zijn optioneel):
<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>
Plaats in een APARTE TOEPASSINGSKLASSE:
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();
}
}
Plaats in de ACTIVITEIT:
@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);
}
Tot slot, de eenvoudige 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>
Er zijn verschillende dingen die verbeterd kunnen worden in mijn oplossing, maar ik heb al te veel tijd besteed, bijvoorbeeld: een kortere manier om te valideren of de activiteit voor de allereerste keer is gestart in plaats van het gebruik van SharedPreferences-opslag.
Deze aanpak houdt uw webweergave intact (afaik), de tekstvakken, labels, gebruikersinterface, javascript-variabelen en navigatiestatussen die niet worden weergegeven door de url.
Antwoord 10, autoriteit 2%
Het enige dat u hoeft te doen is deze code aan uw manifestbestand toe te voegen:
<activity android:name=".YourActivity"
android:configChanges="orientation|screenSize"
android:label="@string/application_name">
Antwoord 11, autoriteit 2%
Update: de huidige strategie is om de WebView-instantie naar de Application-klasse te verplaatsen in plaats van het behouden fragment wanneer het wordt losgekoppeld en opnieuw te koppelen bij het hervatten, zoals Josh doet.
Om te voorkomen dat de toepassing wordt gesloten, moet u de voorgrondservice gebruiken als u de status wilt behouden wanneer de gebruiker tussen toepassingen schakelt.
Als u fragmenten gebruikt, kunt u de bewaarinstantie van de WebView gebruiken.
De webweergave blijft behouden als instantielid van de klas. U moet echter de webweergave in OnCreateView bijvoegen en loskoppelen vóór OnDestroyView om te voorkomen dat deze wordt vernietigd met de bovenliggende container.
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();
}
}
P.S. Credits gaan naar kcoppock-antwoord
Voor ‘SaveState()’ werkt het niet meer volgens officiële documentatie:
Houd er rekening mee dat deze methode niet langer de weergavegegevens opslaat voor:
deze WebView. Het vorige gedrag kan mogelijk bestanden lekken als:
restoreState(Bundle) is nooit aangeroepen.
Antwoord 12
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
}
Deze methoden kunnen voor elke activiteit worden overschreven, het stelt je in feite in staat om waarden op te slaan en te herstellen telkens wanneer een activiteit wordt gemaakt/vernietigd, wanneer de schermoriëntatie verandert, wordt de activiteit vernietigd en opnieuw gemaakt op de achtergrond, dus daarom zou je dat kunnen doen. gebruik deze methoden om statussen tijdelijk op te slaan/te herstellen tijdens de wijziging.
U moet de twee volgende methoden nader bekijken en kijken of deze bij uw oplossing passen.
http://developer.android.com/reference/android/app /Activiteit.html
Antwoord 13
De beste oplossing die ik heb gevonden om dit te doen zonder de vorige Activity
-referentie te lekken en zonder de configChanges
in te stellen.. is het gebruik van een MutableContextWrapper.
Ik heb dit hier geïmplementeerd: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java
Antwoord 14
Dit is het enige dat voor mij werkte (ik gebruikte zelfs de status van de opgeslagen instantie in onCreateView
maar het was niet zo betrouwbaar).
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;
}
}
Ik heb een Singleton-houder gemaakt voor de status van de WebView. De status blijft behouden zolang het proces van de aanvraag bestaat.
EDIT: De loadDataWithBaseURL
was niet nodig, het werkte net zo goed met slechts
//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());
}
Hoewel ik lees dat dit niet per se goed werkt met cookies.
Antwoord 15
probeer dit
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;
}
}
}
Antwoord 16
Deze pagina lost mijn probleem op, maar ik moet een kleine wijziging aanbrengen in de eerste:
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
Dit gedeelte heeft voor mij een klein probleem. Bij de tweede wijziging van de oriëntatie eindigde de toepassing met een null-aanwijzer
gebruik hiervan werkte het voor mij:
@Override
protected void onSaveInstanceState(Bundle outState ){
((WebView) findViewById(R.id.webview)).saveState(outState);
}
Antwoord 17
Je zou dit moeten proberen:
- Maak een service, binnen die service, maak je WebView.
- Start de service vanuit uw activiteit en bind eraan.
- In de
onServiceConnected
methode haalt u de WebView op en roept u desetContentView
methode aan om uw WebView weer te geven.
Ik heb het getest en het werkt, maar niet met andere WebViews zoals XWalkView of GeckoView.
Antwoord 18
@Override
protected void onSaveInstanceState(Bundle outState )
{
super.onSaveInstanceState(outState);
webView.saveState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
webView.restoreState(savedInstanceState);
}
Antwoord 19
Ik vind deze oplossing leuk http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/
Volgens ons hergebruiken we dezelfde instantie van WebView. Het maakt het mogelijk om navigatiegeschiedenis en scrollpositie op te slaan bij configuratiewijzigingen.