写点什么

Android 模拟面试,解锁大厂—,这些面试题你会吗

用户头像
Android架构
关注
发布于: 刚刚

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 token) {


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 WindowMa


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


nager.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<View> mViews = new ArrayList<View>();


private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();


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);


//省略代码。。。


}


}


}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android模拟面试,解锁大厂—,这些面试题你会吗