問題は、回転後のパフォーマンスです。 WebViewはページをリロードする必要があり、少し面倒です。
毎回ソースからページをリロードせずに向きの変更を処理する最良の方法は何ですか?
方向の変更時に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
編集:このメソッドは docs
元の回答:
これは、アクティビティのonSaveInstanceState(Bundle outState)
を上書きし、WebビューからsaveState
を呼び出すことで処理できます。
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
もちろん、webviewが再膨張した後、onCreateでこれを回復します。
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blah);
if (savedInstanceState != null)
((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
これに対する最善の答えは、次のAndroidドキュメントが見つかりました here 基本的に、これはWebviewのリロードを防ぎます:
<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();
}
}
onRetainNonConfigurationInstance(WebViewを返す)を使用して、getLastNonConfigurationInstanceonCreateおよび再割り当て中。
まだ機能していないようです。私は仕方がありませんが、私は本当に近いと思います!これまでのところ、代わりに空白/ホワイトバックグラウンドWebViewを取得しています。誰かがこれをフィニッシュラインを超えてプッシュできるように、ここに投稿してください。
WebViewを渡すべきではないでしょう。おそらくWebView内からのオブジェクトですか?
私が試した他の方法-私のお気に入りではありません-アクティビティでこれを設定することです:
Android:configChanges="keyboardHidden|orientation"
...そして、ここではほとんど何もしません:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// We do nothing here. We're only handling this to keep orientation
// or keyboard hiding from causing the WebView activity to restart.
}
これは機能しますが、 ベストプラクティス とは見なされない場合があります。
一方、回転に応じて自動的に更新する単一のImageViewもあります。これは非常に簡単です。 res
フォルダーの下に、drawable-land
とdrawable-port
があり、ランドスケープ/ポートレートのバリエーションを保持します。その後、ImageViewのソースとAndroidにR.drawable.myimagename
を使用します_「正しいことをする」-イェーイ!
...構成の変更を監視する場合を除き、そうではありません。 :(
だから私は対立している。 onRetainNonConfigurationInstanceを使用し、ImageView回転は機能しますが、WebView永続性は...またはonConfigurationChangedを使用せず、WebViewは安定したままですが、 ImageViewは更新されません。何をすべきか?
最後の注意点:私の場合、向きを強制することは許容できる妥協ではありません。ローテーションを適切にサポートしたいのです。 Android Browserアプリの機能が気に入っています。 ;)
妥協点の1つは、回転を避けることです。これを追加して、縦向きのみのアクティビティを修正します。
Android:screenOrientation="portrait"
私はこれが少し遅れていることを感謝していますが、これは私のソリューションを開発するときに使用した答えです:
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);
}
}
向きの変更を処理し、Rotateで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"`
アクティビティでonSaveInstanceState()
およびonRestoreInstanceState()
を使用して、WebViewインスタンスでsaveState(...)
およびrestoreState(...)
を呼び出すことができます。
それは2015年であり、多くの人がJellybean、KK、Lollipopの携帯電話でまだ機能するソリューションを探しています。 much苦労した後、向きを変えた後でもwebviewをそのまま保持する方法を見つけました。私の戦略は、基本的に別のクラスの個別の静的変数にWebビューを保存することです。次に、回転が発生した場合、アクティビティから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();
}
}
ACTIVITYに以下を入力します。
@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ストレージを使用する代わりに、アクティビティが初めて起動されたかどうかを検証するための短い方法です。このアプローチにより、Webビュー(afaik)、テキストボックス、ラベル、UI、javascript変数、およびURLに反映されないナビゲーション状態がそのまま保持されます。
更新:現在の戦略は、Joshが行うように、再開時にWebViewインスタンスを保持フラグメントの代わりにApplicationクラスに移動し、再開時に再接続することです。アプリケーションが閉じないようにするには、ユーザーがアプリケーションを切り替えたときに状態を保持する場合は、フォアグラウンドサービスを使用する必要があります。
フラグメントを使用している場合、WebViewの保持インスタンスを使用できます。 Webビューは、クラスのインスタンスメンバーとして保持されます。ただし、OnCreateViewでWebビューをアタッチし、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(); } }
追伸クレジットは kcoppock answer に移動します
'SaveState()'に関しては、 公式ドキュメント に従って動作しなくなりました:
このメソッドは、このWebViewの表示データを保存しないことに注意してください。 restoreState(Bundle)が呼び出されなかった場合、以前の動作ではファイルがリークする可能性がありました。
これが私のために働いた唯一のものです(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());
}
私が読んだとしても、これは必ずしもクッキーでうまく機能するとは限りません。
以前のActivity
参照をリークせずにconfigChanges
..を設定せずにこれを行うことがわかった最良の解決策は、 MutableContextWrapper を使用することです。
マニフェストファイルに次のコード行を記述するだけです。他には何もしません。それは実際に動作します:
<activity Android:name=".YourActivity"
Android:configChanges="orientation|screenSize"
Android:label="@string/application_name">
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
}
これらのメソッドは任意のアクティビティでオーバーライドできます。基本的には、アクティビティが作成/破棄されるたびに値を保存および復元できます。画面の向きが変更されると、アクティビティはバックグラウンドで破棄および再作成されるため、これらのメソッドを使用できます変更中に状態を一時的に保存/復元します。
次の2つの方法を詳しく調べて、ソリューションに適合するかどうかを確認する必要があります。
http://developer.Android.com/reference/Android/app/Activity.html
マニフェストファイルにこのコードを追加するだけです。
<activity Android:name=".YourActivity"
Android:configChanges="orientation|screenSize"
Android:label="@string/application_name">
これを試してください:
onServiceConnected
メソッドで、WebViewを取得し、setContentView
メソッドを呼び出してWebViewをレンダリングします。私はそれをテストしましたが、XWalkViewやGeckoViewのような他のWebViewでは動作しません。
これを試して
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;
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState )
{
super.onSaveInstanceState(outState);
webView.saveState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
webView.restoreState(savedInstanceState);
}
このページは私の問題を解決しますが、最初の問題を少し変更する必要があります。
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
この部分には、私にとってこれにはわずかな問題があります。 2番目の方向変更で、アプリケーションがヌルポインターで終了しました
これを使用して、それは私のために働いた:
@Override
protected void onSaveInstanceState(Bundle outState ){
((WebView) findViewById(R.id.webview)).saveState(outState);
}