RequestWindowFeature问题。7.0以下手机要注意。

大家都知道Activity中的requestWindowFeature需要在setContent前调用,否者会抛异常:

AndroidRuntimeException(“requestFeature() must be called before adding content”)

在一部5.0手机上在插件Activity中调用时发现,即使在插件中setContent前调用,也会抛出此异常。
分析下源码。

Activity中的RequestWindowFeature实际上是调用 window.requestFeature(int)
window变量实现类是PhoneWindow。


在7.0以上的版本中代码是:

 public boolean requestFeature(int featureId) {
337        if (mContentParentExplicitlySet) {
338            throw new AndroidRuntimeException("requestFeature() must be called before adding content");
339        }

变量mContentParentExplicitlySet只在两个地方改变过值

 @Override
399    public void setContentView(int layoutResID) {
421        mContentParentExplicitlySet = true;
422    }
430    public void setContentView(View view, ViewGroup.LayoutParams params) {
452        mContentParentExplicitlySet = true;
453    }

在6.0以下版本中,代码是:

 @Override
315    public boolean requestFeature(int featureId) {
316        if (mContentParent != null) {
317            throw new AndroidRuntimeException("requestFeature() must be called before adding content");
318        }

  private void installDecor() {
3980        if (mContentParent == null) {
3981            mContentParent = generateLayout(mDecor);

如下几处调用过installDecor

  @Override
378    public void setContentView(int layoutResID) {
382        if (mContentParent == null) {
383            installDecor();
				}
		}
408    public void setContentView(View view, ViewGroup.LayoutParams params) {
412        if (mContentParent == null) {
413            installDecor();
414        }
430    }
433    public void addContentView(View view, ViewGroup.LayoutParams params) {
434        if (mContentParent == null) {
435            installDecor();
436        }
		}
1967    public final View getDecorView() {
1968        if (mDecor == null) {
1969            installDecor();
1970        }
1972    }
4285    private ImageView getLeftIconView() {
4289        if (mContentParent == null) {
4290            installDecor();
4291        }
		}
4303    private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
4307        if (mContentParent == null && shouldInstallDecor) {
4308            installDecor();
4309        }
4315    }
4316
4317    private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
4321        if (mContentParent == null && shouldInstallDecor) {
4322            installDecor();
4323        }
4329    }
4330
4331    private ImageView getRightIconView() {
4335        if (mContentParent == null) {
4336            installDecor();
4337        }
4339    }

排查一下如果没有调用setContent,在哪里会调用到installDecor。

  • 首先setContentView可以排除。
  • addContentView会被 Dialog会调用
  • getDecorView会被Dialog调用且其他调用地方较多
  • getLeftIconView getRightIconView被 onDrawableChanged调用,onDrawableChanged方法系统没有调用
  • getCircularProgressBar、 getHorizontalProgressBar

getCircularProgressBar、 getHorizontalProgressBar调用处

3648    protected ViewGroup generateLayout(DecorView decor) {
3649        // Apply data from current theme.
  if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
3919            ProgressBar progress = getCircularProgressBar(false);
3920            if (progress != null) {
3921                progress.setIndeterminate(true);
3922            }
3923        }
}
generateLayout<installDecor

1538    private void updateProgressBars(int value) {
1539        ProgressBar circularProgressBar = getCircularProgressBar(true);
1540        ProgressBar horizontalProgressBar = getHorizontalProgressBar(true);

updateProgressBars<onIntChanged<updateInt<setFeatureInt|setChildInt
setChildInt<onIntChanged

最后排除后发现setFeatureInt被Activity调用地方较多,可能是存在问题的原因

5383    public final void setProgressBarVisibility(boolean visible) {
5384        getWindow().setFeatureInt(Window.FEATURE_PROGRESS, visible ? Window.PROGRESS_VISIBILITY_ON :
5385            Window.PROGRESS_VISIBILITY_OFF);
5386    }

5396    public final void setProgressBarIndeterminateVisibility(boolean visible) {
5397        getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
5398                visible ? Window.PROGRESS_VISIBILITY_ON : Window.PROGRESS_VISIBILITY_OFF);
5399    }

5410    public final void setProgressBarIndeterminate(boolean indeterminate) {
5411        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
5412                indeterminate ? Window.PROGRESS_INDETERMINATE_ON
5413                        : Window.PROGRESS_INDETERMINATE_OFF);
5414    }

5426    public final void setProgress(int progress) {
5427        getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress + Window.PROGRESS_START);
5428    }

5443    public final void setSecondaryProgress(int secondaryProgress) {
5444        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
5445                secondaryProgress + Window.PROGRESS_SECONDARY_START);
5446    }

经过分析,7.0以下(不含)的版本,requestWindowFeature会去判断mContentParent 是否为null。如果不为null就会抛出异常。而mContentParent 在多处有有赋值,所以一定要在onCreate方法的最开始调用。
最后发现是在宿主中onCreate中一开始调用了如下代码:

   Window window = activity.getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        window.setStatusBarColor(Color.TRANSPARENT);

        activity.getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                UiModeManager uiModeManager = (UiModeManager) activity.getSystemService(Context.UI_MODE_SERVICE);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && uiModeManager != null
                        && uiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES) {
                    setStatusBarTextWhite(activity);
                } else {
                    setStatusBarTextBlack(activity);
                }
            }
        });

删除后就好了。

还有,7.0以下的版本一定要在onCreate中同步调用,我们可以异步调用setContentView方法,但是不能异步调用requestWindowFeature,因为一旦onCreate执行结束后,其他一些系统自己执行的代码会把mContentParent 赋值,导致即使没有调用setContentView,也会抛出异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值