通过网上查资料,自己看源码及加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} ----