当前位置: 首页 > news >正文

微网站自己怎么做搜狗网站提交入口

微网站自己怎么做,搜狗网站提交入口,做网站都需要哪些技术,济南网站建设哪个好前言: View绘制流程中,主要流程是这样的: 1.用户进入页面,首先创建和绑定Window; 2.首次创建以及后续vsync信号来临时,会请求执行刷新流程; 3.刷新流程完成后,会通知SurfaceFlin…

前言:

View绘制流程中,主要流程是这样的:

1.用户进入页面,首先创建和绑定Window;

2.首次创建以及后续vsync信号来临时,会请求执行刷新流程;

3.刷新流程完成后,会通知SurfaceFlinger读取数据以及刷新页面。

本篇就是大流程中的第一个环节,重点讲解进入页面后,Window是如何创建以及绑定到系统侧的。

本文的流程主要分为以下三大块:

1.APP侧window和布局的创建流程;

2.APP侧window是如何绑定ViewRootImpl以及注册到系统侧的;

3.系统侧接收到window后,是如何处理的。

一.APP侧Window和View创建

1.1 创建Window

Activity启动时,会经历performLaunchActivity和handleResumeActivity的流程,而window的创建以及decorView的创建,就是在launch的过程中。

我们首先看一下ActivityThread.performLaunchActivity中的代码:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...//Activity的创建Activity activity = null;activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);//Activity的关联activity.attach();//执行Activity的onCreate流程mInstrumentation.callActivityOnCreate()...
}

我们看一下activity.attach中实现的相关内容:

//android.app.Activity
final void attach(){//1mWindow = new PhoneWindow();//3mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),...);mWindow.setColorMode(info.colorMode);
}//com.android.internal.policy.PhoneWindow.java
public PhoneWindow(@UiContext Context context) {public PhoneWindow(@UiContext Context context) {super(context);mLayoutInflater = LayoutInflater.from(context);}
}

主要执行了以下的逻辑:

1.创建了Activity所绑定的Window,成员名为mWindow,类型为PhoneWindow。

2.在PhoneWindow中,mLayoutInflater赋值。我们的布局就是通过mLayoutInflater对象去解析的。

3.给Window对象绑定WindowManager,这个WindowManager实际上是WindowManagerImpl。

所以此时,Activity中的mWindow,以及PhoneWindow中的mWindowManager和mLayoutInflater都已经有值了。

1.2 DecorView和ContentParent创建

接下来,我们看下callActivityOnCreate的流程。Activity.onCreate流程没有什么有关window的逻辑,但是一般我们都会在onCreate中调用setContentView,这个方法中却大有玄机,我们一起看一下:

//android.app.Window.java
public void setContentView(@LayoutRes int layoutResID) {//1getWindow().setContentView(layoutResID);
}//com.android.internal.policy.PhoneWindow
public void setContentView(int layoutResID) {if (mContentParent == null) {//2installDecor();}...//3mLayoutInflater.inflate(layoutResID, mContentParent);
}private void installDecor() {if(mDecor == null){mDecor = generateDecor(-1);}if (mContentParent == null) {mContentParent = generateLayout(mDecor);}
}

主要执行了以下的逻辑:

1.调用Activity中所持有window去加载layout。

2.首次的时候,通过installDecor方法去创建根布局DecorView以及容器布局mContentParent。mContentParent是Activity上所有的View的父容器。

3.通过mLayoutInflater对象去解析生成布局对象,并且关联到mContentParent上。

具体的解析逻辑不是本文的核心,这里就不去细讲了。

1.3 小结

至此,Activity的创建和其onCreate的流程已经结束,此时Activity中的成员变量mWindowManager和mWindow对象已经完成了赋值,总结一下,如下图所示:

 

二.APP侧Window注册

2.1 Activity和ActivityClientRecord中成员变量赋值

在第一章中,Activity所对应的window及其中的布局创建完成了,所以下一步,就是需要把这个window向系统做一个绑定,这个流程,主要是在Activity的onResume周期中执行的。

首先,我们仍然看一下resume周期所对应的代码,如下:

//ActivityThread.java
public void handleResumeActivity(ActivityClientRecord r, ...) {final Activity a = r.activity;...if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();...//1a.mDecor = decor;//2l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;//3wm.addView(decor, l);}
}

主要执行了以下的逻辑:

1.把window中的decor赋值给Activity中的mDecor;

2.设置Window.LayoutParams的type类型为WindowManager.LayoutParams.TYPE_BASE_APPLICATION;在安卓中,type决定window图层优先级,值越大优先级越高,部分图层优先级如下:

public static final int TYPE_BASE_APPLICATION   = 1;//默认Activity对应的图层
public static final int FIRST_SYSTEM_WINDOW     = 2000;//系统弹窗的图层
public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;//Toast的图层
public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;//悬浮窗的图层等级
public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;//同上,用于替代上面那个

3.通过windowManager添加decor。这里wm的对象,实际上是WindowManagerImpl,而其中的addView方法中,又交给了WindowManagerGlobal来处理,相关代码如下:

//WindowManagerImpl.java
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {mGlobal.addView(view, params,...);
}

2.2 WindowManagerGlobal装载Window

接下来,我们看一下WindowManagerGlobal.addView()中的逻辑。

public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow, int userId) {ViewRootImpl root;View panelParentView = null;...//1if (windowlessSession == null) {root = new ViewRootImpl(view.getContext(), display);} else {root = new ViewRootImpl(view.getContext(), display, windowlessSession);}view.setLayoutParams(wparams);//2mViews.add(view);mRoots.add(root);mParams.add(wparams);//3root.setView(view, wparams, panelParentView, userId);   
}

主要执行了以下的逻辑:

1.创建ViewRootImpl,ViewRootImpl的角色是页面刷新显示流程的执行者。

2.WindowManagerGlobal的角色是维护客户端所有的页面的,所以自然而然的,其中就维护了很多集合。比如存储所有根布局的mView对象等等,这里就是往集合中注册的。

@UnsupportedAppUsage
private final ArrayList<View> mViews = new ArrayList<View>();
@UnsupportedAppUsage
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
@UnsupportedAppUsage
private final ArrayList<WindowManager.LayoutParams> mParams =new ArrayList<WindowManager.LayoutParams>();

3.上面说到,ViewRootImpl是流程的具体执行者,那么window的绑定自然也是交给其来处理。所以这里通过ViewRootImpl.setView方法来负责。

2.3 ViewRootImpl负责视图的绑定

接下来,我们就看下ViewRootImpl的setView()方法。

ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {...if (mView == null) {mView = view;...//1requestLayout();//2InputChannel inputChannel = null;if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {inputChannel = new InputChannel();}//3res = mWindowSession.addToDisplayAsUser(...);}//mInputEventReceiver = new WindowInputEventReceiver(inputChannel,Looper.myLooper());
}

这一块的逻辑也是较为清晰的:

首先,通过requestLayout方法尝试进行首次View绘制的完整流程,虽然这时window还没有绑定上,但是并不影响View流程的开始,毕竟View流程中,只有最后的绘制流程才需要和SurfaceFlinger进行交互。

然后,生成InputChannel对象,这个对象类似于一个回调,通过后面的binder接口传递给系统侧。后面window上的点击事件,就会通过InputChannel回调通知到应用侧。后面把inputChannel绑定到WindowInputEventReceiver中,所以APP侧点击事件的来源,就是其中的onInputEvent方法。

最后,把相关的对象传递给系统侧,完成注册。传递的内容如下:

int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs,in int viewVisibility, in int layerStackId, in int userId,in InsetsVisibilities requestedVisibilities, out InputChannel outInputChannel,out InsetsState insetsState, out InsetsSourceControl[] activeControls);

int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, in int userId, in InsetsVisibilities requestedVisibilities, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls);

整个流程如下图所示:

给系统侧传递的数据列表如下:

对象类型

成员变量名

解释

IWindow

window

对应ViewRootImpl中的IWindow.Stub,传递的一个binder对象

WindowManager.LayoutParams

attrs

window对应的layoutParams属性

int

viewVisibility

根布局的显示状态

int

layerStackId

displayId,显示区域的唯一ID

int

userId

应用的userId

InsetsVisibilities

requestedVisibilities

InputChannel

outInputChannel

事件分发流程中,传递的通道

InsetsState

insetsState

InsetsSourceControl

activeControls

三.系统侧Window绑定

介绍系统侧的流程前,我们先对系统侧的几个核心类简单介绍下,因为大多数的读者对于系统侧的了解较少。

3.1 核心类介绍

类名

功能介绍

com.android.server.wm.Session

一个session对应一个应用进程,负责应用和系统之间的窗口注册/移除,SurfaceSession注册等等。

SurfaceSession

这个类注册是native的实现。负责维护应用和surfaceFlinger之间的连接。所以,APP刷新时是直接通知SF,并不需要经过system_server。

WindowManagerService

顾名思义,用于所有应用的窗口管理。这里只是维护窗口的关系,并负责具体的渲染流程。

3.2 应用进程绑定唯一的IWindowSession

上一章有讲到,一个应用会有一个维护所有的视图的容器WindowManagerGlobal,那么它其中,一定有一个负责和系统侧通信的对象,这个对象就是IWindowSession。相关代码如下:

//WindowManagerGlobal.java
public static IWindowSession getWindowSession() {if (sWindowSession == null) {IWindowManager windowManager = getWindowManagerService();sWindowSession = windowManager.openSession(...);}
}//WindowManagerService.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {return new Session(this, callback);
}

也就是说,WindowManagerGlobal中只会持有一个sWindowSession对象,而WindowManagerGlobal对应一个应用的进程,所以IWindowSession是绑定唯一一个应用进程的。IWindowSession是一个binder的引用,其在系统侧的具体实现是Session。上面的addToDisplayAsUser方法,就是通过IWindowSession中提供的binder方法。

3.3 把window注册到系统侧

接下来我们就看一下第二中讲到的addToDisplayAsUser()方法,它负责把应用侧的Window向系统侧注册。我们看一下其在系统侧的实现:

//Session.java
class Session extends IWindowSession.Stub{public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,InputChannel outInputChannel, InsetsState outInsetsState,InsetsSourceControl[] outActiveControls) {return mService.addWindow(this, ...);}
}

逻辑很简单,直接交给WindowServiceManger的addWindow方法去处理,接下来我们就看下这个方法:

//WindowManagerService.java
public int addWindow(Session session, ...) {WindowState parentWindow = null;...//1final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);...//2WindowToken token = displayContent.getWindowToken(hasParent ? parentWindow.mAttrs.token : attrs.token);...if (token == null) {if( hasParent ){token = parentWindow.mToken;} else if (){token = new WindowToken.Builder(this, binder, type)} else {token = new WindowToken.Builder(this, binder, type)}...}...//3final WindowState win = new WindowState(this, session, );...if  (openInputChannels) {win.openInputChannel(outInputChannel);}...//4win.openInputChannel(outInputChannel);...//5win.attach();win.initAppOpsState();...win.mToken.addWindow(win);
}

首先,根据displayId找到归属的DisplayContent,DisplayContent的作用是用于跟踪一系列的WindowState;

然后,如果当前的window存在parent,则去查询其parent的WindowToken。WindowToken顾名思义,用于识别WindowState;

接下来,生成WindowState,这里的WindowState和APP侧的Window是对应的,WindowState就是在系统侧window的描述并负责和window进行通讯;

然后,绑定事件输入,这里的outInputChannel就是APP侧传递过来的。

最后,通过attch()方法完成绑定,我们重点看一下这个方法:

//WindowState.java
void attach() {if (DEBUG) Slog.v(TAG, "Attaching " + this + " token=" + mToken);mSession.windowAddedLocked();
}//Session.java
void windowAddedLocked() {if (mPackageName == null) {mPackageName = wpc.mInfo.packageName;}if (mSurfaceSession == null) {mSurfaceSession = new SurfaceSession();...mService.mSessions.add(this);}mNumWindow++;
}

简单来说,一个应用首次完成window.attch()的时候,初始化mPackageName和mSurfaceSession()。

而mSurfaceSession对应的就是显示在前台的区域,它初始化后,对应的就是native创建surface以及后续和surfaceFlinger交互的流程了,这个我们后面的文章来讲解。

最后使用mNumWindow记录Window的数量。

3.4 小结

我们仍然做一个小的总结,window注册在系统侧的实现。其实就是接受一个客户端传递过来的binder引用对象IWindow,然后生成一个唯一的对应对象WindowState。并且在应用进程级别生成一个SurfaceSession去维护应用的ViewRootImpl和surfaceFlinger的关系。流程图如下:

 

四.总结

最后,我们做一下总结,整个window的注册流程主要分为三块大块:

1.create流程主要是各种对象的初始化。流程中完成客户端window的创建以及mDecor,mContentParent等相关成员变量的初始化;

2.resume流程主要是window关系的维护。所以创建视图处理类ViewRootImpl,并且使用其把window向系统侧申请绑定;

3.系统收到后主要是生成window在系统侧的对象并记录。所以分别创建Window组的对象WindowToken和Window的系统侧对象WindowState并保存。

整体流程图如下:

 

五.扩展性问题

1.如果onCreate中不调用setContentView,那么会执行后面的流程吗?

答:会的,即使不调用setContentView,只是不会有ContentView,但是DecorView仍然会创建和绑定的,只不过这时候展示的会是黑屏。

http://www.hkea.cn/news/121157/

相关文章:

  • 网站建设开发合同书关键词怎么找出来
  • 常州微信网站建设附子seo
  • 上海网站seo招聘十种营销方式
  • 农产品网络营销模式百度推广怎么优化
  • 公司网站维护如何做分录自己搭建一个网站
  • 做期货浏览哪些网站网络优化工程师前景如何
  • 垂直b2b电子商务网站有哪些google搜索排名优化
  • 建设中网站源码网络推广工具和方法
  • 厦门做点击付费网站培训教育
  • 常州网站建设案例网站制作建设公司
  • 外国人做家具的网站一站传媒seo优化
  • 佛山h5建站模板怎样优化网站
  • 第三方做公司网站谷歌搜索广告优化
  • 网站风格模板快速排名精灵
  • 做网站横幅 的网站推荐几个公司推广
  • html5国内网站建设客户管理软件
  • 网站建设报价单站长工具 seo查询
  • 日本电商网站贵州快速整站优化
  • 物业服务网站建设建立网站要多少钱一年
  • 中铁建设门户加长版廊坊百度提升优化
  • 最便宜的外贸网站建设电商平台运营方案
  • 做网站应该会什么问题网络营销软文范例500字
  • 摄影网课百度关键词优化查询
  • 打广告型的营销网站西安百度推广外包
  • 乌鲁木齐招聘网站建设一站式网络营销
  • 中小型网站建设服务淘宝数据分析工具
  • 梧州网站设计企业网站模板建站
  • 行政事业单位网站建设建议营销策划公司
  • 网络推广网站怎么做百度联盟广告点击一次收益
  • wordpress居中样式宁波seo网络推广外包报价