Android的WebView中:在处理方向变化Android的WebView中:在处理方向变化(A

2019-05-13 10:43发布

问题是下面的旋转性能。 web视图具有刷新页面,这可能是有点乏味。

什么是处理的方向没有改变,每次重装从源页面的最佳方法是什么?

Answer 1:

如果你不希望的WebView有望重新加载方向发生在你的Activity类只需覆盖onConfigurationChanged:

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

并设置了android:configChanges在清单属性:

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

更多信息,请参阅:
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

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



Answer 2:

编辑:此方法不再起作用,如所陈述的文档


原来的答案:

这可以通过overrwriting处理onSaveInstanceState(Bundle outState)在您的活动,并呼吁saveState来自网页流量:

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

然后在你的onCreate恢复此web视图已重新充气课程后:

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


Answer 3:

最佳答案这是继发现Android文档在这里基本上这将防止从网页视图重装:

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

在活动:

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


Answer 4:

我已经使用onRetainNonConfigurationInstance(返回的WebView)尝试,然后在的onCreate得到它回来getLastNonConfigurationInstance并重新分配它。

似乎并不只是还没有工作。 我不禁觉得我真的非常接近,但! 到目前为止,我只是得到了一个空白/白背景的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-landdrawable-port保持横向/纵向变化,然后我用R.drawable.myimagenameImageView的的来源和Android‘做正确的事’ -耶!

...当你留意配置的变化,除了,那么它没有。 :(

所以,我在赔率。 使用onRetainNonConfigurationInstanceImageView的旋转工作,但持续的WebView不...或使用onConfigurationChangedWebView中保持稳定,但ImageView的不更新。 该怎么办?

最后一点:在我的情况下,迫使方向不是一个可以接受的妥协。 我们真的想平稳地支持旋转。 有点像Android的浏览器应用程序怎么做! ;)



Answer 5:

一个妥协是为了避免旋转。 增加这个修为仅纵向方向的活动。

android:screenOrientation="portrait"


Answer 6:

处理方向的变化和旋转防止的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"`


Answer 7:

我明白这是一个有点晚了,但是这是我开发我的解决方案时所使用的答案:

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

}


Answer 8:

您可以尝试使用onSaveInstanceState()onRestoreInstanceState()在你的活动来调用saveState(...)restoreState(...)在您的WebView实例。



Answer 9:

这是2015年,很多人都在寻找仍然workds上杰利贝恩,KK和棒棒糖手机的解决方案。 很多挣扎后,我找到了一种方法来保存你改变方向后完整web视图。 我的策略是基本的web视图存储在另一个类单独的静态变量。 然后,如果发生旋转,我dettach从活动web视图,等待方向到结束,并重新安装web视图回活动。 例如......第一次把这个清单的(keyboardHidden和键盘是可选的):

<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完好(据我所知),它的文本框,标签,UI,JavaScript的变量,导航不受该URL反映的状态。



Answer 10:

更新:目前的策略是,当它分离到的WebView实例移动到应用类,而不是保留片段和恢复重新连接为乔什一样。 为了防止正关闭的应用,你应该使用前台服务,如果您想保留状态,当用户切换应用程序之间。

如果您使用的片段,您可以使用保留的WebView的实例。 web视图将被保留作为类的实例成员。 然而,你应该重视网页视图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答案

至于“即时存档()”它不再根据工作的官方文档 :

请注意,这种方法不再存储的显示数据这个的WebView。 以前的行为可能泄漏的文件,如果restoreState(捆绑)从未被调用。



Answer 11:

@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



Answer 12:

我发现这样做没有泄露之前的最佳解决方案Activity参考,不设置configChanges ..是使用MutableContextWrapper 。

我在这里实现了这个: https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java



Answer 13:

你唯一需要做的事情是将此代码添加到您的清单文件:

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


Answer 14:

这仅仅是为我工作的事(我甚至用在保存实例状态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());
    }

虽然我读这不一定与饼干很好地工作。



Answer 15:

只要写下面的代码行中的清单文件 - 没有别的。 真的行:

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


Answer 16:

本页面解决我的问题,但我不得不在最初的一个细微的变化:

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

这部分有轻微的问题,对我来说这一点。 在第二个方向改变与空指针终止应用程序

使用这种它为我工作:

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


Answer 17:

你应该试试这个:

  1. 创建一个服务,该服务中,创建的网页视图。
  2. 开始从你的活动服务,并绑定到它。
  3. onServiceConnected方法,得到的WebView和调用setContentView方法来呈现的网页视图。

我测试了它和它的作品,但不与其他网页视图像XWalkView或GeckoView。



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


Answer 19:

试试这个

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

}


Answer 20:

我喜欢这个解决方案http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

根据它,我们重用的WebView的同一个实例。 它允许保存浏览历史和滚动位置上的配置变化。



文章来源: Android WebView: handling orientation changes