So I was using the ActionBarSherlock and decided to switch to the new ActionBarCompat. With ABS, hiding the ActionBar was possible using the way described in this post: How to hide action bar before activity is created, and then show it again?
But, with the ActionBarCompat the app crashes on API14, because when you set android:windowActionBar
as false
the getSupportActionBar()
method returns null, even if you have declared the getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
into the onCreate()
method.
Funny thing is that if you call getActionBar()
instead, you get the object and everything works fine.
So, is that a bug or am I missing something? Any ideas are welcome!
styles.xml
file:
<style name="Theme.MyApp" parent="@style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowTitleSize">0dp</item>
</style>
MyActivity.java
file:
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the action bar feature. This feature is disabled by default into the theme
// for specific reasons.
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
...
// By default the action bar is hidden.
getSupportActionBar().hide();
}
I got stuck with the same problem and, it seems to me, found a reason of this strange behavior. I looked through source of support library and got this:
Appcompat checks a value of mHasActionBar
variable before creating new action bar in ActionBarActivityDelegate
final ActionBar getSupportActionBar() {
// The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
// could change after onCreate
if (mHasActionBar || mOverlayActionBar) {
if (mActionBar == null) {
mActionBar = createSupportActionBar();
...
And we can change its value by calling supportRequestWindowFeature(int featureId)
which is delegated by ActionBarActivity
to a ActionBarActivityDelegate.
There are base delegate class ActionBarDelegateBase
and its descendants ActionBarDelegateHC
, ActionBarActivityDelegateICS
, ActionBarActivityJB
, one of which is chosen according to a version of running android. And method supportRequestWindowFeature
is actually works fine almost in all of them, but it's overridden in ActionBarActivityDelegateICS
like that
@Override
public boolean supportRequestWindowFeature(int featureId) {
return mActivity.requestWindowFeature(featureId);
}
So it has no effect on the variable mHasActionBar
, that's why getSupportActionBar()
returns null.
We almost there. I came to two different solutions.
import source project of appcompat from git
change overridden method in ActionBarActivityDelegateICS.java
to something like this
@Override
public boolean supportRequestWindowFeature(int featureId) {
boolean result = mActivity.requestWindowFeature(featureId);
if (result) {
switch (featureId) {
case WindowCompat.FEATURE_ACTION_BAR:
mHasActionBar = true;
case WindowCompat.FEATURE_ACTION_BAR_OVERLAY:
mOverlayActionBar = true;
}
}
return result;
}
place this line in activity's onCreate
method before getSupportActionBar()
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
import project of appcompat from android SDK (which is with empty src directory)
add this method to your activity
private void requestFeature() {
try {
Field fieldImpl = ActionBarActivity.class.getDeclaredField("mImpl");
fieldImpl.setAccessible(true);
Object impl = fieldImpl.get(this);
Class<?> cls = Class.forName("android.support.v7.app.ActionBarActivityDelegate");
Field fieldHasActionBar = cls.getDeclaredField("mHasActionBar");
fieldHasActionBar.setAccessible(true);
fieldHasActionBar.setBoolean(impl, true);
} catch (NoSuchFieldException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
} catch (IllegalAccessException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
} catch (ClassNotFoundException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
}
}
call requestFeature()
in onCreate
method of your activity like this
if (Build.VERSION.SDK_INT >= 11) {
requestFeature();
}
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
I used the second way. That's all.