.getSupportActionBar not available in Fragment; workaround leads to NullPointerException on rotation

PattaFeuFeu picture PattaFeuFeu · Jul 30, 2014 · Viewed 17.7k times · Source

Structure

(names of Activies/Fragments changed)

Based on some advice written in Android Programming: The Big Nerd Ranch Guide, I have the following structure:

  • MyListFragment extends ListFragment
  • MyListActivity extends SimpleFragmentActivity
  • SimpleFragmentActivity extends ActionBarActivity

MyListActivity.java

public class MyListActivity extends SingleFragmentActivity {

    @Override
    protected Fragment createFragment() {
        return new MyListFragment();
    }
}

SingleFragmentActivity.java

public abstract class SingleFragmentActivity extends ActionBarActivity {

    protected abstract Fragment createFragment ();

    @Override
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment);

        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);

        if (fragment == null) {
            fragment = createFragment();
            fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
        }
    }
}

After having outlined and programmed the basic functionality of my app (including Contextual Action Bar, navigation, …) I wanted to make sure that the app is as backwards compatible as possible without too much additional effort. Therefore, I started using the AppCompat (com.android.support:appcompat-v7:20+) ActionBar.

What baffled me right at the beginning was that—opposed to every tutorial or Android’s Developer guidelines I read—the getSupportActionBar method has never been available in Android Studio (I’m using Android Studio v0.8.2 and JRE 1.7_60). Whenever I type getActivity().getSup, the only suggestions I get are getSupportFragmentManager and getSupportLoaderManager.

As a workaround, I create a member variable ActionBar mActionBar in MyListFragment and initialise it:

@Override
public void onAttach (Activity activity) {
    super.onAttach(activity);
    mActionBar = ((ActionBarActivity) activity).getSupportActionBar();
}

That seemed to do the trick on either Android 4.4.4 (Moto G) and 2.3.4 (LG E-510)—the only devices I have available.

However—coming to the problem I have—on rotation the ActionBar assignment gets lost and the application crashes with a NullPointerException. Debugging the application and setting a breakpoint on the following line in onCreate:

mActionBar.setTitle(R.string.title_activity_my_list);

I found out that mActionBar is null after the rotation. Placing said line in onCreateView didn’t help.

What I tried

  • Placing the initialisation of mActionBar in
    • onAttach
    • onActivityCreated
    • onCreate/onCreateView right before .setTitle gets called

I’m out of ideas here and grateful for advice.

EDIT-0 (30.07.)

Exception being thrown (after editing according to Alex’ suggestion)

07-30 15:05:25.239    5049-5049/MYAPPNAME E/AndroidRuntime﹕ [Blue Error Handler] Make Debugging Report file for main
java.lang.RuntimeException: Unable to start activity ComponentInfo{MYAPPNAME/MYAPPNAME.MYLISTACTIVITY}: java.lang.NullPointerException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1653)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1669)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2838)
    at android.app.ActivityThread.access$1600(ActivityThread.java:117)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3737)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:894)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
    at MYAPPNAME.MYLISTFRAGMENT.onCreate(MYLISTFRAGMENT.java:54)
    at android.support.v4.app.Fragment.performCreate(Fragment.java:1481)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:908)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1103)
    at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:1896)
    at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:216)
    at android.support.v7.app.ActionBarActivity.onCreate(ActionBarActivity.java:98)
    at MYAPPNAME.SingleFragmentActivity.onCreate(SingleFragmentActivity.java:22)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1617)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1669)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2838)
    at android.app.ActivityThread.access$1600(ActivityThread.java:117)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3737)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:894)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652)
    at dalvik.system.NativeStart.main(Native Method)

MyListFragment line 54 (exception occured using either SingleFragmentActivity and ActionBarActivity as a cast)

((SingleFragmentActivity) getActivity()).getSupportActionBar().setTitle(R.string
            .title_activity_my_list);

SingleFragmentActivity lines 20-22:

@Override
public void onCreate (Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

Answer

Alex picture Alex · Jul 30, 2014

Cast your getActivity() to ActionBarActivity/AppCompatActivity (depends what you are using) and you will have access to the support ActionBar.

((AppCompatActivity)getActivity()).getSupportActionBar();

or

((ActionBarActivity)getActivity()).getSupportActionBar();

Use this code in onActivityCreated(...) method instead of onAttach(...)