問題はローテーション後の性能です。WebView はページをリロードする必要がありますが、これは少し面倒です。
毎回ソースからページをリロードせずに向きの変更を処理する最良の方法は何ですか?
問題はローテーション後の性能です。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
編集:このメソッドは、ドキュメントに記載されているように機能しなくなりました
元の答え:
これはonSaveInstanceState(Bundle outState)
、アクティビティを上書きしsaveState
、Webビューから呼び出すことで処理できます。
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
もちろん、Webビューが再膨張した後、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 ドキュメントに従うことです。 基本的にこれにより、Webview のリロードが防止されます。
<activity android:name=".MyActivity"
android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection|uiMode"
android:label="@string/app_name">
編集(2020 年 1 月 4 日): このオプションのコードは必要ありません。必要なのはマニフェスト属性だけです。オプションのコードをここに残して、回答を完全に保ちます。
必要onConfigurationChanged
に応じて、アクティビティでオーバーライドすることにより、異常 (存在する場合) を修正できます。
@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を返す)を使用してみました。次に、onCreate中にgetLastNonConfigurationInstanceを使用して取得し、再割り当てしました。
まだ機能していないようです。でも本当に近いと思わずにはいられない!これまでのところ、代わりに空白/白い背景のWebViewを取得しています。誰かがこれをフィニッシュラインを越えて押し進めるのを手伝ってくれることを期待して、ここに投稿します.
たぶん、 WebViewを渡すべきではありません。おそらくWebView内のオブジェクトでしょうか?
私が試したもう 1 つの方法 (私のお気に入りではありません) は、アクティビティでこれを設定することです。
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
あり、保持するために、ImageViewのソースに使用し、Android は「正しいことを行います」-やった!drawable-port
R.drawable.myimagename
...構成の変更を監視する場合を除いて、そうではありません。:(
だから私は対立しています。onRetainNonConfigurationInstanceを使用するとImageViewの回転は機能しますが、WebViewの永続性は機能しません ... またはonConfigurationChangedを使用するとWebViewは安定したままですが、ImageViewは更新されません。何をすべきか?
最後に 1 つ注意してください: 私の場合、向きを強制することは許容できる妥協ではありません。ローテーションを適切にサポートしたいと考えています。Android ブラウザ アプリのやり方と似ています。;)
1 つの妥協点は、回転を避けることです。これを追加して、縦向きのみのアクティビティを修正します。
android:screenOrientation="portrait"
Activity と WebView インスタンスを使用して呼び出すことがonSaveInstanceState()
できます。onRestoreInstanceState()
saveState(...)
restoreState(...)
2015 年になり、多くの人が Jellybean、KK、Lollipop の携帯電話で引き続き機能するソリューションを探しています。苦労の末、向きを変えた後もウェブビューをそのまま保持する方法を見つけました。私の戦略は基本的に、別のクラスの別の静的変数に webview を格納することです。次に、回転が発生した場合は、アクティビティから webview をデタッチし、オリエンテーションが終了するのを待って、webview をアクティビティに再度アタッチします。たとえば...最初にこれをMANIFESTに入れます(keyboardHiddenとkeyboardはオプションです):
<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>
SEPARATE APPLICATION CLASS に、次のように記述します。
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 ストレージを使用する代わりに、Activity が初めて起動されたかどうかを検証するためのより短い方法です。このアプローチは、webview をそのまま (afaik)、そのテキストボックス、ラベル、UI、javascript 変数、および URL に反映されていないナビゲーション状態を保持します。
このコードをマニフェスト ファイルに追加するだけです。
<activity android:name=".YourActivity"
android:configChanges="orientation|screenSize"
android:label="@string/application_name">
更新: 現在の戦略は、Josh のように、WebView インスタンスがデタッチされたときにフラグメントを保持するのではなく、アプリケーション クラスに移動し、再開時に再アタッチすることです。アプリケーションが閉じないようにするには、ユーザーがアプリケーションを切り替えたときに状態を保持する場合は、フォアグラウンド サービスを使用する必要があります。
フラグメントを使用している場合は、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();
}
}
PS クレジットはkcoppock の回答に移動します
「SaveState()」に関しては、公式ドキュメントによると機能しなくなりました:
このメソッドは、この WebView の表示データを保存しないことに注意してください。以前の動作では、restoreState(Bundle) が呼び出されなかった場合、ファイルがリークする可能性がありました。
Activity
以前の参照を漏らさず、configChanges
..を設定せずにこれを行うために私が見つけた最良の解決策は、 MutableContextWrapperを使用することです。
これは私のために働いた唯一のものです(インスタンスの状態を保存することさえ使用しまし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());
}
私はこれを読みましたが、必ずしも Cookie でうまく機能するとは限りません。
@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
このページは私の問題を解決しますが、最初の問題を少し変更する必要があります。
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
この部分は私にとってはちょっとした問題です。2 回目の向きの変更で、アプリケーションは null ポインタで終了しました
これを使用すると、私にとってはうまくいきました:
@Override
protected void onSaveInstanceState(Bundle outState ){
((WebView) findViewById(R.id.webview)).saveState(outState);
}
私はこのソリューションが好きhttp://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/
それによると、WebView の同じインスタンスを再利用します。構成変更時にナビゲーション履歴とスクロール位置を保存できます。