欢迎使用CSDN-markdown编辑器

Window初探

在启动一个Activity时,会走到ActivityThread的handleLaunchActivity方法

    /**
     * ActivityThread
     */
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent){
        ...
        //初始化WindowManagerGlobal,该类是4.x以后出现的
        WindowManagerGlobal.initialize();
        //生成Activity
        Activity a = performLaunchActivity(r, customIntent);
        if (a != null) {
            ...
            //执行Activity的Resume
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
        }
    }

Step1 WindowManagerGlobal初始化

WindowManagerGlobal在2.3的版本中是没有的,一个应用会有三个数组来管理当前的窗口

分别是List ,List ,List,旧版本中,这三个数组是在WindowManagerImpl中的,而新版本统一由WindowManagerGlobal管理。

/**
*  WindowManagerGlobal
*/

public static void initialize() {
        getWindowManagerService();
 }

public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
              //获取WindowManagerService
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
               }
            }
            return sWindowManagerService;
        }
}
Step2 performLaunchActivity

performLaunchActivity做了以下重要事情

生成Activity

生成或获得Application

生成ContextImpl

调用activity的attach

间接调用activity的onCreate

public final class ActivityThread {  
    ......  

    Instrumentation mInstrumentation;  
    ......  

    private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
        ......  

        ComponentName component = r.intent.getComponent();  
        ......  

        Activity activity = null;  
        try {  
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
            activity = mInstrumentation.newActivity(  
                    cl, component.getClassName(), r.intent);  
            ......  
        } catch (Exception e) {  
            ......  
        }  

        try {  
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);  
            ......  

            if (activity != null) {  
                Context appContext = createBaseContextForActivity(r, activity);//旧版本是ContextImpl appContext = new ContextImpl();  
                ......  
               //旧版本有 appContext.setOuterContext(activity);  新版本在createBaseContextForActivity中
                ......  
                Configuration config = new Configuration(mConfiguration);  
                ......  

                activity.attach(appContext, this, getInstrumentation(), r.token,  
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,  
                        r.embeddedID, r.lastNonConfigurationInstance,  
                        r.lastNonConfigurationChildInstances, config);  
                ......  

                mInstrumentation.callActivityOnCreate(activity, r.state);  

                ......    
            }  

            ......  
        } catch (SuperNotCalledException e) {  
            ......  
        } catch (Exception e) {  
            ......  
        }  

        return activity;  
    }  
}  
Step 3 Activity的Attach
public class Activity extends ContextThemeWrapper    
        implements LayoutInflater.Factory,    
        Window.Callback, KeyEvent.Callback,    
        OnCreateContextMenuListener, ComponentCallbacks {    
    ......     

    private Window mWindow;     
    ......    

    final void attach(Context context, ActivityThread aThread,    
            Instrumentation instr, IBinder token, int ident,    
            Application application, Intent intent, ActivityInfo info,    
            CharSequence title, Activity parent, String id,    
            Object lastNonConfigurationInstance,    
            HashMap<String,Object> lastNonConfigurationChildInstances,    
            Configuration config) {    
        ......    

         mWindow = new PhoneWindow(this);//新版本直接就new了一个phoneWindow,少见,旧版本为PolicyManager.makeNewWindow(this)
        mWindow.setCallback(this);//用于获取Window上得到的Event
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {    
            mWindow.setSoftInputMode(info.softInputMode);    
        }    
        ......    
                mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
      //setWindowManager的第一个参数为WindowManager,旧版本传了空,新版本通过getSystemService获得(获得的是一个WindowManagerImpl),本质是一样的
        mWindow.setWindowManager(null, mToken, mComponent.flattenToString());  
        mWindowManager = mWindow.getWindowManager();  
        ......    

    }    

    ......    
}    

其中PhoneWindow的构造函数非常简单

PhoneWindow继承自Window

public class PhoneWindow extends Window implements MenuBuilder.Callback {  
    ......  

    // This is the top-level view of the window, containing the window decor.  
    private DecorView mDecor;  

    // This is the view in which the window contents are placed. It is either  
    // mDecor itself, or a child of mDecor where the contents go.  
    private ViewGroup mContentParent;  
    ......  

    private LayoutInflater mLayoutInflater;  
    ......  

    public PhoneWindow(Context context) {  
        super(context);  
        mLayoutInflater = LayoutInflater.from(context);  
    }  

    ......  
}  

而其父类Window的构造函数也非常简单

public abstract class Window {  
    ......  

    private final Context mContext;  
    ......  

    public Window(Context context) {  
        mContext = context;  
    }  

    ......  
} 
Step 4 Window.setManager
public abstract class Window {  
    ......  

    private WindowManager mWindowManager;  
    private IBinder mAppToken;  
    private String mAppName;  
    ...... 

   public void setWindowManager(WindowManager wm,
             IBinder appToken, String appName) {
        mAppToken = appToken;
        mAppName = appName;
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }


  /*旧版本的代码
    public void setWindowManager(WindowManager wm,  
            IBinder appToken, String appName) {  
        mAppToken = appToken;  
        mAppName = appName;  
        if (wm == null) {  
            wm = WindowManagerImpl.getDefault();  
        }  
        mWindowManager = new LocalWindowManager(wm);  
    }  
    */

    ......  
}  

传入的三个参数,第一个是一个WindowManager

第二个是appToken,用于知道该Window是与哪个Activity对应的

第三个是Activity的相关的名字。

我们可以看出一个应用中,旧版本中,只有一个WindowManagerImpl,而其他的都是LocalWindowManager,因为ViewRoot,View,WindowParams的列表都是在WindowManagerImpl中,而新版本中,没有了LocalWindowManager,而有了多个WindowManagerImpl,只要确保WindowManagerImpl的成员变量WindowManagerGlobal唯一就好了。

public final class WindowManagerImpl implements WindowManager {
  //新版本添加的,十分重要的一个类
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }
 }
step 5 setContentView

在Activity attach以后,window和windowmanager就已经准备就绪了接下来就可以走Activity的onCreate,并在里面调用setContentView了

public class Activity extends ContextThemeWrapper  
        implements LayoutInflater.Factory,  
        Window.Callback, KeyEvent.Callback,  
        OnCreateContextMenuListener, ComponentCallbacks {  
    ......  

    private Window mWindow;  
    ......  

    public Window getWindow() {  
        return mWindow;  
    }  
    ......  

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

    ......  
}  

这里获得的window是一个phoneWindow的实例,所以调用了phoneWindow的setContentView

public class PhoneWindow extends Window implements MenuBuilder.Callback {  
    ......  

    // This is the view in which the window contents are placed. It is either  
    // mDecor itself, or a child of mDecor where the contents go.  
    private ViewGroup mContentParent; 
    private DecorView mDecor;

    ......  

    @Override  
    public void setContentView(int layoutResID) {  
        if (mContentParent == null) {  
            installDecor();  
        } else {  
            mContentParent.removeAllViews();  
        }  
        mLayoutInflater.inflate(layoutResID, mContentParent);  
        final Callback cb = getCallback();  
        if (cb != null) {  
            cb.onContentChanged();  
        }  
    }  

    ......  

    private void installDecor() {  
        if (mDecor == null) {  
            mDecor = generateDecor();  
            ......  
        }  
        if (mContentParent == null) {  
            mContentParent = generateLayout(mDecor);  
            ...... 
        }  
    }  



}  

phoneWindow中有两个重要的成员变量

mDecor:代表该窗口的界面,包含标题和内容

mContentParent :代表该窗口的内容,对应的是android.R.id.content

而我们自己的view则是mContentParent的一个子View

setContentView做了两件事

1.initDecor 生成一个DecorView,调用generateLayout方法,把窗口装饰View设为mDocor的子View。

窗口装饰的View可以大致理解为一个垂直的LinearLayout,上部分是Title,下部分是Content。

窗口装饰的View是通过xml生成的。有很多种,但区别不大:

R.layout.screen_title

R.layout.screen_simple

R.layout.screen_custom_title等等

但是他们有一个共同的特点,就是包含一个id为content的FrameLayout

2.inflate我们的view,并将该view设为mContentParent的子View

至此,setContentView就完成了。

step 6 handleResumeActivity
public final class ActivityThread {  
    ......  

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {  
        ......  

        ActivityClientRecord r = performResumeActivity(token, clearHide);  

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

            // If the window hasn't yet been added to the window manager,  
            // and this guy didn't finish itself or start another activity,  
            // then go ahead and add the window.  
            boolean willBeVisible = !a.mStartedActivity;  
            if (!willBeVisible) {  
                try {  
                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(  
                            a.getActivityToken());  
                } catch (RemoteException e) {  
                }  
            }  
            if (r.window == null && !a.mFinished && willBeVisible) {  
                r.window = r.activity.getWindow();  
                View decor = r.window.getDecorView();  
                decor.setVisibility(View.INVISIBLE);  
                ViewManager wm = a.getWindowManager();  
                WindowManager.LayoutParams l = r.window.getAttributes();  
                a.mDecor = decor;  
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;  
                ......  
                if (a.mVisibleFromClient) {  
                    a.mWindowAdded = true;  
                    wm.addView(decor, l);  
                }  
            }   

            ......  
        }  

        ......  
    }  

    ......  
}  

这个方法非常简单好理解,最主要的就是调用了WindowManagerImpl的addView方法

step 7 WimdowManagerGlobal 的 addView
public final class WindowManagerImpl implements WindowManager {

    public void addView(@NonNull View view, 
                        @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
}

调用了WindowManagerGlobal的addView。

WindowManagerGlobal

WindowManagerGlobal中有三个List:mViews 、mRoots、mParams

addView的本质就是生成一个ViewRoot,调用ViewRoot的setView。并将View、ViewRoot、Params加入List。


52 public final class WindowManagerGlobal {
114    private final ArrayList<View> mViews = new ArrayList<View>();
115    private final ArrayList<ViewRootImpl> mRoots = 
               new ArrayList<ViewRootImpl>();
116    private final ArrayList<WindowManager.LayoutParams> mParams =
117            new ArrayList<WindowManager.LayoutParams>(); 


204    public void addView(View view, ViewGroup.LayoutParams params,
205            Display display, Window parentWindow) {
206        if (view == null) {
207            throw new IllegalArgumentException("view must not be null");
208        }
209        if (display == null) {
210            throw new IllegalArgumentException("display must not be null");
211        }
212        if (!(params instanceof WindowManager.LayoutParams)) {
213            throw new IllegalArgumentException("Params must be                WindowManager.LayoutParams");
214        }
            //以上为校验
215
216        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
217        if (parentWindow != null) {
218            parentWindow.adjustLayoutParamsForSubWindow(wparams);
219        } else {
220            // If there's no parent and we're running on L or above (or in the
221            // system context), assume we want hardware acceleration.
222            final Context context = view.getContext();
223            if (context != null
224                    && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
225                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
226            }
227        }
228
229        ViewRootImpl root;
230        View panelParentView = null;
231
232        synchronized (mLock) {
233            // Start watching for system property changes.
234            if (mSystemPropertyUpdater == null) {
235                mSystemPropertyUpdater = new Runnable() {
236                    @Override public void More ...run() {
237                        synchronized (mLock) {
238                            for (int i = mRoots.size() - 1; i >= 0; --i) {
239                                mRoots.get(i).loadSystemProperties();
240                            }
241                        }
242                    }
243                };
244                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
245            }
246
247            int index = findViewLocked(view, false);
248            if (index >= 0) {//如果View已经被加入
249                if (mDyingViews.contains(view)) {
250                    // Don't wait for MSG_DIE to make it's way through root's queue.
251                    mRoots.get(index).doDie();
252                } else {
253                    throw new IllegalStateException("View " + view
254                            + " has already been added to the window manager.");
255                }
256                // The previous removeView() had not completed executing. Now it has.
257            }
258
259            // If this is a panel window, then find the window it is being
260            // attached to for future reference.
261            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
262                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
263                final int count = mViews.size();
264                for (int i = 0; i < count; i++) {
265                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
266                        panelParentView = mViews.get(i);
267                    }
268                }
269            }
270             //重点 生成一个ViewRootImpl
271            root = new ViewRootImpl(view.getContext(), display);
272     
273            view.setLayoutParams(wparams);
274             //加入数组
275            mViews.add(view);
276            mRoots.add(root);
277            mParams.add(wparams);
278        }
279
280        // do this last because it fires off messages to start doing things
281        try {
                //重点中的重点,调用root的setView
282            root.setView(view, wparams, panelParentView);
283        } catch (RuntimeException e) {
284            // BadTokenException or InvalidDisplayException, clean up.
285            synchronized (mLock) {
286                final int index = findViewLocked(view, false);
287                if (index >= 0) {
288                    removeViewLocked(index, true);
289                }
290            }
291            throw e;
292        }
293    }
step 8 ViewRootImpl setView

ViewRootImpl 在 低版本叫 ViewRoot

99  public final class More ...ViewRootImpl implements ViewParent,
100         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
140     final Context mContext;
141     final IWindowSession mWindowSession;
154     final WindowManager.LayoutParams mWindowAttributes = 
                              new    WindowManager.LayoutParams();
155 
156     final W mWindow;  //IBinder
162     View mView;
3393    final ViewRootHandler mHandler = new ViewRootHandler();

444     public void setView(View view, 
                            WindowManager.LayoutParams attrs,
                            View panelParentView){
445         synchronized (this) {
446             if (mView == null) {
447                 mView = view;
                    ......
454                 mWindowAttributes.copyFrom(attrs);
455                 ......
508                 if (panelParentView != null) {
509                     mAttachInfo.mPanelParentWindowToken
510                             = panelParentView.getApplicationWindowToken();
511                 }
512                 mAdded = true;
513                 int res; /* = WindowManagerImpl.ADD_OKAY; */
514 
515                 // Schedule the first layout -before- adding to the window
516                 // manager, to make sure we do the relayout before receiving
517                 // any other events from the system.
518                 requestLayout();
519                 if ((mWindowAttributes.inputFeatures
520                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
521                     mInputChannel = new InputChannel();
522                 }
523                 try {
                        ......
527                     res = mWindowSession.addToDisplay(mWindow, 
                                mSeq, mWindowAttributes,
528                             getHostVisibility(), mDisplay.getDisplayId(),
529            mAttachInfo.mContentInsets,  mAttachInfo.mStableInsets,    mInputChannel);
530                 } catch (RemoteException e) {
531                     mAdded = false;
                        ......
538                     throw new RuntimeException("Adding window failed", e);
539                 } finally {
540                     if (restore) {
541                         attrs.restore();
542                     }
543                 }
544 
                    ......
615                 view.assignParent(this);
                    ......
645     }



   }

ViewRoot类的成员函数setView执行两个操作:

       1. 调用ViewRoot类的另外一个成员函数requestLayout来请求对应用程序窗口视图的UI作第一次布局。

       2. 调用ViewRoot类的静态成员变量sWindowSession所描述的一个类型为Session的Binder代理对象的成员函数add来请求WindowManagerService增加一个WindowState对象,以便可以用来描述当前正在处理的一个ViewRoot所关联的一个应用程序窗口。

到这里,客户端部分就结束了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值