Android源码分析之WindowManager.LayoutParams属性更新过程
1.来源
问题的来源是因为现在的公司准备转向Android,但是又不想放弃原来的系统,所以想把原来在linux上直接跑的系统移植到Android上来,当然一大重头任务就是对原有界面库的移植和Android图形系统的修改。
我们需要对Android的图形系统加以修改,以实现原有系统的图形效果。原来的系统中有一种页面切换效果,需要将它在Android上实现出来。一开始我是在应用程序层面上,重载装载页面的viewgroup的绘制函数实现的。但是,由于view的内容太过复杂以及在页面切换时系统需要做很多事情,所以切换的动画过程很卡,出现跳帧的现象。
所以我们想到在Android的底层,也就在SurfaceFlinger这个层面上做这种效果。
要想在SurfaceFlinger上面做出这种页面切换效果,而且能根据程序设置决定效果的样式,那么我们需要从应用程序层传递标志到SurfaceFlinger。
我们在SurfaceFlinger里的drawWithOpenGl里,可以得到一个Layer的alpha值,而在应用程序里,我们可以通过来改变此activity对应的surface的alpha值。
[cpp] view plain copy
- Windowwindow=null;
- WindowManager.LayoutParamswl;
- window=getWindow();
- wl=window.getAttributes();
- wl.alpha=0.5f;
- window.setAttributes(wl);
所以需要以Window的LayoutParams.alpha为例,研究Android的图形系统是怎样将WindowManager.LayoutParams里的alpha属性传递到SurfaceFlinger中的drawWithOpenGL中去的。
2.过程分析
1.从Activity类开始
既然在程序中首先是在Activity类中通过getWindow()方法取得Window,那么我们就从Activity类开始。 [java] view plain copy它的实现也很简单,就是返回了一个Window的实例mWindow.
- publicWindowgetWindow(){
- returnmWindow;
- }
那么我们转到Window类中去看看。2.Window类
找到它的位置:./frameworks/base/core/java/android/view/Window.java,按它的类的说明:它是一个顶层的窗口外观和行为策略的抽象类。它的实例应该被用作顶层窗口而添加到Window Manager中去。它提供标准的UI策略,例如背景,标题区域以及默认键处理等。 它有一个惟一的实现类:android.policy.PhoneWindow. 我们先看public void setAttributes(WindowManager.LayoutParams a) ,这个函数的功能是详细的定制窗口的属性: [cpp] view plain copy可见这个函数的功能就是将传进来的属性拷贝到它的成员变量里面,然后调用回调变量的方法。 在Window类里面找到mCallback的赋值,发现它是通过Window::setCallback()方法对这个变量赋值的。接下来就要找Window::setCallback()方法的调用。由于我们的Activity类中有mWindow变量,所以它应该调用了setCallback().我们回到Activity.java中,看getWindow()方
- publicvoidsetAttributes(WindowManager.LayoutParamsa){
- mWindowAttributes.copyFrom(a);
- if(mCallback!=null){
- mCallback.onWindowAttributesChanged(mWindowAttributes);
- }
- }
3.再回到Activity
在Activity::attch()方法里,果然有mWindow成员的赋值以及设置回调对象:mWindow.setCallback(this);从这一句发现,山Window类设置的回调对象就是Activity类,所以在第2小节里,回调对象调用onWindowAttributesChanged()方法也是就调用Activity::onWindowAttributesChanged()方法:
[java] view plain copy
- publicvoidonWindowAttributesChanged(WindowManager.LayoutParamsparams){
- if(mParent==null){
- Viewdecor=mDecor;
- if(decor!=null&&decor.getParent()!=null){
- getWindowManager().updateViewLayout(decor,params);
- }
- }
- }
这里面的getWindowManager()方法返回Activity类的WindowManager成员变量。经过层层追踪,这个mWindowManager成员变量其实就是一个WindowManagerImpl对象经过包装后的LocalWindowManager对象的实例。
4.WindowManager
它的updateViewLayout()方法的实现在WindowManagerImpl.java中:
[java] view plain copy
- publicvoidupdateViewLayout(Viewview,ViewGroup.LayoutParamsparams){
- if(!(paramsinstanceofWindowManager.LayoutParams)){
- thrownewIllegalArgumentException("ParamsmustbeWindowManager.LayoutParams");
- }
- finalWindowManager.LayoutParamswparams
- =(WindowManager.LayoutParams)params;
- view.setLayoutParams(wparams);
- synchronized(this){
- intindex=findViewLocked(view,true);
- ViewRootImplroot=mRoots[index];
- mParams[index]=wparams;
- root.setLayoutParams(wparams,false);
- }
- }
这段代码的大概过程是:先取得先将传入的参数转换成WindowManager.LayoutParams, 然后根据第一个参数 view(其实它是一个decoview)找到此Activity对象的mRoot,然后调用它的setLayoutParams()方法。
5.ViewRootImpl
在ViewRootImpl.java中,我们查看ViewRootImpl::setLayoutParams()方法,它只是将传入的窗口属性参数保存起来,然后设置属性变化标志符,然后就调用了scheduleTraversals()方法。那么经过调度,最终会运行performTraversals()这个方法。在这个方法里,由会调用relayoutWindow()方法
6.relayoutWindow()
在这个方法里,最重要的一句就是这一句: [java] view plain copy
- intrelayoutResult=sWindowSession.relayout(
- mWindow,mSeq,params,
- (int)(mView.getMeasuredWidth()*appScale+0.5f),
- (int)(mView.getMeasuredHeight()*appScale+0.5f),
- viewVisibility,insetsPending?WindowManagerImpl.RELAYOUT_INSETS_PENDING:0,
- mWinFrame,mPendingContentInsets,mPendingVisibleInsets,
- mPendingConfiguration,mSurface);
由ViewRootImpl的成员变量mWindowSession调用它的方法relayout对窗口重新布局。
sWindowSession其实是与WindowManagerService类进行通信的一个会话,它最终调用的是WindowManagerService::relayoutWindow()方法
7.WindowManagerService
WindowManagerService::relayoutWindow()的主要作用是将传入的窗口属性保存到与每个Window相关联的WindowState上去: [cpp] view plain copy
- //通过session和client,在HashMap<IBinder,WindowState>找到WindowState变量
- WindowStatewin=windowForClientLocked(session,client,false);
- 。。。//将属性进行相应的转换后保存到WindowState
- if((attrChanges&WindowManager.LayoutParams.ALPHA_CHANGED)!=0){//这二个条件来自WindowManager.java,先不管
- winAnimator.mAlpha=attrs.alpha;
- }
winAnimator是WindowState实例的一个成员,它用来实现状态变化时的动画效果。
8.在java层面上属性设置完毕
到一步,我们的属性设置从Activity类一直传递到WindowManager中的WindowState中的WindowStateAnimator实例中保存起来,那么它什么时候传递到native的SurfaceFlinger中呢。
9.关注WindowManagerService类
WMS中有一个内部类AnimationRunnable,它实现了runnable接口,WMS服务一直运行,那么我们看一看它到底运行了什么东西: [java] view plain copy可以看到,它实现上运行的东西非常简单,就是把与每个Window对应的WindowState放到到WMS的一个成员变量mAnimator的mWinAnimators数组中,然后调用mAnimator的animate()方法。 mAnimator是WindowAniamtor类的实例,它用来保存每个WindowState动画的轨迹和Surface操作。mAnimator.mWinAnimators是一个WindowStateAnimator类型的数组。
- publicvoidrun(){
- synchronized(mWindowMap){
- mAnimationScheduled=false;
- //Updateanimationsofallapplications,includingthose
- //associatedwithexiting/removedapps
- synchronized(mAnimator){
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,"wmAnimate");
- finalArrayList<WindowStateAnimator>winAnimators=mAnimator.mWinAnimators;
- //mAnimator是一个WindowAnimator的实例
- //mAnimator.mWinAnimators实际上是一个WindowState数组byamw
- winAnimators.clear();
- finalintN=mWindows.size();//mWindows:Z有序的WindowState数组
- for(inti=0;i<N;i++){
- finalWindowStateAnimatorwinAnimator=mWindows.get(i).mWinAnimator;
- if(winAnimator.mSurface!=null){
- winAnimators.add(winAnimator);
- }
- }
- mAnimator.animate();
- //上面的大概过程就是将WMS管理的WindowState放到的WindowAnimator中,
- //然后将WindowAnimator放到可系统更新过程中直到被调度
- //由类名可以推测Window的动画也是这样产生的。
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
- }
10.WindowAnimator
在WindowAnimator::animate()方法中,最关键的: [cpp] view plain copy它针对每个WindowStateAnimator调用它的prepareSurfaceLocked()方法
- finalintN=mWinAnimators.size();
- for(inti=0;i<N;i++){
- mWinAnimators.get(i).prepareSurfaceLocked(true);//byamw
- }
11.prepareSurfaceLocked()
在这个方法里,通过 [cpp] view plain copy设置Surface的属性,那么我们查看Surface.java可以知道,setAlpha()方法是一个native方法,所以它实际上调用的是android_view_surface.cpp中的Surface_setAlpha方法。这个方法又调用SurfaceControl::setAlpha()方法。它又调用SurfaceComposerClient::setAlpha方法。在这个方法里: [cpp] view plain copy
- mSurface.setAlpha(mShownAlpha);
- status_tComposer::setAlpha(constsp<SurfaceComposerClient>&client,
- SurfaceIDid,floatalpha){
- LOGD("Composer::setAlpha...SurfaceID:%");//byamw
- Mutex::Autolock_l(mLock);
- layer_state_t*s=getLayerStateLocked(client,id);
- if(!s)
- returnBAD_INDEX;
- s->what|=ISurfaceComposer::eAlphaChanged;
- s->alpha=alpha;
- returnNO_ERROR;
- }
它得到LayerState,设置它的事件类型以及相应的值。然后返回。
12.SurfaceFlinger
由于surfaceFlinger继承自BnSurfaceComposerClient,所以它能响应来自BpSurfaceComposerClient的请求。响应函数为SurfaceFlinger::onTransact();
在这里面就是根据消息类型调用不同的方法来处理,对我们关注的alpha的值的处理:
[cpp] view plain copy读取相应的值,然后调用setTransactionState()方法: [cpp] view plain copy
- caseSET_TRANSACTION_STATE:{
- LOGD("SET_TRANSACTION_STATE");
- CHECK_INTERFACE(ISurfaceComposer,data,reply);
- size_tcount=data.readInt32();
- ComposerStates;
- Vector<ComposerState>state;
- state.setCapacity(count);
- for(size_ti=0;i<count;i++){
- s.read(data);
- state.add(s);
- }
- intorientation=data.readInt32();
- uint32_tflags=data.readInt32();
- setTransactionState(state,orientation,flags);
- }break;
对每个相关联的Layer,设置它的state: [cpp] view plain copy
- constsize_tcount=state.size();
- for(size_ti=0;i<count;i++){
- constComposerState&s(state[i]);
- sp<Client>client(static_cast<Client*>(s.client.get()));
- transactionFlags|=setClientStateLocked(client,s.state);//setastatetotherelativelayer.--byamw
- }
- uint32_tSurfaceFlinger::setClientStateLocked(
- constsp<Client>&client,
- constlayer_state_t&s)
- {
- if(what&eAlphaChanged){//................inSurfaceComposerClient.cpp,Composer::setAlpha(),s->what|=ISurfaceComposer::eAlphaChanged;
- if(layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))//LayerBase::setAlphaiscalledatthere.--byamw
- flags|=eTraversalNeeded;
- }
- ...
- }
从上面可以看到,每个Layer 根据它的state,重新设置了它的alpha值。更多 学习资料
更多相关文章
- [转]快速切换Android工程版本的方法
- Android_TextView属性XML详解
- 图解 Android 动画中 android:pivotX 和 android:pivotY 属性的
- Android中使用Handler机制更新UI的两种方法
- Android中设置关键字高亮的方法
- ProgressBar属性小结