Edited at

Activity再生成時にWebViewのHTMLを維持する方法

More than 3 years have passed since last update.


画面回転するとWebViewの入力内容が破棄される問題ついての解決方法

画面を回転すると、Activityは再生成されます。

その時に保持しているWebViewのHTMLのFORMの内容がクリアされてしまいます。

どうしましょう...?

大抵の場合、

じゃあ、「"android:configChanges" の属性指定で Activity再生成抑止」したらいいんじゃない?といわれますが...

画面回転以外のActivity再生成はどうするの?

物理キーボードがスライドされ有効になった時は?充電ドッグに載せた時は?


Activityが再生成されても問題の無いアプリケーションを作りましょう!


Activity/Fragment再生成時の保存/復元処理には以下のような方法があります。


  • Activity#onSaveInstanceStateで保存 / Activity#onCreateで復元

  • Activity#onRetainNonConfigurationInstanceで保存 / Activity#getLastNonConfigurationInstanceで復元

  • Fragment#onSaveInstanceStateで保存 / Fragment#onCreateで復元

  • Fragment#setRetainInstance(true)で、 Fragment が破棄されないようにする。


ActivityのWebView

Activity#onRetainNonConfigurationInstanceで保存 / Activity#getLastNonConfigurationInstanceで復元 する方法で行います。


WebViewActivity

public class WebViewActivity extends AppCompatActivity {

private View mContent;
private WebView mWebView;
protected boolean mHasSavedInstanceState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LOGV(TAG, "onCreate()");

mHasSavedInstanceState = (savedInstanceState != null);

// 保存されたWebViewを取得する。
mContent = (View) getLastCustomNonConfigurationInstance();

if (mContent == null) {
// 取得できなかった場合は、Viewを作成する。
LayoutInflater inflater = getLayoutInflater()
.cloneInContext(new MutableContextWrapper(this));
ViewGroup parent = (ViewGroup) getWindow().getDecorView()
.findViewById(Window.ID_ANDROID_CONTENT);
mContent = inflater.inflate(R.layout.activity_webview, parent, false);
} else {
// 取得したViewをsetContentViewする。
MutableContextWrapper context = (MutableContextWrapper) mContent.getContext();
// Change the base context for this ContextWrapper.
context.setBaseContext(this);
}

setContentView(mContent);
mWebView = (WebView) findViewById(R.id.web_view);
}

@Override
public Object onRetainCustomNonConfigurationInstance() {
LOGV(TAG, "onRetainCustomNonConfigurationInstance()");

// WebViewを保存する。
((ViewGroup) findViewById(Window.ID_ANDROID_CONTENT)).removeView(mContent);
return mContent;
}

@Override
protected void onDestroy() {
super.onDestroy();
LOGV(TAG, "onDestroy()");

// Activity破棄の理由を取得
int changingConfigurations = getChangingConfigurations();
LOGV(TAG, "getChangingConfigurations() :" + changingConfigurations + " (" + String.format("0x%08x", changingConfigurations) + ")");

// Activity再作成以外の破棄の場合。
if (changingConfigurations == 0) {
// WebViewを破棄する。
if (mWebView != null) {
mWebView.stopLoading();
mWebView.setWebChromeClient(null);
mWebView.setWebViewClient(null);
unregisterForContextMenu(mWebView);
mWebView.destroy();
mWebView = null;
}
}
}
}



FragmentのWebView

Fragment#setRetainInstance(true)で、 Fragment が破棄されないようにする方法で行います。


WebViewFragment

public class WebViewFragment extends Fragment{

View mContent;
WebView mWebView;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LOGV(TAG, "onCreateView()");

// Activity再生成時にFragmentを破棄させない。
setRetainInstance(true);

// Viewが生成されていない場合に、Viewをインフレートして作成する。
if (mContent == null) {
mContent = inflater.inflate(R.layout.fragment_webview, container, false);
}
return mContent;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
LOGV(TAG, "onViewCreated()");
super.onViewCreated(view, savedInstanceState);

     // WebViewがまだ設定されていない場合にメンバー変数へ格納する。
if (mWebView == null) {
mWebView = (WebView) view.findViewById(R.id.web_view);
}
}

@Override
public void onDestroy() {
super.onDestroy();
LOGV(TAG, "onDestroy()");

// Activityの再生成ではない場合には呼ばれる。

// WebViewを破棄する。
if (mWebView != null) {
mWebView.stopLoading();
mWebView.setWebChromeClient(null);
mWebView.setWebViewClient(null);
unregisterForContextMenu(mWebView);
mWebView.destroy();
mWebView = null;
}
}


Fragment#onDestroyは、Activity再生成時でない場合にはちゃんと呼ばれるので、WebViewの破棄の処理を行っおきます。


参考)

- Android WebView handling orientation changes - Stack Overflow http://stackoverflow.com/questions/1002085/android-webview-handling-orientation-changes

- slightfoot/android-web-wrapper https://github.com/slightfoot/android-web-wrapper/tree/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb

- Activity再生成時のデータの保存・復元(Fragment#setRetainInstance) - プログラマってこんなかんじ?? http://daichan4649.hatenablog.jp/entry/20120530/1338367072


GitHub)

granoeste/WebViewFragmentExample https://github.com/granoeste/WebViewFragmentExample