8

I am trying to save my View states in my fragment but I am concerned I make be leaking my Activity. Here is what I am doing:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state){
   if(mView != null){
      View oldParent = mView.getParent();
      if(oldParent != container){
         ((ViewGroup)oldParent).removeView(mView);
      }
      return mView;
   }
   else{
      mView = inflater.inflate(R.id.fragview, null)
      return mView;
   }
}

I am concerned because I know all Views hold onto a context and I don't know if it is the Activity context or Application context if inflated from the inflater. Perhaps it would be a better idea to pragmatically create the view and set its attributes using getActivity().getApplication() rather than use the inflater. I would appreciate any feedback on this.

Thanks!

EDIT: Confirmed Activity leak, although this code works great don't do it :*(

Programmer Bruce
  • 64,977
  • 7
  • 99
  • 97
Nathan Schwermann
  • 31,285
  • 16
  • 80
  • 91

3 Answers3

2

I am trying to save my View states in my fragment but I am concerned I make be leaking my Activity.

Use onSaveInstanceState() (in the fragment) and onRetainConfigurationInstance() (in the activity) for maintaining "View states" across configuration changes. I am not quite certain what other "View states" you might be referring to.

I am concerned because I know all Views hold onto a context and I don't know if it is the Activity context or Application context if inflated from the inflater.

Since using the Application for view inflation does not seem to work well, you should be inflating from the Activity. And, hence, the views will hold a reference to the Activity that inflated them.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • @commonsware I should have mentioned I am using the compatibility package and can't override `onRetainConfigurationInstance()` since its final in `FragmentActivity` In this case I am trying to retain my entire WebView and don't want to reload the page when the device is rotated. Although I would like to reuse this technique to retain stuff like text in an EditText if this is a viable solution. What issues have you ran into with inflating with an Application, and how did you do it since the inflate method doesn't take a context argument? Thanks for the quick reply! – Nathan Schwermann Mar 27 '11 at 19:31
  • @schwiz: Gadzooks! Having `onRetainNonConfigurationInstance()` be `final` is a big-time problem. Hadn't run into that yet. "In this case I am trying to retain my entire WebView and don't want to reload the page when the device is rotated" -- a `WebView` is one good spot to use `android:configChanges` and avoid the destroy/recreate cycle, IMHO. – CommonsWare Mar 27 '11 at 19:41
  • @schwiz: "What issues have you ran into with inflating with an Application, and how did you do it since the inflate method doesn't take a context argument?" -- `LayoutInflater.from()` takes a `Context`, but you usually get it from `getLayoutInflater()` in an `Activity`, which uses itself as the `Context`. Ran into a problem with somebody reusing one of my components where the real problem was inflating a layout using an `Application`. It's possible that for some widgets it will be OK, but I suspect that some will assume the `Context` is an `Activity`. – CommonsWare Mar 27 '11 at 19:42
  • @commonsware setting through the FragmentManager code I see that it gets the inflater from calling getLayoutInflater() for the containing activity. This is a bummer as I don't think using android:configChanges is a good solution. Perhaps the WebFragment in 3.0 that isn't included in the compatibility package fixes this issue. I don't understand by you can't set the context for a view what could the harm be! This is highly frustrating! – Nathan Schwermann Mar 27 '11 at 20:06
  • 1
    I ended up in this case, rather than using the inflater just creating a new instance of a WebView myself and passing it the application. Luckily I haven't ran into any issues from this yet, although I still think View should have a setContext method! Thanks for you input Mark! – Nathan Schwermann Mar 27 '11 at 21:15
  • @schwiz: BTW, I filed a feature request related to this: http://code.google.com/p/android/issues/detail?id=15795 – CommonsWare Mar 28 '11 at 17:08
  • @CommonsWare, I don't think it would be possible since they made it final so it could retain the fragments. However, I have found its much easier to call setRetainInstance(false) and then use the fragments saveInstanceState method in the same manor, its not quite as powerful since you can only save Parcelables and not Objects but it seems to be good enough. If you want to retain objects you just call setRetainInstance(true) and store them in the fragment. It would however be nice if when setRetainInstance was set to true if the retain hooks were still called on the fragment, but oh well. – Nathan Schwermann Mar 28 '11 at 18:51
  • @schwiz: "I don't think it would be possible since they made it final so it could retain the fragments." -- the strategy I outline in the issue should work fine for getting object retention at the *activity* level, which I'll settle for now. "If you want to retain objects you just call setRetainInstance(true) and store them in the fragment." -- have you gotten that to work? I tried that and it didn't seem to take effect, still recreating my fragments. I didn't experiment a ton, though, and I was focused on another aspect of the problem, so I may have misread the symptoms. – CommonsWare Mar 28 '11 at 19:03
  • @CommonsWare yes I have got setRetainInstance(true) to work, its not exactly what I had expected, onCreatView will still be called wiping out any data in your views but the underlying member data of the fragment is still there. This is why it would be nice if the onSave state hooks were still called so you could retain your views easier. I think the best way to retain stuff in an activity would be to make a non-ui fragment that contains your data you want to save and attach it to your activity with the retain flag set to true. – Nathan Schwermann Mar 28 '11 at 19:45
  • @CommonsWare I was wrong about savedInstanceState not being called if setRetainState is set to true, I was fooled earlier because I didn't realize onCreateView was being called. With this in mind I think Fragmetns are more convenient to use than onRetainNonConfigurationInstance by a long shot. – Nathan Schwermann Mar 29 '11 at 05:54
1

@schwiz é have implemented something similar.

I use the setRetainInstance in the fragment. on the fragment layout I have a FrameLayout placeholder where I put my webView inside.

This webView is created programmatically on the Fragment's onCreate using the Application Context, and I do a addView(webView) on the inflated layout in onCreateView().

webView = new WebView(getActivity().getApplicationContext());

And on onDestroyView I simply remove the webView from my framelayout placeholder.

It work really well, unless you try to play a video in fullscreen. That doesn't work because it expects an Activity Context

Verbeia
  • 4,400
  • 2
  • 23
  • 44
luciofm
  • 737
  • 5
  • 14
0

I am trying to save my View states in my fragment

In order to save and retain view's state you can just use View.onSaveInstanceState () and View.onRestoreInstanceState (Parcelable state)

It will help you to handle saving and restoring view state independantly from neither activity or fragment. See this answer for more information about it (how to prevent custom views from losing state across screen orientation changes)

Community
  • 1
  • 1
rus1f1kat0R
  • 1,645
  • 1
  • 16
  • 22