其他分享
首页 > 其他分享> > Android高工面:Activity创建到View呈现中间发生了什么?子线程到底能不能更新UI

Android高工面:Activity创建到View呈现中间发生了什么?子线程到底能不能更新UI

作者:互联网

}

handleLaunchActivity()主要调用了两个方法:performLaunchActivity()和handleResumeActivity()

performLaunchActivity

我们进入performLaunchActivity()方法,核心代码如下:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
ComponentName component = r.intent.getComponent();
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//创建Activity
Activity activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
Application app = r.packageInfo.makeApplication(false, mInstrumentation);

if (activity != null) {
//创建Context
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);

//调用Activity.attach。
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);

//省略代码…

//调用Activity.onCreate()方法。
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
r.activity = activity;

if (!r.activity.mFinished) {
//调用Activity.onStart()方法。
activity.performStart();
}
}
r.paused = true;
mActivities.put(r.token, r);
return activity;
}

performLaunchActivity()主要做了以下几件事:

  1. 创建Activity。
  2. 创建Context。
  3. 调用Activity.attach(),创建Window,关联WindowManager。
  4. 调用Activity.onCreate()。
  5. 调用Activity.onStart()。

attach

上面说了,在Activity.attach()方法执行时会创建Window并为Window关联WindowManager。我们看一下伪代码。

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);
//创建Window
mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
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);
}
//设置UI线程
mUiThread = Thread.currentThread();
mMainThread = aThread;
//关联WindowManager
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
}

setContentView

顺着流程图,Activity.setContentView()方法会被调用。Activity.setContentView()内又直接调用了PhoneWindow.setContentView()。我们直接看PhoneWindow.setContentView()的源码。

private DecorView mDecor;

//setContentView传过来的View会被add到mContentParent中。mContentParent的Id是R.id.content。
private ViewGroup mContentParent;

@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
}else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
//省略代码。。。
}

private void installDecor() {
if (mDecor == null) {
//初始化DecorView
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
//省略代码。。。
}
}

如果mContentParent为null,会执行installDecor()方法。generateDecor()源代码很长,但是它的逻辑很简单主要是根据Activity Theme的不同,初始化不同的布局。DecorView的布局虽然不同,但它们都一个Id为R.id.content的FrameLayout。Activity.setContentView()就是在这个FrameLayout中添加子View。

handleResumeActivity

performLaunchActivity()执行完后,紧接着执行handleResumeActivity()。

final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {

//处理Activity的onRestart onResume生命周期。
ActivityClientRecord r = performResumeActivity(token, clearHide);

if (r != null) {
if (r.window == null && !a.mFinished) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
//设置DecorView不可见
decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();

if (a.mVisibleFromClient) {
a.mWindowAdded = true;
//利用WindowManager添加DecorView。
wm.addView(decor, l);
}
}
if (!r.activity.mFinished && r.activity.mDecor != null) {
if (r.activity.mVisibleFromClient) {
//设置DecorView可见。
r.activity.makeVisible();
}
}

//IPC调用,通知AMS Activity启动完成。
ActivityManagerNative.getDefault().activityResumed(token);

} else {
try {
ActivityManagerNative.getDefault()
.finishActivity(token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
}
}
}

handleResumeActivity()处理的事情比较多。我总结为以下几个过程:

  1. 通过performResumeActivity()处理Activity的onRestart onResume的生命周期。
  2. 将DecorView设置为InVisible。
  3. 通过WindowManager.addView()将DecorView绘制完成。
  4. 将DecorView设置为Visiable。
  5. 通知AMS Activity启动完成。

WindowManger.addView()

前面说过,WindowManger是一个抽象类,它的实现类是WindowManagerImpl。WindowManager.addView()封装了View绘制的细节。我们着重看一下。

public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Display mDisplay;
private final Window mParentWindow;

private IBinder mDefaultToken;

public WindowManagerImpl(Display display) {
this(display, null);
}

private WindowManagerImpl(Display display, Window parentWindow) {
mDisplay = display;
mParentWindow = parentWindow;
}

public void setDefaultToken(IBinder t

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

oken) {
mDefaultToken = token;
}

@Override
//这里的View是PhoneWindow内创建的DecorView。
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}

private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {
if (mDefaultToken != null && mParentWindow == null) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (wparams.token == null) {
wparams.token = mDefaultToken;
}
}
}
}

WindowManagerImpl.addView会调用WindowManagerGlobal.addView()。在WindowManagerGlobal.addView()方法执行之前,会先执行applyDefaultToken()方法。这个方法其实是给传进来的DecorView加一个身份标识,表示这个DecorView属于哪个Activity。这样系统(WindowManagerService)才会知道要把DecorView绘制到哪个Activity。

我们继续追踪WindowManagerGlobal.addView(),伪代码如下:

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

//这里的View是PhoneWindow内创建的DecorView。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {

final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
//省略代码…

root = new ViewRootImpl(view.getContext(), display);

//省略代码…

mViews.add(view);
mRoots.add(root);
mParams.add(wparams);

root.setView(view, wparams, panelParentView);
}

首先会创建ViewRootImpl,随后把View、ViewRootImpl、LayoutParams都保存在List中,以供将来更新UI使用。它们的index值相同,这样就三者就对应起来了。最后,调用ViewRootImpl.setView()方法。

ViewRootImpl.setView()

public class ViewRootImpl{

View mView;
//这里的View是PhoneWindow内创建的DecorView。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;

//省略代码。。。

// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();

//省略代码。。。

//IPC通信,通知WMS渲染。
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);

//省略代码。。。
}
}
}

@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
//检查当前执行的线程是不是UI线程
checkThread();
mLayoutRequested = true;
//处理DecorView的measure、layout、draw。
scheduleTraversals();
}
}

void checkThread() {

标签:activity,WindowManager,高工,DecorView,线程,Activity,null,View
来源: https://blog.csdn.net/m0_65511807/article/details/122085975