0

I am having a problem preventing a WebView from reloading when inside a fragment with retainInstance set to true.

The routes I have tried:

SaveInstanceState (Doesn't pass a bundle on rotation because of retainInstance) A custom bundle which is saved on onSaveInstanceState and restored in create Keeping the WebView reference and attempt to add it back to the view hierarchy

There must be an easier way?

JamieB
  • 923
  • 9
  • 30

1 Answers1

7

You can do this pretty easily. Since you're already retaining the instance, keep a reference to the WebView in the Fragment and detach it from the parent when the Fragment's onDestroyView() is called. If it's non-null, just return that in onCreateView(). For example:

public class RetainedWebviewFragment extends Fragment {
    private WebView mWebView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (mWebView == null) {
            mWebView = new WebView(getActivity());
        }

        return mWebView;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        if (getRetainInstance() && mWebView.getParent() instanceof ViewGroup) {
            ((ViewGroup) mWebView.getParent()).removeView(mWebView);
        }
    }
}

However, you will leak one reference to the first Activity on the first orientation change -- something I've not yet figured out how to avoid. tThere's no way to set the context on a View to my knowledge. This does work, though, if you're okay with that one memory leak.

EDIT: Alternatively, if you're instantiating it programmatically as I'm doing in this example, you could just use getActivity().getApplicationContext() to avoid leaking the activity. If you use the provided LayoutInflater, it will give the application's context to the Views when inflating.

Don't use the application context for a WebView -- this will cause unexpected crashes when showing dropdown views and potentially other problems.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • When you mention a memory leak on the first rotation - is the leak not always maintaining 1 reference? So there is always another reference to the activity or have I misunderstood that? – JamieB Jul 27 '14 at 21:22
  • So basically, when you create the `WebView` (which will only happen once) you give it the reference to the current `Activity`, which it holds inside (which you can retrieve with `View.getContext()`. When the Activity is destroyed and recreated, that `View` reference is still retained (which still contains the reference to the destroyed `Activity`) and there's no way to update the `View` with the new `Activity` reference (aside from possibly using reflection to update the field internally). – Kevin Coppock Jul 27 '14 at 21:34