Android UI绘制原理——ActivityWindowViewRootImpl基本关系
Posted cao_null
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android UI绘制原理——ActivityWindowViewRootImpl基本关系相关的知识,希望对你有一定的参考价值。
代码路径
/frameworks/base/core/java/android/app/ActivityThread.java
/frameworks/base/core/java/android/app/Activity.java
/frameworks/base/core/java/android/view/Window.java
/frameworks/base/core/java/android/view/WindowManagerImpl.java
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
/frameworks/base/core/java/android/view/ViewRootImpl.java
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
/frameworks/base/services/core/java/com/android/server/wm/Session.java
先放一张时序图和类图
之前分析过Activity启动流程,重温一下ActivityThread的部分
/frameworks/base/core/java/android/app/ActivityThread.java
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent)
...
final Activity a = performLaunchActivity(r, customIntent);
...
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent)
...
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, window, r.configCallback);
...
然后看attach的过程
/frameworks/base/core/java/android/app/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)
//创建PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(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);
//设置PhoneWindow的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();
看Window的方法
/frameworks/base/core/java/android/view/Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated)
...
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
开始创建WindowManagerImpl
/frameworks/base/core/java/android/view/WindowManagerImpl.java
public WindowManagerImpl createLocalWindowManager(Window parentWindow)
return new WindowManagerImpl(mContext, parentWindow);
//只是简单的赋值
private WindowManagerImpl(Context context, Window parentWindow)
mContext = context;
mParentWindow = parentWindow;
接下来会执行handleResumeActivity
/frameworks/base/core/java/android/app/ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason)
...
if (r.window == null && !a.mFinished && willBeVisible)
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow)
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null)
impl.notifyChildRebuilt();
//一般都是true,除非setVisible为false
if (a.mVisibleFromClient)
if (!a.mWindowAdded)
a.mWindowAdded = true;
//在这里把DecorView加到WindowManager里
wm.addView(decor, l);
else
// The activity will get a callback for this @link LayoutParams change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
实际调用的是WindowManagerImpl的addView
/frameworks/base/core/java/android/view/WindowManagerImpl.java
//单例模式
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params)
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
看具体addView过程
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
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>();
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow)
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock)
...
//创建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
//添加到List
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try
//继续往下调用
root.setView(view, wparams, panelParentView);
catch (RuntimeException e)
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0)
removeViewLocked(index, true);
throw e;
继续看ViewRootImpl
/frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView)
synchronized (this)
// 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();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)
mInputChannel = new InputChannel();
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
catch (RemoteException e)
//重置状态
...
//设置ViewRootImpl为DecorView的Parent
view.assignParent(this);
...
mWindowSession从WindowManagerGlobal
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
public static IWindowSession getWindowSession()
synchronized (WindowManagerGlobal.class)
if (sWindowSession == null)
try
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub()
@Override
public void onAnimatorScaleChanged(float scale)
ValueAnimator.setDurationScale(scale);
,
imm.getClient(), imm.getInputContext());
catch (RemoteException e)
throw e.rethrowFromSystemServer();
return sWindowSession;
这里的windowManager对象其实就是WMS
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
public static IWindowManager getWindowManagerService()
synchronized (WindowManagerGlobal.class)
if (sWindowManagerService == null)
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try
if (sWindowManagerService != null)
ValueAnimator.setDurationScale(
sWindowManagerService.getCurrentAnimatorScale());
catch (RemoteException e)
throw e.rethrowFromSystemServer();
return sWindowManagerService;
通过WMS获取到sWindowSession的binder然后调用addToDisplay,这是一个AIDL请求。
mWindow是在ViewRootImpl构造方法中创建的
/frameworks/base/core/java/android/view/ViewRootImpl.java
//静态内部类,继承自IWindow
static class W extends IWindow.Stub
private final WeakReference<ViewRootImpl> mViewAncestor;
private final IWindowSession mWindowSession;
W(ViewRootImpl viewAncestor)
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeNavBar, int displayId,
DisplayCutout.ParcelableWrapper displayCutout)
...
@Override
public void moved(int newX, int newY)
...
@Override
public void dispatchAppVisibility(boolean visible)
...
...
到这可以看出这个接口是为了WMS回调应用进程准备的,继续看WMS怎么处理。
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext)
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext);
return session;
/frameworks/base/services/core/java/com/android/server/wm/Session.java
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel)
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
调用WMS的addToDisplay方法,然后又回到了WMS,最终WMS通过IWindow接口回调W,最终通知ViewRootImpl,到此流程基本分析完成。
总结:
PhoneWindow:
继承自Window,每个Activity有一个PhoneWindow主要负责生成DecorView,根据不同的FLAG和布局xml生成布局文件。
WindowManagerImpl:
实现WindowManager接口,PhoneWindow创建出WindowManagerImpl,WindowManager接口继承自ViewManager,主要负责通过WindowManagerGlobal实现addView,removeView,updateViewLayout操作。
WindowManagerGlobal:
单例对象,每个应用进程对应一个WindowManagerGlobal。持有WindowSession、WindowManagerService,生成ViewRootImpl,管理根View集合,ViewRootImpl集合。
ViewRootImpl:
所有View的根,处理WMS远程的binder事件,连接了View和Window,绘制事件的发起,点击事件处理等,是一个入口大管家。
以上是关于Android UI绘制原理——ActivityWindowViewRootImpl基本关系的主要内容,如果未能解决你的问题,请参考以下文章
Android UI绘制原理——ActivityWindowViewRootImpl基本关系
Android UI绘制原理——ActivityWindowViewRootImpl基本关系