14

I am using Action Bar on an Activity. For each Tab I am showing different layout. Since the layout is too heavy. So I am inflating each layout into a view. So on each Tab select

public void onTabSelected(Tab tab, FragmentTransaction ft) {
    if (mView == null) {
        mView = LayoutInflater.from(mAct).inflate(mLayout, null);  // mAct is Activity reference
    }
    mAct.setContentView(mView);
    for (int i = 0; i < mFrags.length; i++) {
     mFrags[i] = (LutronFragment) mAct.getFragmentManager()
         .findFragmentById(mIds[i]);

     if (mFrags[i] != null) {
       mFrags[i].setupHeader();
      }
  }
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
  for (Fragment f : mFrags) {
   try { 
         if (f != null) {
        ft.remove(f);
      }
  } catch (IllegalStateException e) {
        e.printStackTrace();
  }
   }
}

So Now if I select tab second time and do some operation on that Tab, app get crashed on getActivity.(NullPointerException)

Please suggest if there is some another approach to cache heavy layout.

CRABOLO
  • 8,605
  • 39
  • 41
  • 68
Ashutosh Dubey
  • 385
  • 1
  • 4
  • 14
  • are you saying `mAct` becomes null? Also, there is no point in caching layouts, what you should do is have the layout load in the background while the foreground should have some user interface like either a progress dialog or some kind of an intermediate user interactable screen. Finally, consider reducing the weight of your layout, or load elements on demand. Can you post your layout xml to see if it is actually heavy? – gaara87 Jul 18 '12 at 07:31

2 Answers2

39

The problem is most likely that you're using an old Fragment that has been detached from your Activity.

So, the first time you create your Fragment, it is attached to your activity. All is good. Then when you change tab, your fragment might or might not be detached from the activity. When you tab back to it, the old fragment may be detached from the activity and so getActivity() returns null.

This can happen if you're trying to keep references to your Fragments, rather than accessing them via the FragmentManager.

It can also happen if your adapter is returning a reference to a fragment rather than a new fragment. I've fallen into this trap.

(Posting the code where you create your fragments might help)

Edit

Maybe have a look at this and how they create add their ActionBar listeners. You need scope to your Activity. The way they do it is to define the listener in the Activity/Fragment (via implementing an interface) and then attach it to the Tab. This will give you scope and is probably a more stable way of doing things.

Mike T
  • 4,747
  • 4
  • 32
  • 52
  • Please edit your question and add it to the bottom rather. It's really tough trying to read this. – Mike T Jul 18 '12 at 07:35
  • Where are you calling this code from? It looks like it would be called from your activity. If so, why keep a reference to your activity in your activity? Why not just call `setContentView(mView)` rather than `mAct.setContentView(mView)`? – Mike T Jul 18 '12 at 07:38
  • Please read my comment just above please. It doesn't seem like you should be storing a reference to your activity at all – Mike T Jul 18 '12 at 07:42
  • OnTabSelected() and onTabUnselected() are the metods of ActionBar.TabListener. – Ashutosh Dubey Jul 18 '12 at 07:42
  • Actually I have created a class that implementes the ActionBar.TabListener. – Ashutosh Dubey Jul 18 '12 at 07:54
  • I realise that now. I'll reply from now on by editing my answer. – Mike T Jul 18 '12 at 07:56
6

This can happen if you create an anonymous object inside a fragment that calls getActiviy(). If getActivity() is called in the anonymous object after the fragment is popped off the fragment stack, getActivity() will return null. At that point, the fragment is no longer associated with an activity.

morten.c
  • 3,414
  • 5
  • 40
  • 45
Kru
  • 61
  • 1
  • 1