47

Window的创建,更新,删除

 5 years ago
source link: http://coderlengary.github.io/2018/08/21/Window/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Window是一个抽象类,它的真正实现是PhoneWindow。所以我们知道Window并不是真正存在的,它是以View的形式存在。对Window的访问必须通过WindowManager.

Window的添加过程

Window的添加过程是通过WindowManager的addView来实现的,而WindowManager是一个接口,它的真正实现是WindowManagerImpl类。

@Override
public void addView(View view, ViewGroup.LayoutParams params){
  mGlobal.addView(view, params, mDisplay, mParentWindow);
}

@Override
public void updateView(View view, ViewGroup.LayoutParams params){
  mGlobal.updateView(view, params);
}

@Override
public void removeView(View view){
  mGlobal.removeView(view, false);
}

可以看到WindowManagerImpl并没有真正实现window的添加、更新、删除,而是交给了WindowManagerGlobal来处理,这种是典型的桥接模式。

WindowManagerGlobal的addView方法主要分为下面几步。

1.检查参数是否合法,如果是子View的话还要调整一下布局参数

if(view == null){
  throw new IllegalArgumentException("view must not be null");
}

if(!(params isntanceof WindowManager.LayoutParams)){
  throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}

if(diaplay == null){
  throw new IllegalArgumentException("diaplay must not be null");
}

final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

if(parentWindow != null){
  parentWindow.adjustLayoutParamsForSubWindow(wparams);
}

2.创建ViewRootImpl并将View添加到列表中

在WindowManagerGlobal中有几个列表比较重要

private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();

在上面的声明中:

  • mViews存储的是所有Window所对应的View
  • mRoots存储的是所有Window所对应的ViewRootImpl
  • mParams存储的是所有Window所对应的布局参数
  • mDyingViews存储的是那些正在被删除的View对象

3.添加一系列参数到上面的列表中

root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);

mViews.add(view);
mRoots.add(root);
mParams.add(wparams);

4.通过ViewRootImpl来更新界面并完成Window的添加过程

这个步骤由ViewRootImpl的setView方法来完成,ViewRootImpl会完成View的绘制。在setView内部会通过requestLayout来完成异步刷新请求。

public void requestLayout(){
  ...
  scheduleTraversals();//执行View的绘制
}

5.通过WindowSession来完成Window的添加过程

在下面代码中mWindowSession的类型是IWindowSession,是一个Binder对象,真正的实现类是Session

...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mInputChannel);
...

在真正实现类Session内部会通过WindowManagerService来实现Window的添加

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParamsattrs, int viewVisibility, int displayId, Rect outContentInsets, InputChannel outInputChannel){
  return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outInputChannel);
}

这样一来,window的添加请求就交给WindowManagerService去处理了。

Window的删除过程

Window的删除过程跟添加过程一样,先通过WindowManagerImpl,再通过WindowManagerGlobal来实现的,WindowManagerGlobal的removeView的代码如下

public void removeView(View view, boolean immidiate){
  ...
  synchronized(mLock){
    int index = findViewLocked(view, true);
    View curView = mRoots.get(index).getView();
    removeViewLocked(index, immidiate);
  }
}

先通过findViewLocked找到要删除的view的索引

再通过removeViewLocked进行进一步的删除

private void removeViewLocked(int index, boolean immidiate){
  ViewRootImpl root = mRoots.get(index);
  View view = root.getView();

  boolean deferred = root.die(immidiate);
  ...
  if(deferred){
    mDyingViews.add(view);
  }
}

root的die方法如下所示。首先View的删除有两种,异步删除和同步删除。immidiate为true就是同步删除,反之亦然。

boolean die(boolean immidiate){

  if(immidiate && !mIsInTraversal){
    doDie();
    return false;
  }

  mHandler.sendEmptyMessage(MSG_DIE);
  rerturn true;
}

如果是同步删除,则立即调用doDie()方法,如果是异步删除,则会发送一个MSG_DIE的消息,root中的Handler会处理这个消息并执行doDie()。

在doDie()内部会调用dispatchDetachedFromWindow方法,它的内部主要做了这几件事

  • 垃圾回收工作,包括清除数据和信息,移除回调
  • 通过mWindowSession.remove(mWindow),这是一个IPC过程,最终实现是Session的remove(mWindow),它的内部同样会调用WindowManagerService的removeWindow方法
  • 调用View的dispatchDetachedFromWindow,最终会会调用onDeteachedFromWindow(),我们可以在这个方法中做一些资源回收工作
  • 调用WindowManagerGlobal的doRemoveView方法,刷新mRoots,mParams,mDyingViews
AV7niyu.png!web

Window的更新过程

Window的更新过程跟添加过程一样,先通过WindowManagerImpl,再通过WindowManagerGlobal来实现的,WindowManagerGlobal的updateViewLayout的代码如下

public void updateViewLayut(View view, ViewGroup.LayoutParams params){
  ...
  final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
  view.setLayoutParams(params);

  synchronized(mLock){
    int index = findViewLocked(view, true);
    ViewRootImpl root = mRoots.get(index);
    mParams.remove(index);
    mParams.add(index, wparams);
    root.setLayoutParams(wparams, false);
  }
}

首先它需要替换掉View的老的LayoutParams,接下来更新ViewRootImpl中的LayoutParams。在ViewRootImpl中还会对View进行重新布局,包括测量、布局、重绘。除了View本身的重绘以外,ViewRootImpl还会通过WindowSeesion来更新window的视图,最终会通过WindowManagerService的relayoutWindow来具体实现


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK