Window和WindowManager(一)

一、Window和WindowManager概念:
1、Window表示一个窗口,是一个抽象类,是view的直接管理者。他的具体实现是PhoneWindow
无论是Activity、Dialog、Toast 它们的视图实际上都是附属在Window上的 。
(1)应用Window :Activity
(2)子window ,必须依附在特定的父window上:dialog(子window不能单独存在,需要依附在特定的父Window中)
(3)系统window,必须声明权限才能创建:Toast和系统状态栏
2、WindowManager是一个接口,是外界访问Window的入口。创建一个Window是通过WindowManager完成的。
3、Window的具体实现在WindowManagerService中,WindowManager和WindowManagerService的交互是IPC过程。
二、Window内部机制
1、WindowManager继承了ViewManager,常用的有三个方法,即创建一个Window并向其添加View、更新Window中的View和删除Window中的View。
这三个方法都是针对view的,说明view是window存在的实体。
public interface WindowManager extends ViewManager
public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
2、每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。
WindowManager的操作接口都是针对View的,说明View才是Window的实体,对Window得访问必须通过WindowManager。
3、PhoneWindow和WindowManagerImpl
(1)Window的具体实现类PhoneWindow
#PhoneWindow:
private ViewRootImpl getViewRootImpl() {
		if (mDecor != null) {
			ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
			if (viewRootImpl != null) {
				return viewRootImpl;
			}
		}
		throw new IllegalStateException("view not added");
	}
(2)WindowManager的具体实现类是WindowManagerImpl,WindowManagerImpl是桥接模式,将所有的操作都委托给windowManagerGlobal实现的。
#WindowManagerImpl
public final class WindowManagerImpl implements WindowManager {
		private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

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

		@Override
		public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
			applyDefaultToken(params);
			mGlobal.updateViewLayout(view, params);
		}
		@Override
		public void removeView(View view) {
			mGlobal.removeView(view, false);
		}

	}
4、WindowManagerGlobal
(1)定义的属性:
#WindowManagerGlobal
//Window所对应的view
private final ArrayList mViews = new ArrayList();
//Window所对应的ViewRootImpl
private final ArrayList mRoots = new ArrayList();
//Window所对应的布局参数
private final ArrayList mParams =
new ArrayList();
//已经调用了removeView,但是还没完成的Window对象
private final ArraySet mDyingViews = new ArraySet();
(2)addView  (Window的添加过程)     
#WindowManagerGlobal                                                                                                                                                 
  • 检查参数是否为null,如果是子Window那么还需要调整一些布局参数
  • 创建ViewRootImpl并将View添加到列表中
  • 通过ViewRootImpl的setView实现view的绘制 ,setView内部通过requestLayout完成异步刷新请求。
public void addView(View view, ViewGroup.LayoutParams params,
                    Display display, Window parentWindow) {
    //检查参数是否为null
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (display == null) {
        throw new IllegalArgumentException("display must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if (parentWindow != null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } else {
        //如果是子view需要调整一些布局参数
        final Context context = view.getContext();
        if (context != null
                && (context.getApplicationInfo().flags
                & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }

    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        ..........   
        //创建ViewRootImpl
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        //将View、ViewRootImpl、LayoutParams加入列表
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }
    // do this last because it fires off messages to start doing things
    try {
        //通过ViewRootImpl的setView实现view的绘制
        root.setView(view, wparams, panelParentView);                                                                                                 
    } catch (RuntimeException e) {
        // BadTokenException or InvalidDisplayException, clean up.
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
        throw e;
    }
}
#ViewRootImpl
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            ......
            //requestLayout完成异步刷新请求
            requestLayout();
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                mInputChannel = new InputChannel();
            }
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
                //接着通过WindowSession完成Window的添加过程。WindowSession类型为IWindowSession,是一个                  //Binder对象,实现类是Session,所以Window的添加过程是一次IPC调用。
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mInputChannel);
            } catch (RemoteException e) {
                mAdded = false;
                mView = null;
                mAttachInfo.mRootView = null;
                mInputChannel = null;
                mFallbackEventHandler.setView(null);
                unscheduleTraversals();
                setAccessibilityFocus(null, null);
                throw new RuntimeException("Adding window failed", e);
            } finally {
                if (restore) {
                    attrs.restore();
                }
            }

            ..........
        }
    }
}

@Override
	public void requestLayout() {
		if (!mHandlingLayoutInLayoutRequest) {
			checkThread();
			mLayoutRequested = true;
			scheduleTraversals(); //View绘制的入口
		}
	}
IWindowSession实现类Session
#Session:
final class Session extends IWindowSession.Stub
		implements IBinder.DeathRecipient {
	final WindowManagerService mService;
	@Override
	public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
							int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
							Rect outOutsets, InputChannel outInputChannel) {
		return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
				outContentInsets, outStableInsets, outOutsets, outInputChannel);
	}
}
最终的Window添加的过程交给WindowManagerService方法处理

Window添加过程:
WindowManagerImpl(实现WindowManager)—>WindowManagerGlobal(检查参数,创建ViewRootImpl将View添加到列表中)—>ViewRootImpl(更新界面)—>IWindowSession(Binder对象)—>Session(具体实现)—>
WindowManagerService(完成Window的添加)

(3)removeView (Window删除过程)
WindowManager提供两种删除接口,removeView(异步删除)和removeViewImmediate(同步删除)
#WindowManagerGlobal
public void removeView(View view, boolean immediate) {
	if (view == null) {
		throw new IllegalArgumentException("view must not be null");
	}

	synchronized (mLock) {
//查找需要删除view的索引
		int index = findViewLocked(view, true);
		View curView = mRoots.get(index).getView();
		removeViewLocked(index, immediate);
		if (curView == view) {
			return;
		}

		throw new IllegalStateException("Calling with view " + view
				+ " but the ViewAncestor is attached to " + curView);
	}
}

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

    if (view != null) {
        InputMethodManager imm = InputMethodManager.getInstance();
        if (imm != null) {
            imm.windowDismissed(mViews.get(index).getWindowToken());
        }
    }
    boolean deferred = root.die(immediate);
    if (view != null) {
        view.assignParent(null);
        if (deferred) {
            mDyingViews.add(view);
        }
    }
}
主要是调用的ViewRootImpl的die()方法进行操作
#ViewRootImpl:
boolean die(boolean immediate) {
// Make sure we do execute immediately if we are in the middle of a traversal or the damage
// done by dispatchDetachedFromWindow will cause havoc on return.
	if (immediate && !mIsInTraversal) {
		doDie();
		return false;
	}

	if (!mIsDrawing) {
		destroyHardwareRenderer();
	} else {
		Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
				" window=" + this + ", title=" + mWindowAttributes.getTitle());
	}
	mHandler.sendEmptyMessage(MSG_DIE);
	return true;
}
异步删除通过Handler发送了MSG_DIE的消息,没有真正删除。只是将view添加到一个待删除的列表mDyingViews中。(同步删除直接调用doDie()方法)
通过Handler接收到发送的消息后,执行doDie方法。
#ViewRootImpl:
void doDie() {
	checkThread();
	if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
	synchronized (this) {
		if (mRemoved) {
			return;
		}
		mRemoved = true;
		if (mAdded) {
			dispatchDetachedFromWindow(); //内部调用view的dispatchDetachedFromWindow方法
		}

		if (mAdded && !mFirst) {
			destroyHardwareRenderer();

			if (mView != null) {
				int viewVisibility = mView.getVisibility();
				boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
				if (mWindowAttributesChanged || viewVisibilityChanged) {
// If layout params have been changed, first give them
// to the window manager to make sure it has the correct
// animation info.
					try {
						if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
								& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
							mWindowSession.finishDrawing(mWindow);
						}
					} catch (RemoteException e) {
					}
				}

				mSurface.release();
			}
		}

		mAdded = false;
	}
	WindowManagerGlobal.getInstance().doRemoveView(this);//调用WindowManagerGlobal刷新数据
}

void dispatchDetachedFromWindow() {
   if (mView != null && mView.mAttachInfo != null) {
      mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
      //调用View的dispatchDetachedFromWindow方法
      mView.dispatchDetachedFromWindow();
   }

   mAccessibilityInteractionConnectionManager.ensureNoConnection();
   mAccessibilityManager.removeAccessibilityStateChangeListener(
         mAccessibilityInteractionConnectionManager);
   mAccessibilityManager.removeHighTextContrastStateChangeListener(
         mHighContrastTextManager);
   removeSendWindowContentChangedCallback();

   destroyHardwareRenderer();

   setAccessibilityFocus(null, null);

   mView.assignParent(null);
   mView = null;
   mAttachInfo.mRootView = null;

   mSurface.release();

   if (mInputQueueCallback != null && mInputQueue != null) {
      mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
      mInputQueue.dispose();
      mInputQueueCallback = null;
      mInputQueue = null;
   }
   if (mInputEventReceiver != null) {
      mInputEventReceiver.dispose();
      mInputEventReceiver = null;
   }
   try {
      //调用到了mWindowSession是个Binder,最后调用是Session的remove方法。这是一个IPC过程
      mWindowSession.remove(mWindow);
   } catch (RemoteException e) {
   }

   // Dispose the input channel after removing the window so the Window Manager
   // doesn't interpret the input channel being closed as an abnormal termination.
   if (mInputChannel != null) {
      mInputChannel.dispose();
      mInputChannel = null;
   }

   mDisplayManager.unregisterDisplayListener(mDisplayListener);

   unscheduleTraversals();
}
#View
void dispatchDetachedFromWindow() {
	AttachInfo info = mAttachInfo;
	if (info != null) {
		int vis = info.mWindowVisibility;
		if (vis != GONE) {
			onWindowVisibilityChanged(GONE);
		}
	}

	onDetachedFromWindow();//view从Window移除时调用,做资源回收的工作
	onDetachedFromWindowInternal();

	.....
}
doDie和dispatchDetachedFromWindow的主要工作:
  • 垃圾回收的工作,比如清除数据和消息,移除回调。
  • 通过Session的remove方法删除Window,mWindowSession.remove(mWindow),这同样是一个IPC过程,最终会调用WindowManagerService的removeWindow方法。
  • 调用View的dispatchDetachedFromWindow方法,在内部调用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。
  • 调用WindowManagerGlobal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews,需要将当前Window所关联的这三类对象从列表中删除。
Window删除过程:
WindowManagerImpl(实现WindowManager)—>WindowManagerGlobal(将View添加到待删除的列表)—>ViewRootImpl(调用doDie)—>IWindowSession(Binder对象)—>Session(具体实现)—>
WindowManagerService(调用removeWindow)—>View(调用dispatchDetachedFromWindow回收资源等工作)—>WindowManagerGlobal(调用doRemoveView刷新数据)

(3)updateViewLayout
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
    //更新View的LayoutParams
    view.setLayoutParams(wparams);

    synchronized (mLock) {
        //查找控件索引
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots.get(index);
        //移除之前的LayoutParams
        mParams.remove(index);
        //新增LayoutParams
        mParams.add(index, wparams);
        //给ViewRootImpl更新
        root.setLayoutParams(wparams, false);
    }
}
调用View的setLayoutParams来更新View的LayoutParams
调用ViewRootImpl的setLayoutParams来更新ViewRootImpl的layoutParams 

在setLayoutParams方法中调用scheduleTraversals方法
#ViewRootImpl
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}
对View重新布局,包括view重新测量、布局、重绘。
ViewRootImpl通过WindowSession的relayout方法来更新Window视图,最终通过WindowManagerService的relayoutWindow()来实现,这也是IPC过程。

Window更新过程:
WindowManagerImpl(实现WindowManager)—>WindowManagerGlobal—>View(调用setLayoutParams)—>ViewRootImpl(调用setLayoutParams)—>IWindowSession(Binder对象,调用relayout)—>Session(具体实现)—>WindowManagerService(调用relayoutWindow方法


注:开发艺术探索笔记整理

















 
   

你可能感兴趣的:(Window和WindowManager(一))