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}
----


 

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