Dialog의 작성 프로세스를 한 걸음 한 걸음 추적(1)
16421 단어 android창설dialogDecorViewRootViewImpl
하나.Dialog의 구조 함수
구조 함수에서 출발하여 모든 구조 함수는 아래의 이 구조 함수를 호출한다.
public Dialog(Context context, int theme) {
this(context, theme, true);
}
Dialog(Context context, int theme, boolean createContextThemeWrapper) {
if (createContextThemeWrapper) {
if (theme == 0) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
outValue, true);
theme = outValue.resourceId;
}
mContext = new ContextThemeWrapper(context, theme);
} else {
mContext = context;
}
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
}
중요하지 않은 것을 제거하는데 이 안에는 두 가지가 특히 중요하다. mWindow 관리자와 mWindow이다.그것들은 각각 창 관리 클래스와 하나의 창을 대표하는 클래스이다.mWindow를 만드는 데는 Policy Manager라는 클래스를 사용합니다. 이 클래스는androidapi에 없고 시스템 수준의 클래스입니다.그래서 이 클래스를 사용하여 윈도우를 만들고 직접 다이얼로그를 만드는 것은 비교적 어렵다.당분간 이런 생각은 하지 않겠습니다. 이 창을 대표하는 클래스 (Window) 는 어떤 것입니까?mWindow Manager는 또 어떻게 창을 관리합니까?문제를 가지고 코드를 계속 추적하다.일단 mWindow가 뭔지 보자.둘.Window 및 PhoneWindow 클래스에 대한 설명은 다음과 같습니다.
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
* window manager. It provides standard UI policies such as a background, title
* area, default key processing, etc.
*
* <p>The only existing implementation of this abstract class is
* android.policy.PhoneWindow, which you should instantiate when needing a
* Window. Eventually that class will be refactored and a factory method
* added for creating Window instances without knowing about a particular
* implementation.
*/
이 말은 윈도 클래스는 추상적인 맨 윗부분 창의 외관과 행위 전략의 추상적인 클래스라는 뜻이다.이 종류의 실례는 윈도우 관리자에 층을 정한view로 추가해야 합니다.Window는 배경, 제목 영역, 기본 키 처리 등 표준 UI 정책을 제공합니다.
이 종류의 유일한 실례는 바로 Phone Window입니다. 우리가 윈도를 필요로 할 때, Phone Window는 실례화되어야 합니다.최종적으로, 이 클래스는 재구성되고, 윈도우를 만드는 실례를 만드는 공장 방법을 추가합니다. 그러면 이 클래스를 만드는 구체적인 세부 사항을 숨깁니다.
다음은 Phone Window입니다. 이 Window의 유일한 실현 클래스는 UI의 외관 그리기와 이벤트 처리를 어떻게 실현하는지 보십시오.
다음은 구조 함수입니다.
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
구조 함수는 Layout Inflater의 실례를 얻었다. 이 실례는view를 구성하는 데 사용되기 때문에 Phone Window에서 어떤view를 구성할 것으로 추측할 수 있다.
구조 함수를 봤는데 뭘 봐야 되지?이 종류에는 많은 함수가 있는데, 어쨌든 한 번 다 볼 수는 없겠지?이럴 때 생각이 없어지면 다이아로그류를 돌아보고 다이아로그를 어떻게 나타냈는지 봐야 한다.
셋.show () 방법
우리가 Dilog를 어떻게 사용했는지 생각해 보자. 일반적으로 Dilog 대상을 만들고 한 무더기의 물건을 설정한다. 무엇을 설정하든지 최종적으로 show () 방법을 호출해야 한다. 그렇지 않으면 Dialog가 나타나지 않기 때문에 비밀은 show () 방법에 있는 것 같다.
그렇다면 쇼 방법은 무엇일까?
/**
* Start the dialog and display it on screen. The window is placed in the
* application layer and opaque. Note that you should not override this
* method to do initialization when the dialog is shown, instead implement
* that in {@link #onStart}.
*/
public void show() {
if (mShowing) {
if (mDecor != null) {
if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
}
mDecor.setVisibility(View.VISIBLE);
}
return;
}
mCanceled = false;
if (!mCreated) {
dispatchOnCreate(null);
}
onStart();
mDecor = mWindow.getDecorView();
if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
final ApplicationInfo info = mContext.getApplicationInfo();
mWindow.setDefaultIcon(info.icon);
mWindow.setDefaultLogo(info.logo);
mActionBar = new WindowDecorActionBar(this);
}
WindowManager.LayoutParams l = mWindow.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
nl.copyFrom(l);
nl.softInputMode |=
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
l = nl;
}
try {
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
} finally {
}
}
코드가 비교적 많고 주간을 잡는다.mWindow에서 DecorView 객체를 가져옵니다.2. Window Manager의 addView() 방법을 사용하여 DecorView를 추가합니다.그렇다면 이 DecorView는 무엇일까요?넷.DecorView
DecorView의 정의는 다음과 같습니다.
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
DecorVeiw의 정의에서 볼 수 있듯이 FrameLayout을 계승했다. 즉, 이것은 하나의 View이다.세 번째 show () 방법에서 DecorView가 처음으로 윈도우 관리자에 추가된 것은 DecorView가 윈도우의 루트 View라는 것을 의미하는 것입니까?그래야지, 그렇지 않으면 또 누가 있겠는가?DecorView에서 분석을 많이 하지 않았습니다. 왜냐하면, 제가 알고 싶은 것은Dialog가 디스플레이에 생성되는 과정입니다.오.mWindowManager,addView(...)도대체 무슨 짓을 한 거야?
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
mGlobal의addview(...)를 다시 호출한 것을 볼 수 있습니다.메서드, 이 메서드는 다음과 같습니다. public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
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 {
// If there's no parent and we're running on L or above (or in the
// system context), assume we want hardware acceleration.
final Context context = view.getContext();
if (context != null
&& context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
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.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
이 방법은 비교적 복잡하다. 코드는 매우 길지만, 하는 일은 결코 복잡하지 않다. 앞에서 무엇을 하든지, 마지막으로, 코드는view, 루트, wparams와 대응하는 데이터 구조에 추가된다.view는 Dialog에서 전해 내려오는 DecorView입니다.
wparams는 우리가 전해 준 또 다른 매개 변수입니다. 여기에 또 처리를 했습니다.
세 가지 데이터 구조는 다음과 같습니다.
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>();
여기에 무거워 보이는 또 다른 것이 생겼다. 바로 루트다. 이것은 ViewRootImpl의 실례이다.그럼 ViewRootImpl은 또 뭐 하는 거예요?먼저 알아본 다음에 그것을 쓸 때 다시 자세하게 분석해라.root,view,mParams 세 개는 틀림없이 연락이 있을 거야, 마지막.
root.setView(view, wparams, panelParentView);
, 。 。 , ViewRootImpl,WindowSession 。
여섯.ViewRootImpl
구조 함수는 다음과 같습니다.
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mDisplayAdjustments = display.getDisplayAdjustments();
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
mAdded = false;
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityInteractionConnectionManager =
new AccessibilityInteractionConnectionManager();
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
mHighContrastTextManager = new HighContrastTextManager();
mAccessibilityManager.addHighTextContrastStateChangeListener(
mHighContrastTextManager);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
loadSystemProperties();
mWindowIsRound = context.getResources().getBoolean(
com.android.internal.R.bool.config_windowIsRound);
}
구조 함수에서 IWindow Session의 실례를 얻었는데, 이 종류는 또 무엇을 하는 것입니까????
일곱IWindowSession
IWindowSession은 구현 클래스가 Session인 인터페이스로, Session의 정의는 다음과 같습니다.
final class Session extends IWindowSession.Stub
에서 볼 수 있듯이 이것은 binder 클래스로 서비스와 통신할 수 있다.이렇게 좀 알아봤으면 좋겠어, 본분을 잃어서는 안 돼.여덟root.setView(view,wparams,panelParentView)가 다시 이 방법으로 돌아가 이 방법이 도대체 무엇을 했는지 살펴보자.
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
<span style="white-space:pre"> </span>...
// 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();
<span style="white-space:pre"> </span>...
<span style="white-space:pre"> try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, 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();
}
}</span>
}
}
}
이 함수는 매우 길고 주요한 단계는 RequestLayout()을 호출하는 것이다.리퀘스트 Layout 호출에 대한 설명입니다: window Manager에 가입하기 전에 첫 번째layout을 호출합니다.시스템의 다른 이벤트를 받기 전에 Relayout을 합니다.이후 mWindowSession을 사용했습니다.addToDisplay 방법.mWindowSession은 실제로 Session의 실례이며, addToDisplay 방법은 다음과 같습니다. @Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outInputChannel);
}
여기에서 mService가 호출된 것을 볼 수 있습니다.dd Window, 여기는 분명히 프로세스 통신입니다. mService는 Window Manager 서비스의 실례입니다. 즉, 진정한 window 추가는 실제로 Window Manager 서비스에서 이루어집니다.
아홉임시 소결
밤이 깊어서 하루 종일 피곤했고 피곤한 기운이 넘쳐 잠을 잘 시간이고 내일도 일찍 일어나서 출근해야 한다.여기까지만 분석해 보면 이러한 추적을 통해 적어도 다음과 같은 결론을 얻을 수 있다.
1. DecorView는 루트 뷰입니다.
2. ViewRootImpl의 setView 방법은 DecorView와 ViewRootImpl을 밀접하게 연결시킨다.
3. Window Manager Service의ddWindow는 최종적으로 Window를 추가했습니다.
뷰 트리를 그리기 시작한 곳을 추적했을 거예요. 구체적으로 어떻게 그렸는지, 아직 긴 코드가 있을 거예요. 이 부분은 다음 절에서 탐색해 보세요.
마지막으로 이것은 제가 처음으로 이 부분의 코드를 분석하려고 시도한 것입니다. 분석이 비교적 거칠고 잘못된 부분도 있을 수 있으니 여러분의 지적을 바랍니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.