Window的简单使用
public void addView(View view){
mFloatingButton = new Button(this);
mFloatingButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
mWindowParams.x = (int) event.getRawX();
mWindowParams.y = (int) event.getRawY();
//window更新操作
mWindowManager.updateViewLayout(mFloatingButton,mWindowParams);
break;
default:
break;
}
return true;
}
});
mFloatingButton.setText("bottom");
mWindowParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT
,WindowManager.LayoutParams.WRAP_CONTENT,0,0, PixelFormat.TRANSPARENT);
mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
mWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
mWindowParams.x = 100;
mWindowParams.y = 300;
//8.0以上使用TYPE_APPLICATION_OVERLAY 8.0以下使用Error
mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY ;
//新增window操作
mWindowManager.addView(mFloatingButton,mWindowParams);
}
//移出window操作
public void removeView(View view){
if (null != mWindowManager){
mWindowManager.removeView(mFloatingButton);
}
}
应用Window层级分为1-99 ,子window层级范围是1000-1999,系统window层级范围是2000-2999.
通过一下代码设置:
mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY ;
需要配置系统弹窗权限:
Window内部机制
addView方法
通过下面代码获取到WindowManager对象。
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager是接口类,继承ViewManager接口。提供addView updateViewLayout removeView方法。实现类为WindowManagerImpl。
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
所以我们看一下WindowManagerImpl的相关操作方法:
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), 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);
}
可以发现WindowManagerImpl并没有直接实现Window的相关操作方法,而是通过WindowManagerGlobal类来处理的。WindowManagerrGlobal的addView主要有以下几个操作:
1.检测参数是否合法,如果是子Window则需要调整布局参数,不是则针对是否硬件加速做处理
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 {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
2.观测系统属性变化
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
3.判断添加的view是否是之前删除的view,如果是立即调用dodie方法删除
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
4.创建ViewRootImpl并将View添加到列表中
在WindowManagerGlobal中有几个重要的列表:
private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList();
private final ArrayList mParams =
new ArrayList();
private final ArraySet mDyingViews = new ArraySet();
其中mViews存储的是所以Window对应的view,mRoots存储的是Window对应的ViewRootImpl,mParams存储的是Window对应的布局参数,mDyingViews存储的是正在被删除的View对象,也就是那些调用了removeView方法但是删除操作还没完成的Window对象。在addView方法中将Window一系列对象存储到列表中:
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
5.通过ViewRootImpl更新界面并完成Window的添加过程:
root.setView(view, wparams, panelParentView);
通过ViewRootImpl.setView方法来完成。在setView内部通过requestLayout来完成异步刷新请求。下面的代码中scheduleTraversals实际上是view绘制的入口:
public void requestLayout() {
f (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
然后通过WindowSession完成Window的添加过程。
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
setFrame(mTmpFrame);
上面的代码中,mWindowSession类型是IWindowSession,它是一个binder对象,实现类是Session,也就是说Window添加过程其实是一次IPC的过程。
Session内部通过WindowManagerService来实现Window的添加代码如下:
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
这样一来,Window添加请求就交