(一)AlertDialog的實作模式
AlertDialog的實作模式使用了Builder模式,通過Builder對象來組裝Dialog的各個部分。AlertController用于存儲Builder成員變量中的各個參數。
AlertDialog可以設定title,message,button等參數,這些參數存儲在AlertController.AlertParams的成員變量P中,AlertController.AlertParams中包含了AlertDialog視圖中對應的成員變量。Builder類在調用create函數時會建立AlertDialog,并将P中的儲存的參數應用到AlertDialog的mAlert對象中。這個是通過P.apply函數來實作的。
在調用完create函數後,我們擷取了AlertDialog對象,就可以使用show函數顯示這個對話框。
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);
} else {
// Fill the DecorView in on any configuration changes that
// may have occured while it was removed from the WindowManager.
final Configuration config = mContext.getResources().getConfiguration();
mWindow.getDecorView().dispatchConfigurationChanged(config);
}
onStart();
mDecor = mWindow.getDecorView();
//省略代碼
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
}
show函數執行了三個操作:
1.如果AlertDialog沒有被create,就通過dispatchOnCreate調用了AlertDialog的onCreate方法
2.調用AlertDialog的onStart方法
3.将DecorView添加到WindowManager中
我們看一下onCreate方法的實作。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
然後我們看一下installContent()方法。
public void installContent() {
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();
}
這方法就實作了兩步,(1)設定AlertDialog的内容布局(2)初始化AlertDialog布局中的各個部分。setupView中使用了大量的findViewById來尋找相關的元件,代碼比較龐雜,對此我們就不一一看了。
(二)WindowManager
AlertDialog的視圖最後是将view傳遞給WindowManger來顯示的。事實上所有的要顯示到螢幕上的内容(包括Activity)都是通過WindowManager來進行操作的。
WindowManager是ContextImpl中注冊的衆多服務之一。各種系統服務會注冊到ContextImpl的一個map容器中,然後通過該服務的關鍵字來擷取。
通過getSystemService方法擷取到WindowManger對象後。我們該如何将Window對象和WindowManager建立聯系呢。在Dialog的構造函數中,我們可以看到這麼一行代碼。
w.setWindowManager(mWindowManager, null, null);
我們看一下setWindowManager方法的具體實作。
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
//省略代碼
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
WindowManagerImpl是WindowManagerGlobal的包裝。我們在上一層,通過調用WindowManager的addView方法請求系統将該View顯示到螢幕上,實際上這一切的實作都是通過WindowManagerGlobal的addView方法來實作的。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//代碼省略
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
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;
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;
}
}
這裡建構了ViewRootImpl,将布局參數設定給View,存儲ViewRootImpl,View,LayoutParam到清單中。然後通過ViewRootImpl的setView将View顯示到視窗上。
ViewRootImpl實作了native層和Java層View系統通信的橋梁。它會檢測系統中View的消息,并通過調用方法來繪制整棵視圖樹。我們看一下ViewRootImpl的建構方法。
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
//省略代碼
}
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;
}
}
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
從上文代碼中可以看到,Android的架構層和native的wms是通過Binder機制進行通信的。架構層通過了Binder機制和Native建立了聯系,并通過了openSession與WMS建立通行會話。
WMS管理的是View的Z軸。
在與WMS建立完聯系後,我們會調用ViewRootImp的setView方法。該方法會向WMS發送顯示Dialog或者Activity中的DecorView的請求,具體代碼如下:
setView方法很複雜,但是主要邏輯是兩步:
(1)requestLayout
(2)向WMS發送顯示目前Window的請求
requestLayout方法會向handler中發送一個DO_TRAVERSAL消息,這個消息會觸發整個視圖樹的繪制操作,簡而言之就是周遊整棵樹的各個View,執行了Measure,Layout,Draw方法。
總結:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcpXUq50dnRUTuBnblZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DN3cTM1QzMwATMyIDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
架構層和native層通過binder來進行通信