Android Window 9问9答
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答相关推荐
- 【Android App】实战项目之实现你问我答的智能语音机器人(超详细 附源码和演示视频)
需要全部代码请点赞关注收藏后评论区留言私信~~~ 一.需求描述 想必大家都见过商场里的智能语音机器人,你对它提问时它可以自动回答你的问题,接下来我们也实现这样一个机器人,它依靠语音技术完成问询服务 基 ...
- 摩托罗拉v3android,一问易答:MOTO推出Android版V3靠谱吗!
原标题:一问易答:MOTO推出Android版V3靠谱吗! 就在前不久摩托罗拉发布G4/G4 Plus/G4 Play三款新机的时候,一个视频广告引起了大家无限的遐想,因为视频出现了摩托罗拉经典的V3 ...
- android流畅机制,一问易答:为何安卓手机没有iPhone流畅
网易江苏省手机网友[专属你的王]在一问易答中问: 小便为何配置相近的手机在Android和WP下玩同样的手机,Android没有WP流畅?小便求给上榜!!! 说上榜就上榜,开心咩?很多人都会觉得And ...
- ram android手机 占用,一问易答:为何安卓机RAM使用率总是很高
网易山西省阳泉市手机网友[凌雪银痕]在一问易答中问: 小编你好,虽然小米黑的捧的一堆堆,但是我就一个普通用户,小米三配苹果六,管它说啥爱谁谁!切入正题,米三我用了一年了,系统什么都还好,可是有个非常郁 ...
- 有问有答 | AWS使用精华问答,带您开启 AWS 上的云计算之旅!
戳蓝字"CSDN云计算"关注我们哦! AWS作为业界领先的云服务提供商,提供多种多样的高可靠性服务.那么究竟该如何使用AWS呢?今天的有问有答栏目,将带您开启 AWS 上的云计算之 ...
- Cocos论坛九问九答
今天周未,Shawn将之前在Cocos论坛中回答的问题,整理了部分继续我的分享之路! 1. 既然有这么流畅的Cocos界面,为什么应用使用它来做H5界面 问:既然有这么流畅的Cocos界面.为什么应用 ...
- Android面试必问框架原理
Android面试必问框架原理 volatile的实现原理 synchronized的实现原理 join方法实现原理 CAS无锁编程的原理 ReentrantLock的实现原理 AQS的大致实现思路 ...
- Android面试必问之触摸事件传递机制
Android面试必问之触摸事件传递机制 一.Activity的构成 二.触摸事件的类型 三.事件传递的三个阶段 Activity对点击事件的分发过程 五.View的事件分发机制 六.点击事件分发的传 ...
- 《C++入门经典(第5版•修订版)》——2.6 问与答
本节书摘来自异步社区出版社<C++入门经典(第5版•修订版)>一书中的第2章,第2.6节,作者:[美]Jesse Liberty , Rogers Cadenhead,更多章节内容可以访问 ...
最新文章
- copyof java_死磕 java集合之CopyOnWriteArrayList源码分析
- [linux][MongoDB] mongodb学习(一):MongoDB安装、管理工具、
- MOS管的主要参数与重要特性
- mybatis学习(26):插入功能(插入数据)
- python tkinter pack 同一行_用python tkinter中的一行连接2个复选按钮
- 流程型企业SCM、ERP、MES、PCS如何集成?
- 【mac】iTerm2中ssh保持连接不断开
- 新乡学院2019计算机报名,新乡学院2019年招生章程
- 怎样实现MathType在Numbers中的运用
- android开发那些事儿(五)-通用流行框架大全
- 简述redux(1)
- 创新创业基础答案李家华金利杰
- 一个时代的剪影-----汉 (作者:金立扬)
- 【python 走进NLP】机器学习和深度学习情感分类模型
- (一)事务与并发控制
- cvte在线笔试 android,CVTE在线笔试
- 抗击肺炎,我们能做到的,就是别让爱隔离——python分析B站三个视频弹幕内容,云图数据。
- c语言编写一个简单的答题系统
- JS黄金分割法实现随机漂亮颜色!
- Python汉英/英汉翻译(百度API/有道API)
热门文章
- python代替shell脚本_自动化shell脚本except与python的pexpect模块
- 学计算机应用基础学到了什么,2021年学习计算机应用基础心得体会-得范文网
- matlab画迟滞迥线,[画图的问题]怎么画类似于磁滞回线的图像?一个x值对应两个y值的...
- Java 8 Stream.distinct() 列表去重示例
- python中math函数_Python math模块 数学函数教程
- lisp获取qleader端点_AutoLISP开发用命令
- android-25是什么手机,25.手机摄影的20个常用APP
- html图片浮空但占位置,求助:鼠标经过图片时,图片悬浮出现变大
- 《Python预测之美》送书活动,中奖名单公示
- 2014-7 Andrew Ng 自动化所报告听后感