Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

fixes NPE ActionBar.TabListener #402

Merged
merged 2 commits into from

3 participants

@gabrielittner

This is a fix for Issue #391. The explanation is in the commit message.

For testing you can overwrite the FragmentTabs class in the fragment sample with the following code:

public class FragmentTabs extends SherlockFragmentActivity {

    ActionBar actionBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(SampleList.THEME); //Used for theme switching in samples
        super.onCreate(savedInstanceState);

        actionBar = getSupportActionBar();
        actionBar.addTab(actionBar.newTab().setText("Simple")
            .setTabListener(new TabListener<FragmentStackSupport.CountingFragment>
            (this, "simple", FragmentStackSupport.CountingFragment.class)));
        actionBar.addTab(actionBar.newTab().setText("Contacts")
            .setTabListener(new TabListener<CursorLoaderListFragment>
            (this, "contacts", LoaderCursorSupport.CursorLoaderListFragment.class)));
        actionBar.addTab(actionBar.newTab().setText("Custom")
            .setTabListener(new TabListener<AppListFragment>
            (this, "custom", LoaderCustomSupport.AppListFragment.class)));
        actionBar.addTab(actionBar.newTab().setText("Throttle")
            .setTabListener(new TabListener<ThrottledLoaderListFragment>
            (this, "throttle", LoaderThrottleSupport.ThrottledLoaderListFragment.class)));
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    }

public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
    private Fragment mFragment;
    private final Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    public TabListener(Activity activity, String tag, Class<T> clz) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
    }

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if (ft == null) {
             Log.i("tabselected", "fragmenttransaction == null");
             return;
        }
        if (mFragment == null) {
            mFragment = Fragment.instantiate(mActivity, mClass.getName());
            ft.add(android.R.id.content, mFragment, mTag);
        } else {
            ft.attach(mFragment);
        }
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        if (ft == null) {
            Log.i("tabunselected", "fragmenttransaction == null");
                return;
        }
        if (mFragment != null) {
            ft.detach(mFragment);
        }
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }
}
}
@gabrielittner gabrielittner prevent NullPointerException at onTabSelected()
The implementation of onTabSelected() uses the instance variable 
mFragmentTransaction, which is hand over to the listeners 
onTabSelected(). At the start of an Activity, which uses a TabListener
a NullPointerException is thrown, because the FragmentTransaction is
null. The only point where a FragmentTransaction is assigned to 
mFragmentTransaction is onTabUnselected().

I guess the intended behavior is that the transaction created in
onTabUnselected() is used in onTabSelected() afterwards and the
detaching/attaching is done in the same transaction (because
onTabUnselected() doesn't call commit on the transaction itself). 

However at the start just onTabSelected() is called and not
onTabUnselected(), because there was nothing selected before. So
mFragmentTransaction is null and the Exception is thrown. I added an
if-check to  receive the FragmentTransaction the same way
onTabUnselected() does, when mFragmentTransaction is null.
e14a1c1
@JakeWharton
Owner

Can you add an instanceof check to the if statement as well? If someone is using tabs inside of a regular SherlockActivity you'll get a ClassCastException on the activity start.

@JakeWharton JakeWharton merged commit a1c502f into from
@SimoneCasagranda

Hi to all :)
I don't really like this solution because if you rotate your device the onTabUnselected isn't called and after rotation you'll find two "lastVisibleFragment".

I have solved using directly the FragmentManager. For example for onTabSelected:

public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (ft == null) {
Log.i(TAG, "FragmentTransaction == null during Tab selection");
return;
}
Fragment fragment = mFragmentManager.findFragmentByTag(mTag);
if(fragment == null) {
ft.add(android.R.id.content, Fragment.instantiate(mActivity, mClass.getName()), mTag);
} else {
ft.attach(fragment);
}

}

Is this a valid solution?

Thanks a lot (and thanks Jake for your great work!),
Simone

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 23, 2012
  1. @gabrielittner

    prevent NullPointerException at onTabSelected()

    gabrielittner authored
    The implementation of onTabSelected() uses the instance variable 
    mFragmentTransaction, which is hand over to the listeners 
    onTabSelected(). At the start of an Activity, which uses a TabListener
    a NullPointerException is thrown, because the FragmentTransaction is
    null. The only point where a FragmentTransaction is assigned to 
    mFragmentTransaction is onTabUnselected().
    
    I guess the intended behavior is that the transaction created in
    onTabUnselected() is used in onTabSelected() afterwards and the
    detaching/attaching is done in the same transaction (because
    onTabUnselected() doesn't call commit on the transaction itself). 
    
    However at the start just onTabSelected() is called and not
    onTabUnselected(), because there was nothing selected before. So
    mFragmentTransaction is null and the Exception is thrown. I added an
    if-check to  receive the FragmentTransaction the same way
    onTabUnselected() does, when mFragmentTransaction is null.
  2. @gabrielittner

    added instanceof check

    gabrielittner authored
This page is out of date. Refresh to see the latest.
View
8 library/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java
@@ -335,6 +335,14 @@ public void onTabReselected(android.app.ActionBar.Tab tab, android.app.FragmentT
@Override
public void onTabSelected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
if (mListener != null) {
+
+ if (mFragmentTransaction == null) {
+ if (mActivity instanceof SherlockFragmentActivity) {
+ mFragmentTransaction = ((SherlockFragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
+ .disallowAddToBackStack();
+ }
+ }
+
mListener.onTabSelected(this, mFragmentTransaction);
if (mFragmentTransaction != null) {
Something went wrong with that request. Please try again.