1.简述一下window是什么?在android体系里 扮演什么角色?

答:window就是一个抽象类,他的实现类是phoneWindow。我们一般通过windowManager 来访问window。就是windowmanager 和windowmanagerservice的交互。

此外 android中 你所有能看到的视图,activity,dialog,toast等 都是附加在window上的。window就是view的直接管理者。

2.如何使用windowmanager添加一个view?

答:

1  Button bt = new Button(this);2         bt.setText("button here");3         WindowManager.LayoutParams layoutParams = newWindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,4                 0, 0, PixelFormat.TRANSPARENT);5         layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;6         layoutParams.x = 300;7         layoutParams.y = 300;8         layoutParams.gravity = Gravity.RIGHT |Gravity.TOP;9         getWindowManager().addView(bt, layoutParams);

View Code

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 来做的。
2 public final class WindowManagerImpl implementsWindowManager {3
4
5 //他的view方法 一看,发现也是基本没做实际的addview操作 是交给mGlobal来做的
6 @Override7     public voidaddView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {8 applyDefaultToken(params);9 mGlobal.addView(view, params, mDisplay, mParentWindow);10 }11
12
13 //发现这是一个工厂吗,到这里一看就明白了,WindowManagerImpl的实际操作 都桥接给了WindowManagerGlobal来处理
14 private final WindowManagerGlobal mGlobal =WindowManagerGlobal.getInstance();15
16 //先看一下WindowManagerGlobal的 重要变量,注意上面已经分析过了,WindowManagerGlobal本身自己是一个单例,全局唯一,17 //所以下面这些参数list ,全局也是唯一的,mViews 就是所有window对应的view,mRoots就是所有viewRootImpl,mParams就是这些18 //view的参数,dyingviews 就是正在删除的对象,就是那种你调用了remove操作 但是remove还没有操作完毕的那些view
19  private final ArrayList<View> mViews = new ArrayList<View>();20     private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();21     private final ArrayList<WindowManager.LayoutParams> mParams =
22             new ArrayList<WindowManager.LayoutParams>();23     private final ArraySet<View> mDyingViews = new ArraySet<View>();24
25
26
27
28 //所以 我们就看看WindowManagerGlobal源码里的addView是如何实现的
29 public voidaddView(View view, ViewGroup.LayoutParams params,30 Display display, Window parentWindow) {31         if (view == null) {32             throw new IllegalArgumentException("view must not be null");33 }34         if (display == null) {35             throw new IllegalArgumentException("display must not be null");36 }37         if (!(params instanceofWindowManager.LayoutParams)) {38             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");39 }40
41         final WindowManager.LayoutParams wparams =(WindowManager.LayoutParams)params;42         //如果是子window 就调整一下参数
43         if (parentWindow != null) {44 parentWindow.adjustLayoutParamsForSubWindow(wparams);45         } else{46             //If there's no parent and we're running on L or above (or in the47             //system context), assume we want hardware acceleration.
48             final Context context =view.getContext();49             if (context != null
50                     && context.getApplicationInfo().targetSdkVersion >=Build.VERSION_CODES.LOLLIPOP) {51                 wparams.flags |=WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;52 }53 }54
55 ViewRootImpl root;56         View panelParentView = null;57
58         synchronized(mLock) {59             //Start watching for system property changes.
60             if (mSystemPropertyUpdater == null) {61                 mSystemPropertyUpdater = newRunnable() {62                     @Override public voidrun() {63                         synchronized(mLock) {64                             for (int i = mRoots.size() - 1; i >= 0; --i) {65 mRoots.get(i).loadSystemProperties();66 }67 }68 }69 };70 SystemProperties.addChangeCallback(mSystemPropertyUpdater);71 }72
73             int index = findViewLocked(view, false);74             if (index >= 0) {75                 if(mDyingViews.contains(view)) {76                     //Don't wait for MSG_DIE to make it's way through root's queue.
77 mRoots.get(index).doDie();78                 } else{79                     throw new IllegalStateException("View " +view80                             + " has already been added to the window manager.");81 }82                 //The previous removeView() had not completed executing. Now it has.
83 }84
85             //If this is a panel window, then find the window it is being86             //attached to for future reference.
87             if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
88                     wparams.type <=WindowManager.LayoutParams.LAST_SUB_WINDOW) {89                 final int count =mViews.size();90                 for (int i = 0; i < count; i++) {91                     if (mRoots.get(i).mWindow.asBinder() ==wparams.token) {92                         panelParentView =mViews.get(i);93 }94 }95 }96
97             //这个代码充分说明了每一个window都对应着一个view 和一个viewrootIMPL,window本身自己不存在,98             //他的意义就在于管理view,而管理view 就要通过windowmanager 最终走到windwmanagerglobal这里来完成管理
99             root = newViewRootImpl(view.getContext(), display);100
101 view.setLayoutParams(wparams);102
103 mViews.add(view);104 mRoots.add(root);105 mParams.add(wparams);106 }107
108         //do this last because it fires off messages to start doing things
109         try{110             //view的最终绘制 是在viewrootimpl里完成的,所以这里view的绘制也是在这个里面完成的111             //我们在viewrootimpl里能找到setview的源码 他在这个函数里调用了requetlayout
112 root.setView(view, wparams, panelParentView);113         } catch(RuntimeException e) {114             //BadTokenException or InvalidDisplayException, clean up.
115             synchronized(mLock) {116                 final int index = findViewLocked(view, false);117                 if (index >= 0) {118                     removeViewLocked(index, true);119 }120 }121             throwe;122 }123 }124
125
126     //而requestLayout里有scheduleTraversals方法 这个就是view绘制的入口处
127     public voidrequestLayout() {128         if (!mHandlingLayoutInLayoutRequest) {129 checkThread();130             mLayoutRequested = true;131 scheduleTraversals();132 }133 }134
135     //回到前面提到的setView那个函数136     //我们可以看到requestLayout 结束以后 mWindowSession.addToDisplay 就有了这个方法的调用137     //实际上这个方法 完成的就是一个window的添加。
138 requestLayout();139     if((mWindowAttributes.inputFeatures140                          & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {141                     mInputChannel = newInputChannel();142 }143     try{144                     mOrigWindowType =mWindowAttributes.type;145                     mAttachInfo.mRecomputeGlobalAttributes = true;146 collectViewAttributes();147                     res =mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,148 getHostVisibility(), mDisplay.getDisplayId(),149 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);150
151     //然后我们很容易就发现这是一个接口 并且代码一看就知道 还是一个binder152     //所以实际上添加window的功能 就是通过BInder 是调用windwmangerservice的方法 来完成的
153 public interface IWindowSession extendsandroid.os.IInterface154 {155 /**Local-side IPC implementation stub class.*/
156 public static abstract class Stub extends android.os.Binder implementsandroid.view.IWindowSession157 {158 private static final java.lang.String DESCRIPTOR = "android.view.IWindowSession";159 /**Construct the stub at attach it to the interface.*/
160 publicStub()161 {162 this.attachInterface(this, DESCRIPTOR);163 }

View Code

6.activity的window是如何创建的?

答:应用类的window创建过程:

1
2 //activity的window创建 由activityThread的performLaunchActivity 方法开始
3  privateActivity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {4 ......5             if (activity != null) {6                 Context appContext =createBaseContextForActivity(r, activity);7                 CharSequence title =r.activityInfo.loadLabel(appContext.getPackageManager());8                 Configuration config = newConfiguration(mCompatConfiguration);9                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
10                         + r.activityInfo.name + " with config " +config);11                 //其中最主要的就是attach方法 注意是调用的activity的attach方法 不是activitytherad的
12                 activity.attach(appContext, this, getInstrumentation(), r.token,13 r.ident, app, r.intent, r.activityInfo, title, r.parent,14 r.embeddedID, r.lastNonConfigurationInstances, config,15 r.referrer, r.voiceInteractor);16
17 ......18
19         returnactivity;20 }21
22
23 final voidattach(Context context, ActivityThread aThread,24             Instrumentation instr, IBinder token, intident,25 Application application, Intent intent, ActivityInfo info,26 CharSequence title, Activity parent, String id,27 NonConfigurationInstances lastNonConfigurationInstances,28 Configuration config, String referrer, IVoiceInteractor voiceInteractor) {29 attachBaseContext(context);30
31         mFragments.attachActivity(this, mContainer, null);32         //这里一下就能看出来 Acitity的window对象 是由PolicyManager的makeNewWindow方法构造出来33         //有兴趣的还可以看一下 这里set了很多接口 都是我们熟悉的那些方法
34         mWindow = PolicyManager.makeNewWindow(this);35         mWindow.setCallback(this);36         mWindow.setOnWindowDismissedCallback(this);37         mWindow.getLayoutInflater().setPrivateFactory(this);38         if (info.softInputMode !=WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {39 mWindow.setSoftInputMode(info.softInputMode);40 }41         if (info.uiOptions != 0) {42 mWindow.setUiOptions(info.uiOptions);43 }44         mUiThread =Thread.currentThread();45
46         mMainThread =aThread;47         mInstrumentation =instr;48         mToken =token;49         mIdent =ident;50         mApplication =application;51         mIntent =intent;52         mReferrer =referrer;53         mComponent =intent.getComponent();54         mActivityInfo =info;55         mTitle =title;56         mParent =parent;57         mEmbeddedID =id;58         mLastNonConfigurationInstances =lastNonConfigurationInstances;59         if (voiceInteractor != null) {60             if (lastNonConfigurationInstances != null) {61                 mVoiceInteractor =lastNonConfigurationInstances.voiceInteractor;62             } else{63                 mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,64 Looper.myLooper());65 }66 }67
68 mWindow.setWindowManager(69 (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),70 mToken, mComponent.flattenToString(),71                 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);72         if (mParent != null) {73 mWindow.setContainer(mParent.getWindow());74 }75         mWindowManager =mWindow.getWindowManager();76         mCurrentConfig =config;77 }78
79
80
81 //makenewWindow就是在这里被调用的,可以看出来 makenewWindow返回的 正是phoneWindow对象82 //到这里我们的window对象就生成了,
83     public class Policy implementsIPolicy {84     private static final String TAG = "PhonePolicy";85
86     private static final String[] preload_classes ={87         "com.android.internal.policy.impl.PhoneLayoutInflater",88         "com.android.internal.policy.impl.PhoneWindow",89         "com.android.internal.policy.impl.PhoneWindow$1",90         "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",91         "com.android.internal.policy.impl.PhoneWindow$DecorView",92         "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",93         "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",94 };95
96     static{97         //For performance reasons, preload some policy specific classes when98         //the policy gets loaded.
99         for(String s : preload_classes) {100             try{101 Class.forName(s);102             } catch(ClassNotFoundException ex) {103                 Log.e(TAG, "Could not preload class for phone policy: " +s);104 }105 }106 }107
108     publicWindow makeNewWindow(Context context) {109         return newPhoneWindow(context);110 }111
112     publicLayoutInflater makeNewLayoutInflater(Context context) {113         return newPhoneLayoutInflater(context);114 }115
116     publicWindowManagerPolicy makeNewWindowManager() {117         return newPhoneWindowManager();118 }119
120     publicFallbackEventHandler makeNewFallbackEventHandler(Context context) {121         return newPhoneFallbackEventHandler(context);122 }123 }124
125
126 //再看activity的方法 就是在这里把我们的布局文件和window给关联了起来127 //我们上面已经知道window对象就是phonewindow 所以这里就要看看phonewindow的setContentView方法
128 public void setContentView(@LayoutRes intlayoutResID) {129 getWindow().setContentView(layoutResID);130 initWindowDecorActionBar();131 }132
133
134 //phoneWindow的setContentView方法135
136 //要注意的是 这个方法执行完毕 我们也只是 通过decorView创建好了 我们自己的view对象而已。137 //但是这个对象还没有被显示出来,只是存在于内存之中。decorview真正被显示 要在makevisible方法里了
138 @Override139     public void setContentView(intlayoutResID) {140         //Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window141         //decor, when theme attributes and the like are crystalized. Do not check the feature142         //before this happens.
143         if (mContentParent == null) {144             //这个就是创建decorview的 decorView就是那个framelayout我们的根布局 有一个标题栏和内容栏145             //其中内容兰 就是android.R.id.content
146 installDecor();147         } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {148 mContentParent.removeAllViews();149 }150
151         if(hasFeature(FEATURE_CONTENT_TRANSITIONS)) {152             final Scene newScene =Scene.getSceneForLayout(mContentParent, layoutResID,153 getContext());154 transitionTo(newScene);155         } else{156             //这里就是我们自己写的布局 layout 给关联到deorview的content布局里面
157 mLayoutInflater.inflate(layoutResID, mContentParent);158 }159         final Callback cb =getCallback();160         if (cb != null && !isDestroyed()) {161             //添加完毕以后调用回调
162 cb.onContentChanged();163 }164     }

View Code

7.dialog的window创建过程?

答:子window的创建过程如下:其实和activity的过程差不多 无非是acitivity对于decorView的显示是自动控制,交给actitytherad 按照流程来走 最后makevISIABLE函数来完成最终显示的,而dialog就是需要你手动来完成这个过程也就是show函数

1 //看Dialog的构造函数 ,和acitivity差不多 也是PhoneWindow 对象。
2 Dialog(@NonNull Context context, @StyleRes int themeResId, booleancreateContextThemeWrapper) {3         if(createContextThemeWrapper) {4             if (themeResId == 0) {5                 final TypedValue outValue = newTypedValue();6                 context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);7                 themeResId =outValue.resourceId;8 }9             mContext = newContextThemeWrapper(context, themeResId);10         } else{11             mContext =context;12 }13
14         mWindowManager =(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);15
16         final Window w = newPhoneWindow(mContext);17         mWindow =w;18         w.setCallback(this);19         w.setOnWindowDismissedCallback(this);20         w.setWindowManager(mWindowManager, null, null);21 w.setGravity(Gravity.CENTER);22
23         mListenersHandler = new ListenersHandler(this);24 }25
26 //Dialog的setContentView方法 也是调用的phonewindow的方法 和acitivity流程也是一样的
27      public void setContentView(@LayoutRes intlayoutResID) {28 mWindow.setContentView(layoutResID);29 }30
31
32 //我们都知道dialog必须要show才能显示出来,
33
34      public voidshow() {35         if(mShowing) {36             if (mDecor != null) {37                 if(mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {38 mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);39 }40 mDecor.setVisibility(View.VISIBLE);41 }42             return;43 }44
45         mCanceled = false;46
47         if (!mCreated) {48             dispatchOnCreate(null);49 }50
51 onStart();52         mDecor =mWindow.getDecorView();53
54         if (mActionBar == null &&mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {55             final ApplicationInfo info =mContext.getApplicationInfo();56 mWindow.setDefaultIcon(info.icon);57 mWindow.setDefaultLogo(info.logo);58             mActionBar = new WindowDecorActionBar(this);59 }60
61         WindowManager.LayoutParams l =mWindow.getAttributes();62         if((l.softInputMode63                 & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {64             WindowManager.LayoutParams nl = newWindowManager.LayoutParams();65 nl.copyFrom(l);66             nl.softInputMode |=
67 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;68             l =nl;69 }70
71         try{72             //在这里 把decorview给add到这个window中了 与activity流程也是一样的
73 mWindowManager.addView(mDecor, l);74             mShowing = true;75
76 sendShowMessage();77         } finally{78 }79     }

View Code

8.Dialog的创建是不是必须要有activity的引用?

答:不需要,只要你更改为系统window就可以了。系统window是不需要activity作为引用的。注意别遗漏了权限

1  Dialog dialog=new Dialog(MainActivity.this.getApplicationContext());2 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);3                 TextView textView=new TextView(MainActivity.this);4                 textView.setText("this is dialog not use activity this");5 dialog.setContentView(textView);6                 dialog.show();

View Code

9.toast的window创建过程?

答:这属于系统级别的window创建了,和前面的两种window创建过程稍微不一样。其实主要就是notificationmanagerservice和toast本身之间两者的相互调用而已。

就是简单的ipc过程。前面binder的教程有讲到,如何利用binder来进行双向通信。toast的源码 就是利用了binder的双向通信来完成toast的功能。

源码就不分析了,ipc的东西讲过太多了,有兴趣的可以自己看。

转载于:https://www.cnblogs.com/punkisnotdead/p/5186474.html

Android Window 9问9答相关推荐

  1. 【Android App】实战项目之实现你问我答的智能语音机器人(超详细 附源码和演示视频)

    需要全部代码请点赞关注收藏后评论区留言私信~~~ 一.需求描述 想必大家都见过商场里的智能语音机器人,你对它提问时它可以自动回答你的问题,接下来我们也实现这样一个机器人,它依靠语音技术完成问询服务 基 ...

  2. 摩托罗拉v3android,一问易答:MOTO推出Android版V3靠谱吗!

    原标题:一问易答:MOTO推出Android版V3靠谱吗! 就在前不久摩托罗拉发布G4/G4 Plus/G4 Play三款新机的时候,一个视频广告引起了大家无限的遐想,因为视频出现了摩托罗拉经典的V3 ...

  3. android流畅机制,一问易答:为何安卓手机没有iPhone流畅

    网易江苏省手机网友[专属你的王]在一问易答中问: 小便为何配置相近的手机在Android和WP下玩同样的手机,Android没有WP流畅?小便求给上榜!!! 说上榜就上榜,开心咩?很多人都会觉得And ...

  4. ram android手机 占用,一问易答:为何安卓机RAM使用率总是很高

    网易山西省阳泉市手机网友[凌雪银痕]在一问易答中问: 小编你好,虽然小米黑的捧的一堆堆,但是我就一个普通用户,小米三配苹果六,管它说啥爱谁谁!切入正题,米三我用了一年了,系统什么都还好,可是有个非常郁 ...

  5. 有问有答 | AWS使用精华问答,带您开启 AWS 上的云计算之旅!

    戳蓝字"CSDN云计算"关注我们哦! AWS作为业界领先的云服务提供商,提供多种多样的高可靠性服务.那么究竟该如何使用AWS呢?今天的有问有答栏目,将带您开启 AWS 上的云计算之 ...

  6. Cocos论坛九问九答

    今天周未,Shawn将之前在Cocos论坛中回答的问题,整理了部分继续我的分享之路! 1. 既然有这么流畅的Cocos界面,为什么应用使用它来做H5界面 问:既然有这么流畅的Cocos界面.为什么应用 ...

  7. Android面试必问框架原理

    Android面试必问框架原理 volatile的实现原理 synchronized的实现原理 join方法实现原理 CAS无锁编程的原理 ReentrantLock的实现原理 AQS的大致实现思路 ...

  8. Android面试必问之触摸事件传递机制

    Android面试必问之触摸事件传递机制 一.Activity的构成 二.触摸事件的类型 三.事件传递的三个阶段 Activity对点击事件的分发过程 五.View的事件分发机制 六.点击事件分发的传 ...

  9. 《C++入门经典(第5版•修订版)》——2.6 问与答

    本节书摘来自异步社区出版社<C++入门经典(第5版•修订版)>一书中的第2章,第2.6节,作者:[美]Jesse Liberty , Rogers Cadenhead,更多章节内容可以访问 ...

最新文章

  1. copyof java_死磕 java集合之CopyOnWriteArrayList源码分析
  2. [linux][MongoDB] mongodb学习(一):MongoDB安装、管理工具、
  3. MOS管的主要参数与重要特性
  4. mybatis学习(26):插入功能(插入数据)
  5. python tkinter pack 同一行_用python tkinter中的一行连接2个复选按钮
  6. 流程型企业SCM、ERP、MES、PCS如何集成?
  7. 【mac】iTerm2中ssh保持连接不断开
  8. 新乡学院2019计算机报名,新乡学院2019年招生章程
  9. 怎样实现MathType在Numbers中的运用
  10. android开发那些事儿(五)-通用流行框架大全
  11. 简述redux(1)
  12. 创新创业基础答案李家华金利杰
  13. 一个时代的剪影-----汉 (作者:金立扬)
  14. 【python 走进NLP】机器学习和深度学习情感分类模型
  15. (一)事务与并发控制
  16. cvte在线笔试 android,CVTE在线笔试
  17. 抗击肺炎,我们能做到的,就是别让爱隔离——python分析B站三个视频弹幕内容,云图数据。
  18. c语言编写一个简单的答题系统
  19. JS黄金分割法实现随机漂亮颜色!
  20. Python汉英/英汉翻译(百度API/有道API)

热门文章

  1. python代替shell脚本_自动化shell脚本except与python的pexpect模块
  2. 学计算机应用基础学到了什么,2021年学习计算机应用基础心得体会-得范文网
  3. matlab画迟滞迥线,[画图的问题]怎么画类似于磁滞回线的图像?一个x值对应两个y值的...
  4. Java 8 Stream.distinct() 列表去重示例
  5. python中math函数_Python math模块 数学函数教程
  6. lisp获取qleader端点_AutoLISP开发用命令
  7. android-25是什么手机,25.手机摄影的20个常用APP
  8. html图片浮空但占位置,求助:鼠标经过图片时,图片悬浮出现变大
  9. 《Python预测之美》送书活动,中奖名单公示
  10. 2014-7 Andrew Ng 自动化所报告听后感