AndroidによるWindowオブジェクトの管理メカニズムの分析
23742 ワード
転載は出典を明記してください.http://blog.csdn.net/crazy1235/article/details/72625679
Windowオブジェクト管理に関するカテゴリ: View Manager WindowManager WindowManagerImpl WindowManagerGlobal View Part View RootImpl ActvityThread WindowManagerService Windowは抽象的なタイプで、具体的な実現類はPhone Windowです.
WindowはViewで積載されています.View RootImplにも対応しています.
WindowにアクセスするにはWindowManagerを通じて実現しなければなりません.
Windowの具体的な操作方法はWindowManager Impl類の中で実現して、方法はView Managerインターフェイスの中で定義します!
addView
WindowManagerImplクラスで初期化されました. mViewセットには、すべてのwindow対応のViewオブジェクトが格納されています. mRoots集合は、すべてのwindowに対応するView RootImplオブジェクト を記憶している. mParamsのセットは、すべてのwindowに対応するレイアウトパラメータ を記憶している. mDyingViewのセットには、削除されているすべてのwindowオブジェクト が格納されている.
set View()の内部でrequest Layout()を呼び出し、描画プロセスを開始しました.
Viewの描画プロセスはView RootImplによって完成されます.
request Layout()描画プロセスが完了したら、WindowSessionを通じてWindowの追加プロセスが完了します.
本当の実現者はSessionです.
udateView Layout
WindowMangerImpl.java
removeView
View Managerインターフェースには削除機能が一つしかありません.
どちらもWindows ManagerGlobalのremoveView()関数を呼び出します.
WindowManagerImpl.java
Session.java
Windowオブジェクト管理に関するカテゴリ:
WindowはViewで積載されています.View RootImplにも対応しています.
WindowにアクセスするにはWindowManagerを通じて実現しなければなりません.
Windowの具体的な操作方法はWindowManager Impl類の中で実現して、方法はView Managerインターフェイスの中で定義します!
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
View Managerインターフェイスは三つの関数を定義しています.それぞれwindowの追加、更新、削除に対応しています.addView
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
実はWindowManagerImplも具体的な操作をしていません.WindowManagerGlobalに任せました.WindowManagerImplクラスで初期化されました.
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
WindowManager Global.javaprivate WindowManagerGlobal() {
}
public static WindowManagerGlobal getInstance() {
synchronized (WindowManagerGlobal.class) {
if (sDefaultWindowManager == null) {
sDefaultWindowManager = new WindowManagerGlobal();
}
return sDefaultWindowManager;
}
}
これは一例のパターンです.private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList();
private final ArrayList mParams =
new ArrayList();
private final ArraySet mDyingViews = new ArraySet();
WindowManager Globalには4つの重要な集合があります.public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
// 1. !
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 {
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; // ViewRootImpl
View panelParentView = null; // View
synchronized (mLock) {
// ...
// view index
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {// view, ViewRootImpl.doDie()
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
}
// ...
// ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
//
view.setLayoutParams(wparams);
// view
mViews.add(view);
// ViewRootImpl
mRoots.add(root);
// wparams
mParams.add(wparams);
}
try {
// view ViewRootImpl !
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// view
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
関数は最後にView RootImpl.setView()を通じてwindowの添加過程を完成します.set View()の内部でrequest Layout()を呼び出し、描画プロセスを開始しました.
Viewの描画プロセスはView RootImplによって完成されます.
request Layout()描画プロセスが完了したら、WindowSessionを通じてWindowの追加プロセスが完了します.
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
// ...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
// ...
}
mWindowSessionは、Binderオブジェクトです.本当の実現者はSessionです.
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
ここでWindow Manager Serviceを通じてwindowの追加を実現します.そうすると、windowの追加事務はWMSに任せて処理します.udateView Layout
WindowMangerImpl.java
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
// ...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
//
view.setLayoutParams(wparams);
synchronized (mLock) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
mParams.remove(index);
mParams.add(index, wparams); // mParams
root.setLayoutParams(wparams, false); // ViewRootImpl , false view
}
}
View RooImpl.javavoid setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
// ...
if (newView) {
mSoftInputMode = attrs.softInputMode;
requestLayout();
}
//...
mWindowAttributesChanged = true;
scheduleTraversals();
}
}
この関数では、scheduleTraversals()を呼び出して測定、レイアウト、描画プロセスを行います.removeView
View Managerインターフェースには削除機能が一つしかありません.
public void removeView(View view);
WindowManagerインターフェースにviewを削除する方法が追加されました.public void removeViewImmediate(View view); //
この2つの方法は、同期削除を表し、非同期削除を表します.どちらもWindows ManagerGlobalのremoveView()関数を呼び出します.
WindowManagerImpl.java
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
@Override
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}
WindowManager Global.javapublic void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
// view
int index = findViewLocked(view, true);
// mRoots view
View curView = mRoots.get(index).getView();
//
removeViewLocked(index, immediate);
if (curView == view) {
return;
}
throw new IllegalStateException("Calling with view " + view
+ " but the ViewAncestor is attached to " + curView);
}
}
removeView()二つ目のパラメータはすぐに削除するかどうかを表します.private void removeViewLocked(int index, boolean immediate) {
// view ViewRootImpl
ViewRootImpl root = mRoots.get(index);
View view = root.getView();
// ...
// View die()
boolean deferred = root.die(immediate);
if (view != null) {
view.assignParent(null);
if (deferred) { //
mDyingViews.add(view);
}
}
}
View Root Impl.javaboolean die(boolean immediate) {
// , doDie() ! false
if (immediate && !mIsInTraversal) {
doDie();
return false;
}
// ...
// , , true
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
実は非同期削除時に、handler処理時も呼び出したdoDie()関数で削除を完了します.case MSG_DIE:
doDie();
break;
View Root Impl.javavoid doDie() {
checkThread(); // , !
synchronized (this) {
if (mRemoved) { // mRemoved false,doDie() true
return;
}
mRemoved = true;
if (mAdded) { // window ! detach
dispatchDetachedFromWindow();
}
if (mAdded && !mFirst) {
destroyHardwareRenderer(); //
if (mView != null) {
int viewVisibility = mView.getVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
if (mWindowAttributesChanged || viewVisibilityChanged) { // window
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
}
}
mSurface.release(); //
}
}
mAdded = false; //
}
WindowManagerGlobal.getInstance().doRemoveView(this);
}
WindowManager Global.javavoid doRemoveView(ViewRootImpl root) {
synchronized (mLock) {
final int index = mRoots.indexOf(root);
if (index >= 0) {
mRoots.remove(index);// ViewRootImpl
mParams.remove(index); //
final View view = mViews.remove(index); // view
mDyingViews.remove(view);// view
}
}
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
doTrimForeground();
}
}
dispatch DetachedFrom Window()関数を見に来てください.void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow(); // view detach ! onDetachedFromWidow() onDetachedFromWindowInternal()
}
// ...
destroyHardwareRenderer();
// ...
mSurface.release();
// ...
try {
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
// ...
mDisplayManager.unregisterDisplayListener(mDisplayListener);
unscheduleTraversals();
}
再度IPCでremove()関数を呼び出します.Session.java
public void remove(IWindow window) {
mService.removeWindow(this, window);
}
WMS.javapublic void removeWindow(Session session, IWindow client) {
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return;
}
removeWindowLocked(win);
}
}
void removeWindowLocked(WindowState win) {
removeWindowLocked(win, false);
}
void removeWindowLocked(WindowState win, boolean keepVisibleDeadWindow) {
win.mWindowRemovalAllowed = true;
// ...
boolean wasVisible = false;
// ...
removeWindowInnerLocked(win);
// ...
}
removewindowInner Locked(win);方法の内部分析はしばらく停止します!!