您的位置:首页 > 移动开发 > Android开发

Android事件分发和View绘制流程分析(一)

2018-01-10 18:52 537 查看

Android事件分发和View绘制流程分析(一)

写在之前,说到Android的事件分发和View绘制,我们常接触到的是从Activity的dispatchTouchEvent()和顶级DecorView的draw方法开始,但是一个对象的方法调用总是有源头的,而对象也肯定是有初始化的过程的,日常中我们不用关心这个Activity是如何由class文件变成一个内存中的对象,也不需要知道我们的顶级视图DecorView又是什么时候初始化出来的,当然也不需要关心DecorView是如何和我们常说的Window关联起来的,以及进一步我们的一个个页面又是如何被系统管理的。但一个东西用的多了,就会总是想要知道它是从哪里来的,一件事请发生了也总想知道引起这件事的最初源头是在哪里,这在现实的生活中也许是根本不可能,但万幸在代码中却给了我们机会去追本溯源(这正是代码的乐趣之一,所有的规则和逻辑都是有同样的人去code的,而不至于出现像在现实中:人类存在的意义?这些无法回答的问题),当然也许这依旧并没有什么意义。但是这里我还是简单理出Activity中的dispatchTouchEvent()是由谁调用的,DecorView的draw方法又是由谁调用,以及该调用者又是在什么时候以及如何初始化的。也就是去找一找事件分发在应用层的起点是在哪里以及一个View树最开始的绘制起点又是在哪里。

一、Android中一个事件的生成和传递是有一个交互载体的,同样一个View树的绘制显示也是,这个交互的载体最直观的就是我们日常用到的一个Activity。我们在Activity中通过setContentView去初始化我们想要的视图,然后我们再对其中的各个View实现我们的各种事件处理

本文中我们就从Activity的初始化开始,跟着Activiy的初始化过程去找一找事件分发和View树绘制的起点是在哪里。本文内容为个人理解和笔记整理,肯定有错误及不准确的地方万请仅作参考查看,如有错误还请指出

<下面涉及到的Android源码均为API23的源码>

在Activity的整个初始化过程中涉及到的对象有很多,其中比较重要的有:ActivityThread,AvtivityManagerServier,Activity,WindowManager,WindowManagerImpl,WindowManagerGlobal,ViewRootImpl,Context,Window,PhoneWindow,DecorView,我们可以先有个印象:

1、ActivityThread是一个应用的启动的入口,里面有我们Java程序中常见的main函数。Activity的声明周期的调用都是在该类中实现(具体在其内部类H中可以看到)

2.AvtivityManagerServier(AMS) 实体运行在另外一个进程中,应用主线程和AMS的通信为跨进程的通信,基于binder实现。

3.WindowManager 接口类是本地窗口管理的统一接口

4.WindowManagerImpl 窗口管理类的实例类,其主要是实现了对WindowManagerGlobal的包装。具体的方法调用都是转接到了WindowManagerGlobal中去

5.WindowManagerGlobal 是一个典型的单例类用来管理当前应用中对应的ViewRootImpl和DecorView

6.ViewRootImpl 该类是在WindowManagerGlobal中初始化并管理的,【事件的从底层到应用层的接收点】以及【View树的绘制起点】都在该类的实现中

7.PhoneWindow是Window的子类,和视图最终绘制有关

8.DecorView是PhoneWindow的一个内部类,在Activity中调用setContentView()时生成

关于Activity的启动,主要分为当前应用的其他Activity启动和跨应用的的Activity启动(比如点击Launcher图标启动一个app的MainActivity),此处我们不去过于关注在调用startActivity()之后AMS是怎么管理这个Activity的,我们直接跳到要启动的Activity在AMS中注册登记之后,又回到ActivityThread主线程中执行handleLaunchActivity()的地方开始,而对于这之前的过程我们以手机来举一个不太恰当的例子带过:

首先,我们是知道一个手机的功能,我们现在想要使用手机的通话功能。我们就把手机比做是Activity,那么手机中的SIM卡或者说是电话号就相当于ActivityClientRecord,移动运营商就相当于ActivityManagerServer,呼叫一个电话最终会到使我们的电话响起就相当于对Activity的生命周期回调。

然后,我们想要使用手机的通话功能,我们需要去移动的营业厅去办SIM卡,开卡的时候我们需要提供有效的身份证件信息,如果身份信息有效那么最终我们会得到一张SIM卡,准确的说是移动运营商会生成一份对应的数据信息包括电话号码等在其服务端的系统上,同时把这份信息复制一份到SIM卡上,当然这个卡号是和身份信息成套出现的,默认我们以后在呼叫这个号码时,其对应的手机就会响起。而需要注意的是我们在拿到卡号时此时是不需要先有一部手机的,这其实相当于我们在去启动一个Activity的时候,我们会先根据启动Activity时的Intent信息去AMS中注册(该过程会有相应的验证),如果一切正常此时AMS中会返回给一个ActivityClientRecord,同时也会在AMS自己的服务中记录一份用来管理,而不是直接把Activity拿过来保存,同样我们也不会把一个手机直接放在移动公司里

当我们拿到SIM卡之后我们此时买一个手机,然后把卡装到手机上,相当于我们把手机和这个卡绑定到了一块,那么此时只要你在移动端这个号码注册成功,那么通过这个号码就可以呼叫起这部手机,该过程就相当于我们在AMS中注册之后,实例化了一个Activity对象并把该Activity对象和从AMS中返回的ActivityClientRecord绑定,此时AMS只要按照自己记录的那一份数据就能找的到我们之后才实例化的Activity

当然你可能会说那这有不恰当的地方Activity在实例化的时候,是根据注册的具体Activity的名字去实例化的,而买手机的时候可以随便买一个。那我们就假设我们现实中也必须是按照我们在去移动运营商注册SIM时提供的身份信息去拿到一台和身份信息匹配的手机。但是此时还有一个问题那就是我们在注册的时候会去验证身份信息,按照理想我们是要去拿到一台和注册信息完全匹配的手机装上这个SIM卡才行,但是我们实际上还是不用,而是随便拿一台手机装上电话卡依旧可以被呼叫到。而可以被呼叫主要原因:1.因为移动运营商是依照SIM的号码去呼叫的,而不是依照电话相关信息去呼叫的;2.因为我们装入卡的时候是不会去检测当前的手机是不是你在注册SIM卡的时候声明的那部手机的;同样在Activity的启动中,我们当在AMS中注册完一个有效的Activity并返回ActivityClientRecord之后,在其后面的具体实例化中实例化的时候,不管是哪一个Activity,也不会管其合不合法,有没有注册过,都是可以把这个Activity与在AMS中返回的ActivityClientRecord绑定的,而之后的生命周期以及所有的回调也都能到达,因为AMS也只是根据其存储的相关信息直接找到ActivityClientRecord,拿到它里面的Activity去回调的,而不是拿着整个Activity的名字去找的。而在APP插件化的开发中也的确可以利用这一点去启动在Manifest中没有生命过的Activity,而达到插件化开发的真正目的。

1.1 下面我们就从ActivityThread主线程中收到正式启动Activity消息并执行:handleLaunchActivity(ActivityClientRecord r, Intent customIntent)开始,

1.1.1在收到LaunchActivity的消息后,经过ActivityThread中H的处理会调用handleLaunchActivity()

此时该Activity已经在AMS的中存在记录了,只不过这个记录不是这个Activity的实体或者引用,因为此时该Activity还没有创建,只是一个根据其Intent生成的对应的特征信息,而AMS可以通过这个特征信息找到后来生成的Activity

1.1.2 然后进一步会调用performLaunchActivity(),参数ActivityClientRecord中即记录了根据Intent信息生成的Activity的相关信息,比较重要的就是该Activity的全量类名名,后面在具体生成该Activity对象之后,会把Activity的实例引用记录其中

1.1.3 在performLaunchActivity()调用完毕之后,如果成功启动了对应所需的Activity,则此时会继续调用handleResumeActivity()

代码如下:

@ActivityThread.java
//-------1.1.1ActivityThread在收到LaunchActivity的消息后(此时该Activity已经在AMS的栈中存在记录了,只不过这个记录不是这个Activity的实体或者引用,因为此时该Activity还没有创建,只是一个对应的特征信息,而AMS可以通过这个特征信息找到该Activity。)(TODO 完善目前看到的是一个binder)
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;

if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}

// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);

if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);

// Initialize before creating the activity
WindowManagerGlobal.initialize();

Activity a = performLaunchActivity(r, customIntent);//--------------1.1.2、执行 performLaunchActivity,

if (a != null) {//--------------如果a!=null,继续往下走
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);//-------------1.1.3、在performLaunchActivity()调用完毕之后,如果成功启动了对应所需的Activity,则此时会继续调用handleResumeActivity()

if (!r.activity.mFinished && r.startsNotResumed) {//---------------已经start但是没有onResum
// The activity manager actually wants this one to start out
// paused, because it needs to be visible but isn't in the
// foreground.  We accomplish this by going through the
// normal startup (because activities expect to go through
// onResume() the first time they run, before their window
// is displayed), and then pausing it.  However, in this case
// we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just
// retain the current state it has.
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
// We need to keep around the original state, in case
// we need to be created again.  But we only do this
// for pre-Honeycomb apps, which always save their state
// when pausing, so we can not have them save their state
// when restarting from a paused state.  For HC and later,
// we want to (and can) let the state be saved as the normal
// part of stopping the activity.
if (r.isPreHoneycomb()) {
r.state = oldState;
}
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPause()");
}

} catch (SuperNotCalledException e) {
throw e;

} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.paused = true;
}
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
// Ignore
}
}
}


1.2:执行开启Activity:performLaunchActivity(r, customIntent),具体逻辑如下

1.2.1、拿取当前的ClassLoader 加载activity的字节码,生成activity对象,在此之前已经把该activity已经被标记在了AMS的activity栈中,以后AMS则可以通过此找到该Activity并发送消息执行其相应的生命周期回调 TODO 完善

1.2.2、准备Application信息

1.2.3、准备Context信息

1.2.4、执行Activity的 activity.attach()方法,在此方法中会将context信息和Application信息注入到Activity中去,具体的在1.3中给出具体attach()都做了什么

1.2.5、不管如何都会回调到activity的onCreat方法,此处的mInstrumentation对象也是一个比较有意思的地方,在Activity中的onCreate()中,会有常见的setContentView方法,在该方法中最终会在PhoneWindow中生成DecorView并和PhoneWindow相关联

1.2.6、onCreat之后,在调用声明周期时,就会加一个判断当前的Activity有没有被结束,然后回调Activity的onStart()

1.2.7、如果有需要恢复的数据,则回调OnRestoreInstanceState()

ps:代码中ps该处的代码我们可以看到是设置当前Activity主题,其顺序位置是在onCreat(),因为在onCreat的setContentView初始化DecorView的时候是需要用的这个值得,如果我们在代码中设置一个Activity的主题,此时我们就需要在setContentView()调用之前setTheme()否则不会生效

代码:

@ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}

ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}

if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}

Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();//-----------------1.2.1拿取ClassLoader 加载activity的字节码,生成activity对象,在此之前已经把该activity对应的信息以clasinfo或intent中的action等信息为标记在AMS的activity栈中添加。以后AMS则可以通过此找到该Activity并发送消息执行其相应的生命周期回调
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}

try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);//---------------1.2.2准备Application

if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());

if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);//-----------1.2.3生成Context
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);//-----------1.2.4执行Activity的attacth方法

if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);//----**tip:设置teme,需要在setContentView之前,否则setContentView在onCreat中调用时拿不到Theme的值**-----
}

activity.mCalled = false;
if (r.isPersistable()) {//----------------1.2.5、不管如何都会回调到activity的onCreat方法,此处的mInstrumentation对象也是一个比较有意思的地方,在Activity中的onCreate()中,会有常见的setContentView方法,在该方法中最终会在PhoneWindow中生成DecorView并和PhoneWindow相关联
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;//----在r中记录对应的activity
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();//----------------1.2.6回调Activity的onStart()
r.stopped = false;
}
if (!r.activity.mFinished) {//-----------------1.2.7.回调OnRestoreInstanceState
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;

mActivities.put(r.token, r);//----最终保存该Activity

} catch (SuperNotCalledException e) {
throw e;

} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}

return activity;
}


1.3、在上面1.2.4的代码处调用了Activity中的attatch(),此时上下文准备完毕,开始执行Activity和WIndow窗口之间的关联,此处的attach和Activity的onAttachedToWindow()无关,

1.3.1、首先在attach调用时会实例化一个PhoneWindow对象,该PhoneWindow继承自Window,是一个具体实现类

1.3.2、在实例化PhoneWindow之后,调用了PhoneWindow的setCallback(),其所需参数为Window.Callback;并把当前的Activity设置传入(Activity实现了Window.Callback接口),[b]此处需注意,后面在PhoneWindow中的内部类DecorView在调用Callback的时候,正是调用的该Activity中的Window.Callback实现[/b]

1.3.3、给生成的PhoneWindow设置WindowManager,后面在ActivitydThread的handleResumeActivity()中,会使用该PhoneWindow中的WindowManager

代码如下:

@Activity
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,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);

mFragments.attachHost(null /*parent*/);

mWindow = new PhoneWindow(this);//-----1.3.1.创建phoneWindow对象,并保存到本地
mWindow.setCallback(this);//-----1.3.2.把PhoneWindow对象的callBack设置为this,该CallBack是Window.Callback,主要用于在接收到TouchEvent和KeyEvent的事件时回调对应Activity中的dispatchTouchEvent()和KeyEvent的方法
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();

mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}

mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//-----1.3.3、给phoneWindow设置WindowManager
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();//同时保存WindowManager到Activity中
mCurrentConfig = config;
}


1.4 从1.1中可以看到当执行完handleLaunchActivity()之后,如果Activity启动成功,此时会走到1.1.3处的代码:handleResumeActivity(),逻辑如下:

1.4.1 在此处回调performResumeActivity(),在此方法中会更改本地当前Activity的状态

1.4.2 拿取在1.3.1处创建出来的PhoneWindow

1.4.3 拿取PhoneWindow中的DecorView,DecorView是PhoneWindow的内部类,当没有时会直接创建,(其第一次创建是在Activity的Oncreat中的setContentView中创建的,就是我们经常在Activity中调用的setContentView)

1.4.4 拿取WindowManager,实际返回的是其实现类WindowManagerImpl

1.4.5 此处执行WindowManagerImpl的AddView(),WindowManagerImpl是对WindowManagerGlobal的包装最终会调用到WindowManagerGlobal的addView(),该调用处会生成ViewRootImpl,并把DecorView和ViewRootImpl保存起来,一一对应,到此处ViewRootImpl才正式创建出来,在下面的1.5中我们在具体看代码是怎么实现的。

而Activity事件分发中的事件从底层传递到应用层的接收点,通常就是ViewRootImpl中的WindowInputRecever同时Activity的View树的绘制也是从ViewRootImpl中开始的**

1.4.6 此时Activity已经确定执行了完了onResume(),调用 ActivityManagerNative.getDefault().activityResumed(token) 通知AMS(通过binder跨进进程通信)把AMS中对应记录该Activity的状态更改为resumed,再次申明在AMS中保存的不是Activity只是该Activity的一个对应的数据结构(通过该token进行对应),其中记录了当前该Activity的相关状态信息,并进行维护。Activity生命周期的实现实际就是AMS对Activity的管理,根据逻辑在各个逻辑节点对这些<生命周期函数>的回调

我们回顾一下顶级视图DecorView是怎么和Activity关联起来的:首先是在接收到LaunchActivity指令之后,实例化Activity进而执行Activity的attatch()此时创建PhoneWindow对象并使其和WindowManager关联(TODO:具体如何管理),同时Activity中会保存该PhoneWindow,然后又在Activity的onCreate()中setContentView()时,创建DecorView,这样Activity就和DecorView关联起来了。

@ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;

// TODO Push resumeArgs into the activity for consideration
ActivityClientRecord r = performResumeActivity(token, clearHide);//------1.4.1回调Activity的onReusme()

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

if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);

final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

// 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();//--------1.4.2、该处拿取之前在attach时,创建的PhoneWindow
View decor = r.window.getDecorView();//--------1.4.3、此处会拿取DecorView,DecorView是PhoneWindow的内部类,当没有时会直接创建,第一次创建是在Oncreat的setContentView中创建的
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();//-------1.4.4、拿取WindowManager,实际返回的是其实现类WindowManagerImpl
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);//--------1.4.5、此处执行WindowManager的AddView(),该调用处会生成ViewRootImpl,并把DecorView和ViewRootImpl保存起来,一一对应,而Activity中的事件分发和Activity的视图绘制都是从ViewRootImpl中直接开始的
}

// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}

// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r);

// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
r.tmpConfig.setTo(r.newConfig);
if (r.overrideConfig != null) {
r.tmpConfig.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
+ r.activityInfo.name + " with newConfig " + r.tmpConfig);
performConfigurationChanged(r.activity, r.tmpConfig);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
r.newConfig = null;
}
if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
+ isForward);
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}

if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(
TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;

// Tell the activity manager we have resumed.
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token);//------ 1.4.6、此时Activity已经确定执行了完了onResume(),调用 ActivityManagerNative.getDefault().activityResumed(token) 通知AMS(通过binder跨进进程通信)把AMS中对应记录该Activity的状态更改为resumed,再次申明在AMS中保存的不是Activity只是该Activity的一个对应的数据结构(通过该token进行对应),其中记录了当前该Activity的相关状态信息,并进行维护。Activity生命周期的实现实际就是AMS对Activity的管理,根据逻辑在各个节点对这些<生命周期函数>的回调
} catch (RemoteException ex) {
}
}

} else {
// If an exception was thrown when trying to resume, then
// just end this activity.
try {
ActivityManagerNative.getDefault()
.finishActivity(token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
}
}
}


1.5 从上面流程中可以整理出:在ActivityThread的handleResumeActivity()方法中调用的WindowManager.addView(),实际实现是WindowManagerImpl中的addView(),WindowManagerImpl的addView()只是简单的调用了WindowManagerGloble的addView(),代码实现位置在 WindowManagerGloble,逻辑及代码如下:

1.5.1 实例化ViewRootImpl,其中的参数包含了一个Display,这个是和View最终绘制有关

1.5.2 在全局变量中添加记录该DecorView

1.5.3 同时添加记录生成的ViewRoot

1.5.4 调用ViewRootImpl.setView()绑定view到Root,使DecorView和ViewRootImpl相关联,至此ViewRootViewImpl中保存了DecorView的引用,我们在1.6中详细看ViewRootImpl.setView()的实现

@WindowManagerGloble.java WindowManagerGLoable是在WindowManagerImpl中初始化的其为全局单例类:WindowManagerGlobal.getInstance()
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}

final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}

ViewRootImpl root;
View panelParentView = null;

synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}

int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}

// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}

root = new ViewRootImpl(view.getContext(), display);//----1.5.1、实例化ViewRootImpl,其中的参数包含了一个Display,这个是和View最终绘制有关

view.setLayoutParams(wparams);

mViews.add(view);//----1.5.2 在全局变量中添加记录该DecorView
mRoots.add(root);//----1.5.3 同时添加记录生成的ViewRoot
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);//----1.5.4绑定view到Root,使DecorView和ViewRootImpl相关联,至此ViewRootViewImpl中保存了DecorView的引用
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}


对于Activity中的onCreat()中的setContentView()会经过getWindow().setContentVew(),调用到PhoneWindow的setContentView(),为了便于理清直接贴上代码如下

@PhoneView.java
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();//此处会生成DecoreView并会根据Theme和屏幕数据设置相关的参数,DecorView是一个FrameLayout。
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}

if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);//把我们在Activity中set的视图添加到CntentView位置
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}


1.6 在ViewRootImpl的setView()方法中我们最终可以看到外部事件接收对象WindowInputEventReceiver的初始化,以及各对事件处理的原始对象InputStage;同时也可以看到视图绘制的最初调用点requestLayout(),逻辑及代码如下:

1.6.1 此处使用mView保存传递过来的view对象,该view实际就是我们的DecorView

1.6.2 requestLayout() View视图树的绘制即从此处正式开始

1.6.3 初始化WindowInputEventReceiver,用来接收底层传递过来的外部事件比如常见的屏幕点击,返回的点击等等,其构建参数InputChannel是底层识别并回调的到该对象的关键(TODO:具体底层是怎么把事件传递到此处的)

1.6.4 是初始化外部事件的处理器,是一个单向链表结构,其中的ViewPreImeInputStage在接收到事件后会调用到mView.dispatchKeyEventPreIme(event)

1.6.4.1 SyntheticInputStage 是一个兜底消息拦截处理器,当前面的处理器都没有消费掉此次事件时最终会使用该处理器进行处理

1.6.4.2 ViewPostImeInputStage 是View树事件分发处理器,在前面的处理中消息没有被消费掉时可以调用的到,该消息处理器中会调用mView【DecorView】的dispatchTouchEvent()或Keyevent进行转发,进而进入到Activity,再回转到mDecorView

1.6.4.3 NativePostImeInputStage native的一个事件处理器 TODO:具体是分发到谁去处理当前事件

1.6.4.4 EarlyPostImeInputStage输入法相关的拦截处理器,处理完后首先调用到的

1.6.4.5 ImeInputStage 和输入法处理相关的拦截器

1.6.4.6 ViewPreImeInputStage 调用到输入法处理器之前,该处理中会回调所有View的dispatchKeyEventPreIme(event),进而调用onKeyPreIme()方法

1.6.4.7 NativePreImeInputStage native的在调用到输入法之前的处理

@ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;//------1.6.1此处即为DecorView,事件传递时,到达ViewRootImpl之后调用的即是DecorView的disPatchTouchEvent()
...
requestLayout();//===******===1.6.2请求布局开始,此处为View绘制的起始点
...
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());//===******===1.6.3设置底层事件接收Receiver,此处是事件分发进入用户Application层的接入起始点
}
...
//------1.6.4、外部事件(点击,按键等)地处理Handler的初始化,以下构造的事件处理Handler是以单向链表的方式组织,处理是以职责链的方式进行处理
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();//----1.是一个兜底消息处理器,当前面的处理器都没有消费掉此次事件时最终会使用该处理器进行处理
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);//----####---2.该消息处理器中会调用mView【DecorView】的dispatchTouchEvent()或Keyevent进行转发,进而进入到Activity,再回转到mDecorView
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,//----3.native的一个处理器 不太清楚是干什么的
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);//----4.输入法相关的拦截处理器,处理完后首先调用到的
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);//----5.【和输入法相关的处理】相关的
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);//----6.在在输入法处理之前调用,该处理中会回调所有View的dispatchKeyEventPreIme(event),进而调用onKeyPreIme()方法
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);-----7.native的在调用到输入法之前的处理

mFirstInputStage = nativePreImeStage;//---此处初始化后面事件处理时需要调用的mFirstInputStage
mFirstPostImeInputStage = earlyPostImeStage;//---此处初始化后面事件处理时需要调用的mFirstPostImeInputStage
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
}
}


}

至此花开两两朵各表一枝:下面会以 1.6.2处的requestLayout()为起点的走一遍View的大致绘制过程,以1.6.3处的WindowInputEventReceiver为起点走一边事件分发的大致流程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息