ActionBarCompat: Hide ActionBar before activity is created (bug?)

喜夏-厌秋 提交于 2019-11-27 14:53:52

问题


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();
}

回答1:


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.

First way

  1. import source project of appcompat from git

  2. 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;
    }
    
  3. place this line in activity's onCreate method before getSupportActionBar()

    supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
    

Second way

  1. import project of appcompat from android SDK (which is with empty src directory)

  2. 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);
        }
    }
    
  3. 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.




回答2:


I use this to hide ActionBar in AppCompat: style.xml

<style name="Theme.AppCompat.Light.NoActionBar" parent="@style/Theme.AppCompat.Light">
    <item name="android:windowNoTitle">true</item>
</style>

AndroidManifest.xml:

<activity
        android:name=".Splash"
        android:label="@string/title_activity_splash"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>



回答3:


I don`t know if I understood exactly your question, but here I go.

I think that you need to use both: getSupportActionBar() to old versions and getActionBar() to newest versions. It`s not a bug.

You need to verify the device version before use the methods.

I hope I was able to help.




回答4:


Does your activity extends ActionBarActivity? Probably it doesn't and that's why it's running with the getActionbar() method.



来源:https://stackoverflow.com/questions/18526144/actionbarcompat-hide-actionbar-before-activity-is-created-bug

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!