getSupportActionBar from inside of Fragment ActionBarCompat

AndroidAndroid FragmentsAndroid Support-LibraryAndroid Actionbar-Compat

Android Problem Overview


I'm starting a new project that uses the AppCompat/ActionBarCompat in v7 support library. I'm trying to figure out how to use the getSupportActionBar from within a fragment. My activity that hosts the fragment extends ActionBarActivity, but I don't see a similar support class for Fragments.

From within my fragment

    public class CrimeFragment extends Fragment {
          //...

          getActivity().getSupportActionBar().setSubtitle(R.string.subtitle); // getSupportActionBar is not defined in the v4 version of Fragment

          //...
    }

The google page for using it (http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html) says there should be no changes for the v4 fragment. Do I need to cast all my getActivity() calls to an ActionBarActivity? That seems like poor design.

Android Solutions


Solution 1 - Android

After Fragment.onActivityCreated(...) you'll have a valid activity accessible through getActivity().

You'll need to cast it to an ActionBarActivity then make the call to getSupportActionBar().

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);

You do need the cast. It's not poor design, it's backwards compatibility.

Solution 2 - Android

While this question has an accepted answer already, I must point out that it isn't totally correct: calling getSupportActionBar() from Fragment.onAttach() will cause a NullPointerException when the activity is rotated.

Short answer:

Use ((ActionBarActivity)getActivity()).getSupportActionBar() in onActivityCreated() (or any point afterwards in its lifecycle) instead of onAttach().

Long answer:

The reason is that if an ActionBarActivity is recreated after a rotation, it will restore all Fragments before actually creating the ActionBar object.

Source code for ActionBarActivity in the support-v7 library:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate() creates the mImpl object depending on the Android version.
  • super.onCreate() is FragmentActivity.onCreate(), which restores any previous fragments after a rotation (FragmentManagerImpl.dispatchCreate(), &c).
  • mImpl.onCreate(savedInstanceState) is ActionBarActivityDelegate.onCreate(), which reads the mHasActionBar variable from the window style.
  • Before mHasActionBar is true, getSupportActionBar() will always return null.

Source for ActionBarActivityDelegate.getSupportActionBar():

final ActionBar getSupportActionBar() {
    // The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
    // could change after onCreate
    if (mHasActionBar || mOverlayActionBar) {
        if (mActionBar == null) {
            ... creates the action bar ...
        }
    } else {
        // If we're not set to have a Action Bar, null it just in case it's been set
        mActionBar = null;
    }
    return mActionBar;
}

Solution 3 - Android

If someone uses com.android.support:appcompat-v7: and AppCompatActivity as activity then this will work

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);

Solution 4 - Android

For those using kotlin,

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)

Solution 5 - Android

As an updated answer for Pierre-Antoine LaFayette's answer

ActionBarActivity is deprecated; use AppCompatActivity instead

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

Solution 6 - Android

in your fragment.xml add Toolbar Tag from support library

 <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Now how we can control it from MyFragment class? let's see

inside onCreateView function add the following

mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);

//add this line if you want to provide Up Navigation but don't forget to to 
//identify parent activity in manifest file
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);

and if you want to add items to the toolbar within MyFragment you must add this line inside onCreateView function

        setHasOptionsMenu(true);

this line is important, if you forget it, android will not populate your menu Items.

assume we identify them in menu/fragment_menu.xml

after that override the following functions

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
	inflater.inflate(R.menu.fragment_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
		case R.id.action_1:
    		// do stuff
		    return true;
	        
		case R.id.action_2:
    		// do more stuff
		    return true;
    }
	
    return false;
}

hope this helps

Solution 7 - Android

As an addendum to GzDev's answer, if you already have the string, you can use kotlin's auto-setter:

(activity as AppCompatActivity).supportActionBar?.subtitle = my_string

And you can turn it off by simply using an empty string.

Note that this works for both the title and the subtitle.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaulView Question on Stackoverflow
Solution 1 - AndroidPierre-Antoine LaFayetteView Answer on Stackoverflow
Solution 2 - AndroidmatiashView Answer on Stackoverflow
Solution 3 - AndroidAmirView Answer on Stackoverflow
Solution 4 - AndroidGzDevsView Answer on Stackoverflow
Solution 5 - AndroidDasser BasyouniView Answer on Stackoverflow
Solution 6 - AndroidBasheer AL-MOMANIView Answer on Stackoverflow
Solution 7 - AndroidSMBiggsView Answer on Stackoverflow