通過網上查資料,自己看源碼及加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}
----