概述
在Android开发领域,深入理解应用启动与事件处理机制是进阶的关键。接下来,我们将结合相关流程图,从源码层面详细解读这一复杂过程。
一、AMS驱动应用启动的源码剖析
当点击应用图标启动应用时,AMS的attachApp
方法被调用,这一过程在Binder线程中执行。在ActivityManagerService.java
源码中,attachApp
会与ActivityThread
进行交互。例如,ActivityThread
中的attach
方法会被远程调用,它会将应用进程与AMS进行关联,完成进程的初始化工作。
// ActivityManagerService部分代码示例
public final void attachApp(int pid) {
// 查找对应的应用进程记录
ProcessRecord app = getProcessRecordLocked(pid, null, false);
if (app != null) {
try {
// 通过Binder调用ActivityThread的attach方法
app.thread.attach(false, mCoreSettingsObserver.getCoreSettingsLocked());
} catch (RemoteException ex) {
// 处理异常情况
}
}
}
AMS在启动Launcher应用进程时,会检查Activity栈中已有的Activity。这涉及到ActivityStackSupervisor
类,它负责管理Activity栈。startSpecificActivityLocked
方法会判断栈中是否有可复用的Activity,若有则直接启动,避免重复创建,提高启动效率。
// ActivityStackSupervisor部分代码示例
private void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true);
if (app != null && app.thread != null) {
try {
realStartActivityLocked(r, app, andResume, checkConfig);
} catch (RemoteException e) {
// 处理异常
}
} else {
// 启动新的应用进程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
}
二、Activity创建与初始化的源码流程
Activity创建时,首先创建PhoneWindow
。在Activity.java
的attach
方法中,会实例化PhoneWindow
,并建立Activity与PhoneWindow
的关联。
// Activity.java部分代码示例
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,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
// 其他初始化操作
}
接着,Activity.onCreate
方法被调用,开发者在该方法中进行初始化操作。ActivityThread
中的handleLaunchActivity
方法会触发Activity
的onCreate
。
// ActivityThread部分代码示例
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 创建Activity实例
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
// 调用Activity的onCreate方法
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished &&!r.startsNotResumed, r.lastProcessedSeq, false);
}
}
Activity.setContentView
会调用PhoneWindow.setContentView
。在PhoneWindow
中,setContentView
会将布局资源解析为视图层级结构。
// PhoneWindow.java部分代码示例
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
// 将布局资源填充到mContentParent中
LayoutInflater.from(mContext).inflate(layoutResID, mContentParent);
// 其他操作
}
三、视图与窗口交互及布局请求的源码分析
ViewRootImpl.setView
将视图树与窗口关联。在ViewRootImpl
的构造函数中,会初始化一些关键变量,setView
方法会将视图添加到窗口中,并开始准备布局。
// ViewRootImpl.java部分代码示例
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
// 其他初始化操作
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
// 向窗口会话添加窗口
try {
mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
// 处理异常
}
// 启动布局流程
requestLayout();
}
}
}
ViewRootImpl.requestLayout
发起布局请求,它会检查是否处于布局中,若未处于布局中,则会通过scheduleTraversals
方法安排一次遍历。
// ViewRootImpl.java部分代码示例
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
系统发出VSync信号后,FrameDisplayEventReceiver.onVsync
被调用,它会触发Choreographer.doFrame
。Choreographer
类负责协调动画、输入和绘制等操作。
// Choreographer.java部分代码示例
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
// 将时间戳转换为合适的格式
long now = System.nanoTime();
if (timestampNanos > now) {
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
}
mHavePendingVsync = true;
mTimestampNanos = timestampNanos;
mFrame = frame;
// 将自身添加到主线程消息队列中
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
}
在Choreographer.doFrame
中,会调用ViewRootImpl.enqueueInputEvent
将输入事件加入队列。
// Choreographer.java部分代码示例
void doFrame(long frameTimeNanos, int frame) {
// 计算时间差
final long startNanos;
if (DEBUG_FRAMES) {
startNanos = System.nanoTime();
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
// 处理输入事件
if (mInputEventReceiver != null) {
mInputEventReceiver.consumeEvents();
}
// 调用ViewRootImpl的相关方法处理事件
for (int i = 0; i < mCallbackQueues.length; i++) {
final CallbackRecord callbacks = mCallbackQueues[i].extractDueCallbacksLocked(frameTimeNanos);
if (callbacks != null) {
executeCallbacks(callbacks);
}
}
// 处理动画和绘制
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
四、事件处理责任链模式的源码实现
在ViewRootImpl.doTraversal
中,会按照责任链模式处理事件。InputStage
是责任链中的节点,NativePreImeInputStage
、EarlyPostImeInputStage
、NativePostImeInputStage
等都继承自InputStage
。
// ViewRootImpl.java部分代码示例
private void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mBatchingInput = false;
// 处理输入事件
if (mPendingInputEvent != null) {
handleInputEvent(mPendingInputEvent);
mPendingInputEvent = null;
}
// 开始遍历
performTraversals();
}
}
// InputStage.java部分代码示例
public abstract class InputStage {
protected final InputStage mNext;
public InputStage(InputStage next) {
mNext = next;
}
public void onProcess(QueuedInputEvent q) {
if (mNext != null) {
mNext.onProcess(q);
}
}
}
当事件到达NativePreImeInputStage
时,它会处理与输入法相关的预处理工作。若该阶段未处理完事件,则会传递给下一个阶段EarlyPostImeInputStage
,依此类推,直到事件被处理。
// NativePreImeInputStage.java部分代码示例
public class NativePreImeInputStage extends InputStage {
public NativePreImeInputStage(InputStage next) {
super(next);
}
@Override
public void onProcess(QueuedInputEvent q) {
// 处理输入法相关的预处理
if (!q.mEvent.isConsumed()) {
forward(q);
} else {
finish(q);
}
}
}
五、总结与实践意义
通过对源码的深入解读,我们清晰地了解了Android应用启动与事件处理的全过程。从AMS的调度,到Activity的创建与初始化,再到视图与窗口的交互以及事件处理的责任链模式,每一个环节都紧密协作。
对于开发者来说,掌握这些原理有助于在开发过程中优化应用性能,例如在Activity启动时合理复用资源,避免不必要的创建操作;在事件处理时,能够更精准地定位问题,提高应用的稳定性和响应速度。同时,这也为我们深入研究Android系统源码、定制化开发以及解决复杂的兼容性问题提供了坚实的理论基础。希望本文能帮助大家在Android开发道路上更上一层楼,不断探索和创新。