Android中Window9问9答.docx
《Android中Window9问9答.docx》由会员分享,可在线阅读,更多相关《Android中Window9问9答.docx(17页珍藏版)》请在冰豆网上搜索。
Android中Window9问9答
AndroidWindow9问9答
1.简述一下window是什么?
在android体系里扮演什么角色?
答:
window就是一个抽象类,他的实现类是phoneWindow。
我们一般通过windowManager来访问window。
就是windowmanager和windowmanagerservice的交互。
此外android中你所有能看到的视图,activity,dialog,toast等都是附加在window上的。
window就是view的直接管理者。
2.如何使用windowmanager添加一个view?
答:
1Buttonbt=newButton(this);
2bt.setText("buttonhere");
3WindowManager.LayoutParamslayoutParams=newWindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,
40,0,PixelFormat.TRANSPARENT);
5layoutParams.flags=WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
6layoutParams.x=300;
7layoutParams.y=300;
8layoutParams.gravity=Gravity.RIGHT|Gravity.TOP;
9getWindowManager().addView(bt,layoutParams);
ViewCode
3.总共有几种window类型?
答:
三种。
应用window,就是activity这种类型。
子window,就是dialog这种,系统类,toast,状态栏就是系统类型window。
每种对对应着层级范围,应用1-99子1000-1999系统2000-2999.层级最大的,就是显示在最顶层的window了。
4.使用系统window需要注意什么?
答:
注意system_alert_window这个权限。
否则要出错
5.尝试简单分析window的添加过程?
答:
即window.addView()函数的执行过程:
1//首先我们要知道windwmanger本身就是一个接口,他的实现是交给WindowManagerImpl来做的。
2publicfinalclassWindowManagerImplimplementsWindowManager{
3
4
5//他的view方法一看,发现也是基本没做实际的addview操作是交给mGlobal来做的
6@Override
7publicvoidaddView(@NonNullViewview,@NonNullViewGroup.LayoutParamsparams){
8applyDefaultToken(params);
9mGlobal.addView(view,params,mDisplay,mParentWindow);
10}
11
12
13//发现这是一个工厂吗,到这里一看就明白了,WindowManagerImpl的实际操作都桥接给了WindowManagerGlobal来处理
14privatefinalWindowManagerGlobalmGlobal=WindowManagerGlobal.getInstance();
15
16//先看一下WindowManagerGlobal的重要变量,注意上面已经分析过了,WindowManagerGlobal本身自己是一个单例,全局唯一,
17//所以下面这些参数list,全局也是唯一的,mViews就是所有window对应的view,mRoots就是所有viewRootImpl,mParams就是这些
18//view的参数,dyingviews就是正在删除的对象,就是那种你调用了remove操作但是remove还没有操作完毕的那些view
19privatefinalArrayListmViews=newArrayList();
20privatefinalArrayListmRoots=newArrayList();
21privatefinalArrayListmParams=
22newArrayList();
23privatefinalArraySetmDyingViews=newArraySet();
24
25
26
27
28//所以我们就看看WindowManagerGlobal源码里的addView是如何实现的
29publicvoidaddView(Viewview,ViewGroup.LayoutParamsparams,
30Displaydisplay,WindowparentWindow){
31if(view==null){
32thrownewIllegalArgumentException("viewmustnotbenull");
33}
34if(display==null){
35thrownewIllegalArgumentException("displaymustnotbenull");
36}
37if(!
(paramsinstanceofWindowManager.LayoutParams)){
38thrownewIllegalArgumentException("ParamsmustbeWindowManager.LayoutParams");
39}
40
41finalWindowManager.LayoutParamswparams=(WindowManager.LayoutParams)params;
42//如果是子window就调整一下参数
43if(parentWindow!
=null){
44parentWindow.adjustLayoutParamsForSubWindow(wparams);
45}else{
46//Ifthere'snoparentandwe'rerunningonLorabove(orinthe
47//systemcontext),assumewewanthardwareacceleration.
48finalContextcontext=view.getContext();
49if(context!
=null
50&&context.getApplicationInfo().targetSdkVersion>=Build.VERSION_CODES.LOLLIPOP){
51wparams.flags|=WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
52}
53}
54
55ViewRootImplroot;
56ViewpanelParentView=null;
57
58synchronized(mLock){
59//Startwatchingforsystempropertychanges.
60if(mSystemPropertyUpdater==null){
61mSystemPropertyUpdater=newRunnable(){
62@Overridepublicvoidrun(){
63synchronized(mLock){
64for(inti=mRoots.size()-1;i>=0;--i){
65mRoots.get(i).loadSystemProperties();
66}
67}
68}
69};
70SystemProperties.addChangeCallback(mSystemPropertyUpdater);
71}
72
73intindex=findViewLocked(view,false);
74if(index>=0){
75if(mDyingViews.contains(view)){
76//Don'twaitforMSG_DIEtomakeit'swaythroughroot'squeue.
77mRoots.get(index).doDie();
78}else{
79thrownewIllegalStateException("View"+view
80+"hasalreadybeenaddedtothewindowmanager.");
81}
82//ThepreviousremoveView()hadnotcompletedexecuting.Nowithas.
83}
84
85//Ifthisisapanelwindow,thenfindthewindowitisbeing
86//attachedtoforfuturereference.
87if(wparams.type>=WindowManager.LayoutParams.FIRST_SUB_WINDOW&&
88wparams.type<=WindowManager.LayoutParams.LAST_SUB_WINDOW){
89finalintcount=mViews.size();
90for(inti=0;i91if(mRoots.get(i).mWindow.asBinder()==wparams.token){
92panelParentView=mViews.get(i);
93}
94}
95}
96
97//这个代码充分说明了每一个window都对应着一个view和一个viewrootIMPL,window本身自己不存在,
98//他的意义就在于管理view,而管理view就要通过windowmanager最终走到windwmanagerglobal这里来完成管理
99root=newViewRootImpl(view.getContext(),display);
100
101view.setLayoutParams(wparams);
102
103mViews.add(view);
104mRoots.add(root);
105mParams.add(wparams);
106}
107
108//dothislastbecauseitfiresoffmessagestostartdoingthings
109try{
110//view的最终绘制是在viewrootimpl里完成的,所以这里view的绘制也是在这个里面完成的
111//我们在viewrootimpl里能找到setview的源码他在这个函数里调用了requetlayout
112root.setView(view,wparams,panelParentView);
113}catch(RuntimeExceptione){
114//BadTokenExceptionorInvalidDisplayException,cleanup.
115synchronized(mLock){
116finalintindex=findViewLocked(view,false);
117if(index>=0){
118removeViewLocked(index,true);
119}
120}
121throwe;
122}
123}
124
125
126//而requestLayout里有scheduleTraversals方法这个就是view绘制的入口处
127publicvoidrequestLayout(){
128if(!
mHandlingLayoutInLayoutRequest){
129checkThread();
130mLayoutRequested=true;
131scheduleTraversals();
132}
133}
134
135//回到前面提到的setView那个函数
136//我们可以看到requestLayout结束以后mWindowSession.addToDisplay就有了这个方法的调用
137//实际上这个方法完成的就是一个window的添加。
138requestLayout();
139if((mWindowAttributes.inputFeatures
140&WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL)==0){
141mInputChannel=newInputChannel();
142}
143try{
144mOrigWindowType=mWindowAttributes.type;
145mAttachInfo.mRecomputeGlobalAttributes=true;
146collectViewAttributes();
147res=mWindowSession.addToDisplay(mWindow,mSeq,mWindowAttributes,
148getHostVisibility(),mDisplay.getDisplayId(),
149mAttachInfo.mContentInsets,mAttachInfo.mStableInsets,mInputChannel);
150
151//然后我们很容易就发现这是一个接口并且代码一看就知道还是一个binder
152//所以实际上添加window的功能就是通过BInder是调用windwmangerservice的方法来完成的
153publicinterfaceIWindowSessionextendsandroid.os.IInterface
154{
155/**Local-sideIPCimplementationstubclass.*/
156publicstaticabstractclassStubextendsandroid.os.Binderimplementsandroid.view.IWindowSession
157{
158privatestaticfinaljava.lang.StringDESCRIPTOR="android.view.IWindowSession";
159/**Constructthestubatattachittotheinterface.*/
160publicStub()
161{
162this.attachInterface(this,DESCRIPTOR);
163}
ViewCode
6.activity的window是如何创建的?
答:
应用类的window创建过程:
1
2//activity的window创建由activityThread的performLaunchActivity方法开始
3privateActivityperformLaunchActivity(ActivityClientRecordr,IntentcustomIntent){
4......
5if(activity!
=null){
6ContextappContext=createBaseContextForActivity(r,activity);
7CharSequencetitle=r.activityInfo.loadLabel(appContext.getPackageManager());
8Configurationconfig=newConfiguration(mCompatConfiguration);
9if(DEBUG_CONFIGURATION)Slog.v(TAG,"Launchingactivity"
10+r.activityInfo.name+"withconfig"+config);
11//其中最主要的就是attach方法注意是调用的activity的attach方法不是activitytherad的
12activity.attach(appContext,this,getInstrumentation(),r.token,
13r.ident,app,r.intent,r.activityInfo,title,r.parent,
14r.embeddedID,r.lastNonConfigurationInstances,config,
15r.referrer,r.voiceInteractor);
16
17......
18
19returnactivity;
20}
21
22
23finalvoidattach(Contextcontext,ActivityThreadaThread,
24Instrumentationinstr,IBindertoken,intident,
25Applicationapplication,Intentintent,ActivityInfoinfo,
26CharSequencetitle,Activityparent,Stringid,
27NonConfigurationInstanceslastNonConfigurationInstances,
28Configurationconfig,Stringreferrer,IVoiceInteractorvoiceInteractor){
29attachBaseContext(context);
30
31mFragments.attachActivity(this,mContainer,null);
32//这里一下就能看出来Acitity的window对象是由PolicyManager的makeNewWindow方法构造出来
33//有兴趣的还可以看一下这里set了很多接口都是我们熟悉的那些方法
34mWindow=PolicyManager.makeNewWindow(this);
35mWindow.setCallback(this);
36mWindow.setOnWindowDismissedCallback(this);
37mWindow.getLayoutInflater().setPrivateFactory(this);
38if(info.softInputMode!
=WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED){
39mWindow.setSoftInputMode(info.softInputMode);
40}
41if(info.uiOptions!
=0){
42mWindow.setUiOptions(info.uiOptions);
43}
44mUiThread=Thread.currentThread();
45
46mMainThread=aThread;
47mInstrumentation=instr;
48mToken=token;
49mIdent=ident;
50mApplication=application;
51mIntent=intent;
52mReferrer=referrer;
53mComponent=intent.getComponent();
54mActivityInfo=info;
55mTitle=title;
56mParent=parent;
57mEmbeddedID=id;
58mLastNonConfigurationInstances=lastNonConfigurationInstances;
59if(voiceInteractor!
=null){
60if(lastNonConfigurationInstances!
=null){
61mVoiceInteractor=lastNonConfigurationInstances.voiceInteractor;
62}else{
63mVoiceInteractor=newVoiceInteractor(voiceInteractor,this,this,
64Looper.myLooper());
65}
66}
67
68mWindow.setWindowManager(
69(WindowManager)context.getSystemService(