LoginSignup
32
37

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-09-24

画面回転すると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

32
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
37