getSupportActionBar from inside of Fragment ActionBarCompat
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.
Solution 1:
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:
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 themImpl
object depending on the Android version. -
super.onCreate()
isFragmentActivity.onCreate()
, which restores any previous fragments after a rotation (FragmentManagerImpl.dispatchCreate()
, &c). -
mImpl.onCreate(savedInstanceState)
isActionBarActivityDelegate.onCreate()
, which reads themHasActionBar
variable from the window style. - Before
mHasActionBar
is true,getSupportActionBar()
will always returnnull
.
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:
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:
For those using kotlin,
(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
Solution 5:
As an updated answer for Pierre-Antoine LaFayette's answer
ActionBarActivity is deprecated; use AppCompatActivity
instead
((AppCompatActivity)getActivity()).getSupportActionBar();