从本篇开始,我将在开发中遇到的应用优化问题进行一点经验的分享。
在UI开发中渲染这个概念相信大家都不陌生,这是优化UI的重点,Android系统支持的硬件加速就是对渲染模型的一个优化。可是不使用这个我们在软件渲染时也有一些小技巧来进行优化。
今天要说的很简单--窗口背景
在开发Activity组件时一般都会给当前的Layout设置背景的,其实这里的Window也是有背景的,如果Layout的背景不透明,那么窗口的背景对用户来说是不可见的,但是在软件渲染模型中只要子View发生变化都会引起父View的重绘,所以这里会有一定的性能影响。对于这种情况,需要将窗口背景设置为空。
采用什么方式来设置呢,有几种方法,在Activity中getWindow().setBackgroundDrawable() 来进行设置,或者通过Theme来进行修改。个人认为通过Theme来进行设置性能最优。
这里有两点需要说明一下,一是窗口背景到底是谁的背景,还有是Theme是什么时候用上的。
1、窗口背景是view树的根也就是常说的DecorView的背景图,这点从源码中可以很清楚的看到,看
phonewindow的setBackgroundDrawable的方法,
其实最后就是设置的mDecor的背景图片
2、Theme是什么时候使用的,来看看phonewindow的setContentView方法就清楚了
很清晰的思路,就不用多说了。需要注意的一点是,由于Theme是在setContentView的时候生效的,所以在代码设置Activity的theme时需要在这个操作之前才可以体现出效果来。
这里面还顺便提两点:
(1) mContentParent,它是generateLayout中创建的,是activity中用户自定义布局的直接父容器,它是一个FrameLayout,这就是布局优化中FrameLayout可以使用merge标签代替的原因。
(2) obtainStyledAttributes看这个方法名,style和theme的区别在哪里,我认为可以统一为Android上的Style,可以分为了两个方面: Theme针对窗体级别的,改变窗体样式; Style针对窗体元素级别的,改变指定控件或者Layout的样式
在UI开发中渲染这个概念相信大家都不陌生,这是优化UI的重点,Android系统支持的硬件加速就是对渲染模型的一个优化。可是不使用这个我们在软件渲染时也有一些小技巧来进行优化。
今天要说的很简单--窗口背景
在开发Activity组件时一般都会给当前的Layout设置背景的,其实这里的Window也是有背景的,如果Layout的背景不透明,那么窗口的背景对用户来说是不可见的,但是在软件渲染模型中只要子View发生变化都会引起父View的重绘,所以这里会有一定的性能影响。对于这种情况,需要将窗口背景设置为空。
采用什么方式来设置呢,有几种方法,在Activity中getWindow().setBackgroundDrawable() 来进行设置,或者通过Theme来进行修改。个人认为通过Theme来进行设置性能最优。
这里有两点需要说明一下,一是窗口背景到底是谁的背景,还有是Theme是什么时候用上的。
1、窗口背景是view树的根也就是常说的DecorView的背景图,这点从源码中可以很清楚的看到,看
phonewindow的setBackgroundDrawable的方法,
public final void setBackgroundDrawable(Drawable drawable) {
if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
mBackgroundResource = 0;
mBackgroundDrawable = drawable;
if (mDecor != null) {
mDecor.setWindowBackground(drawable);
}
}
}
其实最后就是设置的mDecor的背景图片
2、Theme是什么时候使用的,来看看phonewindow的setContentView方法就清楚了
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
………………
}
}
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
TypedArray a = getWindowStyle();
…………………..
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
…………………….
return contentParent;
}
public final TypedArray getWindowStyle() {
synchronized (this) {
if (mWindowStyle == null) {
mWindowStyle = mContext.obtainStyledAttributes(
com.android.internal.R.styleable.Window);
}
return mWindowStyle;
}
}
public final TypedArray obtainStyledAttributes(
int[] attrs) {
return getTheme().obtainStyledAttributes(attrs);
}
很清晰的思路,就不用多说了。需要注意的一点是,由于Theme是在setContentView的时候生效的,所以在代码设置Activity的theme时需要在这个操作之前才可以体现出效果来。
这里面还顺便提两点:
(1) mContentParent,它是generateLayout中创建的,是activity中用户自定义布局的直接父容器,它是一个FrameLayout,这就是布局优化中FrameLayout可以使用merge标签代替的原因。
(2) obtainStyledAttributes看这个方法名,style和theme的区别在哪里,我认为可以统一为Android上的Style,可以分为了两个方面: Theme针对窗体级别的,改变窗体样式; Style针对窗体元素级别的,改变指定控件或者Layout的样式