Window创建过程

1.几个重要类型

1.W:Activity向WMS提供的IPC接口

每个Activity创建时都会通过ViewRootImpl创建并持有一个W对象(extend IWindow),它也是一个Binder对象,向WMS提供服务;
WMS通过该Activity的WindowState持有W的代理对象从而间接调用Activity;

2.WindowSession: WMS向Activity提供的IPC接口

WMS的WindowState中持有session extends IWindowSession 它也是一个Binder对象向Application进程提供服务;
每个Activity需要调用WMS的方法都要通过session对象的代理;

3.其他:

WindowManagerService:系统单例,提供统一的Window管理;
Window:抽象,实现类是PhoneWindow,不可直接访问;每个Window对应一个View和一个ViewRootImpl
WindowManager:是一个接口,实现类是WindowManagerImpl,访问Window只能通过WindowManager;
WindowManagerGlobal:WindowManagerImpl的实际处理逻辑都委托给该类处理;
WindowState:每个Window实体都对应着一个WindowState,这些WindowState存储在WMS的一张Map中
WindowToken
1.一个 WindowToken 就代表着一个应用组件,应用组件包括Activity等,Windowtoken和Window不是一一对应的关系,在WMS中属于同一 WindowToken 的做统一处理;
2.同时WindowToken 具有令牌的作用,应用组件在添加 Window 时都需要提供一个有效的 WindowToken 以表明自己的身份(系统窗口除外,WMS 会自动为该系统窗口隐式的创建 WindowToken)
AppWindowToken:WindowToken的子类,代表Activity的窗口令牌。

在这里插入图片描述AMS和WMS中Token的整理参考:Token

2.Activity添加后创建DecorView的过程:

1.Activity执行attach时创建Window:
Activity.attach在创建新的Activity之后,onCreate之前执行,具体参考Activity启动过程

void attach() {
	...
	mWindow = PolicyManager.makeNewWindow(this);			//return new PhoneWindow;
}

2.setContentView:

public void setContentView(int layoutResId) {
	getWindow().setContentView(layoutResId);
}

PhoneWindow#setContentView:

@Override
public void setContentView(int layoutResID) {
	//DecorView默认有两个子View,一个是Title,一个是Content
	//这里的mContentParent是PhoneWindow的一个成员变量,代表DecorView的Content
    if (mContentParent == null) { // 1
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
	//加载layoutResID这个资源到mContentParent上
    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        mLayoutInflater.inflate(layoutResID, mContentParent); // 2
    }
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

3.PhoneWindow新建一个DecorView

//className = PhoneWindow#installDecor:
private void installDecor() {
	//mDecor就是PhoneWindow的成员变量DecorView
	if(mDecor == null){
		DecorView = new DecorView();
		View view = mLayoutInflater.inflate(layoutResId);
		DecorView.addView(view);
	}
	//mDecor就是PhoneWindow的成员变量DecorView
	if (mContentParent == null) {
		//这个方法根据有无Title等属性向mDecor中添加Title布局和Content布局,并把Content返回赋给mContentParent 
        mContentParent = generateLayout(mDecor); 
    }
}

4.回调Activity的onContentChanged方法通知View已经初始化完毕;(此时Window和DecorView还没有建立联系)

	acitivty.onContentChanged();

5.通过WMS把DecorView添加至Window:
在Activity的Resume阶段会执行:

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) { 
    //...
    ActivityClientRecord r = performResumeActivity(token, clearHide); // 这里面会调用到onResume()方法

    if (r != null) {
        final Activity a = r.activity;

        //...
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow(); // 获得window对象
            View decor = r.window.getDecorView(); // 获得DecorView对象
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager(); // 获得windowManager对象
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (a.mVisibleFromClient) {
                a.mWindowAdded = true;
                // 调用addView方法会创建ViewRootImpl 
                wm.addView(decor, l); 
            }
            //...
        }
    }
}

可以看到ViewRootImpl是在Activity启动的resume前创建的,至此,Activity创建后添加DecorView的过程结束

这里调用了WindowManager.add()方法,后面的逻辑就和添加普通的Window一致,后面将通过添加普通Window的逻辑介绍WindowManager

3.添加普通的Window

除了Activity创建时添加DecorView会向WMS发出请求,添加普通的Window(如Dialog和Toast)也会与WMS发生一些交互,它们都是以Window的形式添加的,但添加的流程与Activity窗口的过程有所不同。

1. 比如我们通过WindowManager在屏幕上添加一个Button,分析其添加流程:

	Button button = new Button(this);
    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        		ViewGroup.LayoutParams.WRAP_CONTENT,
        		ViewGroup.LayoutParams.WRAP_CONTENT);
    params.x = 100;
    params.y = 100;
    getWindowManager().addView(button,params);

2.WindowManager是一个接口,它的实现类是WindowManagerImpl
它们的关系如下,可以类比Context的类结构:

	interface WindowManager {
		public void addView(View view, ViewGroup.LayoutParams params);
		public void updateViewLayout(View view, ViewGroup.LayoutParams params);
		public void removeView(View view);
	}
		
	class WindowManagerGlobal implements WindowManager{
		...
	}
	
	public class WindowManagerImpl implements WindowManager {
		private WindowManagerGlobal mGlobal;				
		...
	}

WindowManagerImpl的addView方法:

public final class WindowManagerImpl implements WindowManager {    
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ...
    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
}

3.在WindowManagerGlobal中新建ViewRootImpl
通过WindowManagerGlobal的addView方法添加窗口:

class WindowManagerGlobal{
	//当前进程中所有Window对应的View;
	private final ArrayList<View> mViews = new ArrayList<View>();
	//当前进程中所有Window对应的ViewRootImpl;
	private final ArrayList<ViewRootImpl> mRoots= new ArrayList<ViewRootImpl>();
	//当前进程中所有Window对应的View的LayoutParams;
	private final ArrayList<WindowManager.LayoutParams> mViews = new ArrayList<View>();
	private final ArraySet<View> mDyingViewViews = new ArraySet<View>();
	
	public void scheduleTraversals()        //完成Measuer,Layout,Draw 三个过程
	
	public void addView(View view,LayoutParams params) {
		ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
        	//WindowManagerGlobal添加View时为该View创建了ViewRoolImpl;
            root = new ViewRootImpl(view.getContext(), display); 
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
        //通过跨进程的方式向WMS(WindowManagerService)发起一个调用,从而将DecorView最终添加到Window上
        //在这个过程中,ViewRootImpl、DecorView和WMS会彼此关联,参考ViewRootImpl类的结构
        root.setView(view, wparams, panelParentView);
	}
}

ViewRootImpl.setView方法通过WindowSession将添加DecorView的请求发送给WMS

//className = ViewRootImpl
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
      res = mWindowSession.addToDisplay(mWindow, mWindowAttributes, ...);      
} 

4.在新建ViewRootImpl时创建W:
在Client端,ViewRootImpl创建时会创建一个W对象和IWindowSession 对象:

public ViewRootImpl(Context context, Display display) {
	//可以看到每个窗口都对应一个W对象,后面可以发现它在WMS端将作为这个Window的唯一标识
    mWindow = new W(this);
    mWindowSession = WindowManagerGlobal.getWindowSession();
}

创建IWindowSession:

//className = WindowMangagerGlobal
public static IWindowSession getWindowSession() {
      synchronized (WindowManagerGlobal.class) {
          if (sWindowSession == null) {
              InputMethodManager imm = InputMethodManager.getInstance();
                  IWindowManager windowManager = getWindowManagerService();
                  sWindowSession = windowManager.openSession(imm, ...);		//跨进程调用
          }
          return sWindowSession;
      }
  }
//className = WindowManagerService
public IWindowSession openSession(InputMethodManager imm) {
        return new Session(this, imm, ...);
}

5.然后通过viewRootImpl.scheduleTraversals对View进行绘制;

public void requestLayout(){
	scheduleTraversals();
}

再调用WindowSession代理调用WMS的addToDisplay()去添加一个窗口,WMS中为每一个窗口保留一个Session;

	res = wWindowSession.addToDisPlay(mWindow,attr, ...) //这里只传递了Window,并没有把View传给WMS

WindowSession:

public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, ...) {
     return mService.addWindow(this, window, attrs, ...); 				//Call WMS
}

6.WMS对新的Window进行处理:

class WindowManagerService {
	//这里的binder类型的键值就是这个Window的W对象
	private Map<Binder,WindowState> mWindowMap;				
	
	public int addWindow(Session session, IWindow client, WindowManager.LayoutParams attrs, ...) {
		  //为添加的Window创建一个WindowState 
          final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
    
          mPolicy.adjustWindowParamsLw(win.mAttrs);
          win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
          res = mPolicy.prepareAddWindowLw(win, attrs);
          if (res != WindowManagerGlobal.ADD_OKAY) {
              return res;
          }
          win.attach();
          //将这个新的Window记录在map中
          mWindowMap.put(client.asBinder(), win);
    }
}
4.附一些类的描述:

WindowManagerService描述:

class WindowManagerService IWindowManager.Stub
			 implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
 	final IActivityManager mActivityManager;
 	final InputManagerService mInputManager;

 	final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<>();
 	//Key值为appToken,这个map的规模和Activity数量相同
 	final HashMap<IBinder, AppWindowToken> mApptokenMap = new HashMap();
 	//Key值为IWindow,由于每个Window都对应一个IWindow值,所以这个Map的大小和Window
	final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
 	
 	@Override	//这里根据token来创建WindowToken并保存在map中;
   	public void addWindowToken(IBinder token, int type) {
       //省略检查android.Manifest.permission.MANAGE_APP_TOKENS权限;
       synchronized(mWindowMap) {
           WindowToken wtoken = mTokenMap.get(token);
           if (wtoken != null) {
               return;
           }
           wtoken = new WindowToken(this, token, type, true);
           mTokenMap.put(token, wtoken);
       }
    }
	
	//这个方法是AMS调用的,AMS在创建完一个新的ActivityRecord之后会调用WMS的这个方法,即向WMS注册此Activity
	//这里的token就是ActivityRecord中的appToken;
	public void addAppToken(IApplicationToken token, ...) {
        ...... 
        synchronized(mWindowMap) {
            AppWindowToken atoken = findAppWindowToken(token.asBinder());
            if (atoken != null) {
                return;
            }
            atoken = new AppWindowToken(this, token, voiceInteraction);
            mApptokenMap.put(token.asBinder(), atoken);
       }
	}
   
   //WMS向Client提供的添加Window的接口
   public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
            
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);
            win.attach();
            mWindowMap.put(client.asBinder(), win);
            win.mToken.addWindow(win);
    }
   
}

ViewRootImpl 描述:

public class ViewRootImpl extends AbsViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    static IWindowSession sWindowSession;
    final W mWindow;
    View mView;  
 
    public ViewRootImpl(Context context, Display display) {
        mWindow = new W(this, context);
    }
 
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
           res = mWindowSession.addToDisplay(mWindow, mWindowAttributes, ...);      
    } 
}

W描述:

static class W extends IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;

        W(ViewRootImpl viewAncestor) {
            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
            mWindowSession = viewAncestor.mWindowSession;
        }
}

WindowState描述:

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState parentWindow, WindowManager.LayoutParams a, ...) {
        mService = service;
        mSession = s;
        mClient = c;
        mToken = token;
        mAppToken = mToken.asAppWindowToken();
    }

这里addWindowToken中所需要的token就是在AMS中创建的对应与Activity的token

WindowToken描述:

class WindowToken extends WindowContainer<WindowState> {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowToken" : TAG_WM;

    protected final WindowManagerService mService;

    final IBinder token;

    final int windowType;    

    protected DisplayContent mDisplayContent;

    WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
            DisplayContent dc, boolean ownerCanManageAppTokens) {
        mService = service;
        token = _token;
        windowType = type;
        mPersistOnEmpty = persistOnEmpty;
        mOwnerCanManageAppTokens = ownerCanManageAppTokens;
        onDisplayChanged(dc);
    }

    void onDisplayChanged(DisplayContent dc) {
        dc.reParentWindowToken(this);
        mDisplayContent = dc;
        SurfaceControl.openTransaction();
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final WindowState win = mChildren.get(i);
            win.mWinAnimator.updateLayerStackInTransaction();
        }
        SurfaceControl.closeTransaction();

        super.onDisplayChanged(dc);
    }
}

WindowToken会在WindowManagerService.addWindowToken中创建

ViewManager描述:

public interface ViewManager {
	public void addView(View view, ViewGroup.LayoutParams params);
	public void updateViewLayout(View view, ViewGroup.LayoutParams params);
	public void removeView(View view);
}
总结:

Activity会在attach时为新的Activity创建Window;
在setContentView方法中,创建DecorView,并把layout资源文件解析成View添加到DecorView中;
在resume阶段把DecorView通过windowManager.addView的方式添加到Window中;
WindowManagerImpl通过WindowManagerGlobal来addView,这时为待添加的View创建了ViewRootImpl
ViewRootImpl创建时内部创建了WindowSession,ViewRootImpl添加View实际上是与WMS的一次跨进程通信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值