通过网上查资料,自己看源码及加log打印调试得出的结论如下
1.android所有的可视的界面可以分为activity,dialog,poupwindow,toast,windowview
2.所有的view在显示和隐藏时都会走系统的统一的接口,并且在系统的接口中是加处理是可以拿到view的宽高,及所在的位置坐标值
3.所有view在显示前都会执行WindowManager.addView(View view, ViewGroup.LayoutParams params),隐藏的时候都会走WindowManager.removeView(View view)
------
具体调试代码及log分析如下
1.系统addview的流程如下
WindowManager.addView(View view, ViewGroup.LayoutParams params)
-----
frameworks\base\core\java\android\view\ViewManager.java
public interface ViewManager{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
-------
frameworks\base\core\java\android\view\WindowManagerImpl.java
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);
}
----------
frameworks\base\core\java\android\view\WindowManagerGlobal.java
WindowManager.LayoutParams参数说明
type:用于区分所有view的类型,应用Window(及activity,dialog类)取值范围为1~99,子Window(即PoupWindow类)取值范围为1000~1999,
系统window(即windowview类型)
x,y:所在坐标值,实际受grivity参数影响
grivity:布局位置属性,如Gravity.LEFT | Gravity.TOP,Gravity.RIGHT | Gravity.TOP,grivity和x,y共同决定view所在屏幕中的位置
width,height:如果不是WindowManager.LayoutParams.WRAP_CONTENT则可以通过此参数拿到view的宽高值,如果是MATCH_PARENT类型则是屏幕的整屏参数值,如果是WRAP_CONTENT参数类型的则需要在view绘制即将完成的时候去拿view的宽高
view.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
int wid = view.getWidth();
int hei = view.getHeight();
return true;
}
});
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window ()parentWindow) {
...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
...
ViewRootImpl root;
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);//mViews 存储的是所有 Window 所对应的 View
mRoots.add(root);//mRoots 存储的是所有 Window 所对应的 ViewRootImpl
mParams.add(wparams);//mParams 存储的是所有 Window 所对应的布局参数
...
root.setView(view, wparams, panelParentView);//View 的绘制过程是由 ViewRootImpl 来完成的,具体是通过setView实现
//按源码的代码解耦逻辑应该是在WindowManagerService中去处理业务逻辑,但是实际WindowManagerService中的接口中拿不到view对象,不好拿view的宽高信息
//实际可在此代码之后拿view的类型,宽高,位置信息
-------
frameworks\base\core\java\android\view\ViewRootImpl.java
final IWindowSession mWindowSession;
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
-------
frameworks\base\services\core\java\com\android\server\wm\Session.java
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);
}
------
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
2.removeview一定会走的接口位置
frameworks\base\core\java\android\view\WindowManagerGlobal.java
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
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);
}
}
3.调试及打印信息
说明:
1.addview打印及代码添加位置为WindowManagerGlobal-addView,view的宽高通过getViewTreeObserver().addOnPreDrawListener获得
removeview打印添加位置为WindowManagerGlobal-removeView
2.打印可以看出view在addview和removeview时对象都是一一对应,不同view的wparams.type是不一样的
1)dialog类型
Log.d(TAG, "dialog");
Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.test);
Window dialogWindow = dialog.getWindow();
dialogWindow.setGravity(Gravity.BOTTOM);
dialogWindow.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = WindowManager.LayoutParams.FILL_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
dialogWindow.setAttributes(lp);
dialog.show();
-------
09-05 04:32:49.485 : dialog
09-05 04:32:49.534 : addView wid=1920,hei=83,wparams.x=0,wparams.y=0,wparams.type=2,wparams.gravity=80,wparams.flags=25165826,view=com.android.internal.policy.PhoneWindow$DecorView{37319ee V.E...... R.....ID 0,0-1920,83}
09-05 04:32:53.613 : removeView view=com.android.internal.policy.PhoneWindow$DecorView{37319ee V.E...... R.....I. 0,0-1920,83-}
-----
2)popuwindow
Log.d(TAG, "poupwindow");
View testView0 = getLayoutInflater().inflate(R.layout.test, null);
PopupWindow popupWindow = new PopupWindow(testView0, RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT, true);
//使弹窗相应返回键
ColorDrawable dw = new ColorDrawable(0x00000000);
popupWindow.setBackgroundDrawable(dw);
popupWindow.showAtLocation(testView0, Gravity.CENTER, 0, 0);
----
09-05 04:34:31.163 : poupwindow
09-05 04:34:31.184 : addView wid=203,hei=83,wparams.x=0,wparams.y=0,wparams.type=1000,wparams.gravity=17,wparams.flags=1098907648,view=android.widget.PopupWindow$PopupDecorView{1450e23 V.E...... ......ID 0,0-203,83}
09-05 04:34:32.553 : removeView view=android.widget.PopupWindow$PopupDecorView{1450e23 V.E...... ........ 0,0-203,83}
----
3)alertdialog
Log.d(TAG, "alertdialog");
View testView1 = getLayoutInflater().inflate(R.layout.test, null);
AlertDialog testAlertDialog = new AlertDialog.Builder(this).create();
testAlertDialog.show();
testAlertDialog.getWindow().setContentView(testView1);
----
09-05 04:35:37.155 : alertdialog
09-05 04:35:37.185 : addView wid=1248,hei=131,wparams.x=0,wparams.y=0,wparams.type=2,wparams.gravity=17,wparams.flags=25296898,view=com.android.internal.policy.PhoneWindow$DecorView{13a05 V.E...... R.....ID 0,0-1248,131}
09-05 04:35:38.386 : removeView view=com.android.internal.policy.PhoneWindow$DecorView{13a05 V.E...... R.....I. 0,0-1248,131}
----
4)toast
Log.d(TAG, "toast");
Toast.makeText(getApplicationContext(),"toast test",Toast.LENGTH_SHORT).show();
----
09-05 04:36:49.333 : toast
09-05 04:36:49.368 : addView wid=167,hei=67,wparams.x=0,wparams.y=96,wparams.type=2005,wparams.gravity=81,wparams.flags=16777368,view=android.widget.LinearLayout{21a4bd V.E...... ......ID 0,0-167,67}
09-05 04:36:51.339 : removeView view=android.widget.LinearLayout{21a4bd V.E...... ......I. 0,0-167,67}
----
5)windowview
Log.d(TAG, "windowview");
mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.x = 330;
params.y = 440;
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
params.format = PixelFormat.RGBA_8888;
mTestView=new TestView(getApplicationContext());
mWindowManager.addView(mTestView, params);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.d(TAG, "delay remove windowview");
mWindowManager.removeView(mTestView);
}
},2000);
----
09-05 04:37:35.539 : windowview
09-05 04:37:35.567 : addView wid=203,hei=83,wparams.x=330,wparams.y=440,wparams.type=2003,wparams.gravity=51,wparams.flags=16777216,view=com.xbh.touchtest123.TestView{9576462 V.E...... ......ID 0,0-203,83}
09-05 04:37:37.548 : delay remove windowview
09-05 04:37:37.548 : removeView view=com.xbh.touchtest123.TestView{9576462 V.E...... ......I. 0,0-203,83}
----
6)activity
Log.d(TAG, "activity");
startActivity(new Intent(this,Main2Activity.class));
----
09-05 04:37:49.442 : activity
09-05 04:37:49.524 : addView wid=1920,hei=1080,wparams.x=0,wparams.y=0,wparams.type=1,wparams.gravity=0,wparams.flags=-2122252032,view=com.android.internal.policy.PhoneWindow$DecorView{ad49e99 V.E...... R.....ID 0,0-1920,1080}
09-05 04:37:53.114 : removeView view=com.android.internal.policy.PhoneWindow$DecorView{ad49e99 V.E...... R....... 0,0-1920,1080}
----