[정수리] 원본 해석: 다이어로그, popupwindow,activity의 첫 번째view는 어떻게 왔어요?
안드로이드에 익숙해지는 과정에서 하나의view나layout의 초기화나 구조의 절차가 비교적 명확하다는 것을 발견했다. 즉, 아버지 컨트롤에 추가된 다음에 대응하는 생명주기가 시작되었다.그러나 전체 인터페이스의 아버지 컨트롤러, 또는 시스템의 첫 번째view는 어떻게 생겼고, 어떻게 초기화하고 그렸을까?
개술
개술: 저를 괴롭히는 문제를 가지고 앞에서 응용 인터페이스와 프레임워크의 관계를 계속 분석하고viewrootimpl의 출처를 분석하며dialog,popupwindow,activity의 루트view의 창설 절차를 결합시켜 질문 인터페이스의 루트view나 첫 번째view가 어떻게 초기화되고 프레임워크에 추가되었는지 대답합니다.
viewrootimpl의 출처 분석
본고의 분석은 전편의 을 이어서 위윈도 관리자에서 인터페이스에 대한 처리를 간략하게 분석했다.
각종 검색 방법을 사용하면 모든android 코드 중 ViewRootImpl이라는 종류를 인용한 곳만 볼 수 있습니다. 바로
android.view.WindowManagerImpl.addView(View, LayoutParams, CompatibilityInfoHolder, boolean)
분석 코드를 통해 알 수 있듯이 window 관리자는ddview () 과정에서 추가된view를 관리하기 위해 세 개의 그룹을 사용했다
private View[] mViews;
private ViewRootImpl[] mRoots;
private WindowManager.LayoutParams[] mParams;
코드 처리에서view의context를 통해 대응하는 ViewRootImpl을 구성한 다음view,rootViewImpl,layoutParams 세 변수를 그룹에 저장한다.그리고 마지막으로 setView. root = new ViewRootImpl(view.getContext());
root.mAddNesting = 1;
if (cih == null) {
root.mCompatibilityInfo = new CompatibilityInfoHolder();
} else {
root.mCompatibilityInfo = cih;
}
view.setLayoutParams(wparams);
if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
Object[] old = mViews;
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
old = mRoots;
mRoots = new ViewRootImpl[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
System.arraycopy(old, 0, mParams, 0, index-1);
}
index--;
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
// do this last because it fires off messages to start doing things
root.setView(view, wparams, panelParentView);
setview에서 바로 앞의 measure 과정에서 제기된 문제입니다.view는 어디에서 왔습니까- 참조- 자, 이제 알겠습니다. 루트 뷰. 최종 처리된view는 윈도우 관리자에서dd가 들어왔습니다.그럼 넝쿨을 타고 참외를 만져보세요. 도대체 윈도 관리자 Impl이 어디에 호출되었는지 보세요.addView()
ViewRootImpl(Context) - android.view.ViewRootImpl
addView(View, LayoutParams, CompatibilityInfoHolder, boolean) : void - android.view.WindowManagerImpl
addView(View, LayoutParams, CompatibilityInfoHolder) : void - android.view.WindowManagerImpl
addView(View, LayoutParams) : void - android.view.WindowManagerImpl
addIntruderView() : void - com.android.systemui.statusbar.phone.PhoneStatusBar
addNavigationBar() : void - com.android.systemui.statusbar.phone.PhoneStatusBar
addPanelWindows() : void - com.android.systemui.statusbar.tablet.TabletStatusBar (5 matches)
addStartingWindow(IBinder, String, int, CompatibilityInfo, CharSequence, int, int, int) : View - com.android.internal.policy.impl.PhoneWindowManager
addView(View) : void - android.view.WindowManagerImpl
advance() : void - com.android.systemui.statusbar.tablet.TabletTicker
handleResumeActivity(IBinder, boolean, boolean) : void - android.app.ActivityThread
handleShow() : void - android.widget.Toast.TN
invokePopup(LayoutParams) : void - android.widget.PopupWindow
makeVisible() : void - android.app.Activity
onBarViewAttached() : void - com.android.systemui.statusbar.phone.PhoneStatusBar
onCreate() : void - com.android.systemui.LoadAverageService
openPanel(PanelFeatureState, KeyEvent) : void - com.android.internal.policy.impl.PhoneWindow
setVisible(boolean) : void - android.widget.ZoomButtonsController
show() : void - android.app.Dialog
show() : void - com.android.internal.policy.impl.KeyguardViewManager
show(int) : void - android.widget.MediaController
showCompatibilityHelp() : void - com.android.systemui.statusbar.tablet.TabletStatusBar
showSafeModeOverlay() : void - com.android.server.am.ActivityManagerService
start() : void - com.android.systemui.statusbar.StatusBar
startAnimation(Runnable, int, int, boolean, boolean) : void - com.android.systemui.screenshot.GlobalScreenshot
updateRecentsPanel() : void - com.android.systemui.statusbar.phone.PhoneStatusBar
updateSettings() : void - com.android.internal.policy.impl.PhoneWindowManager
호출을 살펴보면 많은 곳에서 호출이 있음을 알 수 있다.대충 지나가면 아이폰 Status Bar,Activity Thread,Phone Window,Popup Window,Activity,Toast,Dialog 등 익숙한 것들을 많이 발견할 수 있다.그러면 이 익숙한 컨트롤러와 클래스는 윈도 관리자를 통해 자신의view와 인터페이스를 시스템에 추가하는 것이 뚜렷하다.Dialog가 window 관리자에 어떻게 가입했는지 분석
감은 연한 것부터 줍고 쉬운 것을 먼저 골라라.다음 show ():void - android.app.Dialog
자주 호출되는 내로라하는 쇼(show)잖아요.dialog에서 마지막으로 호출한 show () 방법을 다 썼습니다. 맞습니다. 바로 그것입니다.이 컨트롤을 보면 확실히 이렇다. 윈도 관리자, show의 다이어로그, 바로 윈도 관리자를 통해.addview 해봐.그럼 ddview일 때는 다이어로그의 루트view, 아버지 컨트롤이어야 합니다.코드를 보고 우리의 추측을 검증해 봅시다.
/**
* 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)) {
mActionBar = new ActionBarImpl(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 {
}
}
dd가 윈도 관리자에 들어간 것은 이 mDecor입니다. m윈도에서 왔습니다.getDecorView(); /**
* Retrieve the top-level window decor view (containing the standard
* window frame/decorations and the client's content inside of that), which
* can be added as a window to the window manager.
*
* <p><em>Note that calling this function for the first time "locks in"
* various window characteristics as described in
* {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.</em></p>
*
* @return Returns the top-level window decor view.
*/
public abstract View getDecorView();
주석에서 설명한 것은 top-level window decor view가 맞습니다.앞의 추측을 입증했다.다음은 이 mDecor가 도대체 무엇인지 봅시다.
구체적인 실현com을 찾아라.android.internal.policy.impl.PhoneWindow.getDecorView()
@Override
public final View getDecorView() {
if (mDecor == null) {
installDecor();
}
return mDecor;
}
설치 데코() 호출됨 private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
}
<span style="white-space:pre"> </span>//......
}
generateDecor()를 계속합니다. protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
public DecorView(Context context, int featureId) {
super(context);
mFeatureId = featureId;
}
/** The feature ID of the panel, or -1 if this is the application's DecorView */
private final int mFeatureId;
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker
마지막으로 클래스 정의에서DecorView는FrameLayout이고 RootViewSurfaceTaker를 실현했다.그래서 돌이켜보면 이 top-level window decor view는 window 관리자에 add가 들어간 것이 바로 framelayout이다.
이 점은 Hierarchyviewer를 통해 UI를 분석할 때 증명됩니다.
어떻게 사용하는지는 공식 문서인'Using Hierarchy Viewer'로 이동하십시오. 이미 많은 사람들이 중국어 문서를 썼기 때문에 더 이상 군말을 하지 않습니다.
자, 이제 시스템 다이어로그에 대응하는 맨 윗부분view는 프레임 레이아웃이고 프레임워크에 대응하는viewrootimpl에 대응하는 루트view입니다.
Popup Window가 어떻게 했는지
그리고 일거수일투족으로 팝업 윈도가 어떻게 되는지 봅시다.
invokePopup(LayoutParams) : void - android.widget.PopupWindow
showAsDropDown(View, int, int) : void - android.widget.PopupWindow
showAtLocation(IBinder, int, int, int) : void - android.widget.PopupWindow
이 인터페이스 show AsDrop Down이 바로 Popup Window의api잖아요.여기에 관건적인 코드를 간단하게 열거하면 일일이 분석하지 않겠다.
mWindowManager.addView(mPopupView, p);
if (mBackground != null) {
final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
int height = ViewGroup.LayoutParams.MATCH_PARENT;
if (layoutParams != null &&
layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
height = ViewGroup.LayoutParams.WRAP_CONTENT;
}
// when a background is available, we embed the content view
// within another view that owns the background drawable
PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, height
);
popupViewContainer.setBackgroundDrawable(mBackground);
popupViewContainer.addView(mContentView, listParams);
mPopupView = popupViewContainer;
} else {
mPopupView = mContentView;
public void setContentView(View contentView) {
if (isShowing()) {
return;
}
mContentView = contentView;
if (mContext == null && mContentView != null) {
mContext = mContentView.getContext();
}
if (mWindowManager == null && mContentView != null) {
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
}
}
그래서 Popup Window는 set Content View의view를 window 관리자에 추가했습니다.다음은 액티비티.
그럼 가장 많이 쓰는 액티비티 중에는 어떤 게 있을까요?
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
이곳의 mDecor는 앞의 다이어로그와 팝업 윈도에서 분석하기 쉽지 않다.우선 액티비티라는 클래스를 훑어보았는데 부치문이 없고 기본 클래스도 없었다.마지막으로 모든 mDecor 호출을 확인합니다.
mDecor - android.app.Activity
dispatchKeyEvent(KeyEvent) : boolean - android.app.Activity
handleDestroyActivity(IBinder, boolean, int, boolean) : void - android.app.ActivityThread (2 matches)
handleResumeActivity(IBinder, boolean, boolean) : void - android.app.ActivityThread (2 matches)
handleSendResult(ResultData) : void - android.app.ActivityThread
handleWindowVisibility(IBinder, boolean) : void - android.app.ActivityThread
makeVisible() : void - android.app.Activity (2 matches)
onWindowAttributesChanged(LayoutParams) : void - android.app.Activity
setVisible(boolean) : void - android.app.Activity
updateVisibility(ActivityClientRecord, boolean) : void - android.app.ActivityThread
한 명씩 보기, 마지막으로handle ResumeActivity():void - android.app.ActivityThread에서 관련 지정이 발견되었습니다.
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
<span style="color:#ff0000;">View decor = r.window.getDecorView();</span>
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
<span style="color:#ff0000;">a.mDecor = decor;</span>
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
<span style="white-space:pre"> </span>//......
}
여기 코드는 비교적 많은 내용을 포함하고 주의력을 집중하여decorView를 보고 decor=r.window를 주목한다.getDecorView();. 반면ActivityClientRecordr=performResumeActivity(token,clearHide);
구체적인resume의activity의window의decorView()라는 뜻이다.
앞의 다이어로그 부분의 분석을 통해 아이폰 윈도우를 사용하면 바로 프레임워크 아웃의 그 decorView라는 것을 알 수 있다.현재 다른 유형의 윈도우가 없다. 이는 윈도우의 계승 관계를 보면 알 수 있다.
여기서 알 수 있듯이activity가resume에 있을 때visible인지 판단을 통해 activity의windowdecorView를window 관리자에 추가하면activity의 생명주기는 대응하는 상태에서 window 관리자에서decorView를 제거해야 한다.
앞에서 mDecor의 호출에서android가 발견되었습니다.app.ActivityThread.handleDestroyActivity(Ibinder,boolean,int,boolean), 중.
private void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
if (r != null) {
cleanUpPendingRemoveWindows(r);
WindowManager wm = r.activity.getWindowManager();
<span style="color:#ff0000;">View v = r.activity.mDecor;</span>
if (v != null) {
if (r.activity.mVisibleFromServer) {
mNumVisibleActivities--;
}
IBinder wtoken = v.getWindowToken();
if (r.activity.mWindowAdded) {
if (r.onlyLocalRequest) {
// Hold off on removing this until the new activity's
// window is being added.
r.mPendingRemoveWindow = v;
r.mPendingRemoveWindowManager = wm;
} else {
<span style="color:#ff0000;"> wm.removeViewImmediate(v);</span>
}
}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>//......
}
이로써 다이어로그, popupwindow, 그리고activity의 일부 원본을 보고 일반 인터페이스(dialog, popupwindow, 그리고activity)의 첫 번째view, 어떻게 왔는지, 시스템에 어떻게 가입했는지, 즉 window Manager를 알게 되었다.한 마디로 결론적으로 응용 차원의 인터페이스는 모두 window 관리자를 통해 프레임워크에 추가된 것이다. ViewRootImpl은 프레임워크가view에 대한 추상적이고 인터페이스 관리의 루트이다.
꼬리
첫 번째 문제를 파악한 다음에view의 창설, 그리기,layout 과정을 비교적 완전하게 되돌아보려고 합니다.to be continued...
분석 과정에서 프레임워크에서 activity를 처리하는 일부 절차,handle ResumeActivity(),handle DestroyActivity()를 간단하게 접했다.또 다른 문제는 시스템 프레임워크가activity의 생명주기를 어떻게 관리하는가이다.//TODO
첫 번째 문제를 파악한 다음에view의 창설, 그리기,layout 과정을 비교적 완전하게 되돌아보려고 합니다.to be continued...
분석 과정에서 프레임워크에서 activity를 처리하는 일부 절차,handle ResumeActivity(),handle DestroyActivity()를 간단하게 접했다.또 다른 문제는 시스템 프레임워크가activity의 생명주기를 어떻게 관리하는가이다.//TODO
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Asp와 XML로 상호작용하는 실례 원본XML은 표준 확장 언어로 미래 웹 프로그래밍의 표준이다. asp는 현재 널리 전해지는 웹 프로그래밍 언어 중의 하나이다. 그들 두 사람이 연합하여 역할을 발휘할 수 있을까?두부는 여기서 여러분에게 아주 간단한 As...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.