android 各種view的顯示及隱藏流程

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


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章