Dialog源码分析
生活随笔
收集整理的這篇文章主要介紹了
Dialog源码分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄介紹
- 1.簡單用法
- 2.AlertDialog源碼分析
- 2.1 AlertDialog.Builder的構造方法
- 2.2 通過AlertDialog.Builder對象設置屬性
- 2.3 builder.create方法
- 2.4 看看create方法中的P.apply(dialog.mAlert)源碼
- 2.5 看看AlertDialog的show方法
- 3.Dialog源碼分析
- 3.1 Dialog的構造方法
- 3.2 Dialog生命周期
- 3.3 Dialog中show方法展示彈窗
- 3.4 Dialog的dismiss銷毀彈窗
- 4.Dialog彈窗問題分析
- 5.Dialog彈窗總結
好消息
- 博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計47篇[近20萬字],轉載請注明出處,謝謝!
- 鏈接地址:github.com/yangchong21…
- 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質變!
- DialogFragment封裝庫項目地址:github.com/yangchong21…
- 02.Toast源碼深度分析
- 最簡單的創建,簡單改造避免重復創建,show()方法源碼分析,scheduleTimeoutLocked吐司如何自動銷毀的,TN類中的消息機制是如何執行的,普通應用的Toast顯示數量是有限制的,用代碼解釋為何Activity銷毀后Toast仍會顯示,Toast偶爾報錯Unable to add window是如何產生的,Toast運行在子線程問題,Toast如何添加系統窗口的權限等等
- 03.DialogFragment源碼分析
- 最簡單的使用方法,onCreate(@Nullable Bundle savedInstanceState)源碼分析,重點分析彈窗展示和銷毀源碼,使用中show()方法遇到的IllegalStateException分析
- 05.PopupWindow源碼分析
- 顯示PopupWindow,注意問題寬和高屬性,showAsDropDown()源碼,dismiss()源碼分析,PopupWindow和Dialog有什么區別?為何彈窗點擊一下就dismiss呢?
- 06.Snackbar源碼分析
- 最簡單的創建,Snackbar的make方法源碼分析,Snackbar的show顯示與點擊消失源碼分析,顯示和隱藏中動畫源碼分析,Snackbar的設計思路,為什么Snackbar總是顯示在最下面
- 07.彈窗常見問題
- DialogFragment使用中show()方法遇到的IllegalStateException,什么常見產生的?Toast偶爾報錯Unable to add window,Toast運行在子線程導致崩潰如何解決?
- 08.Builder模式
- Builder模式使用場景,簡單案例,Builder模式實際案例Demo展示,看看AlertDialog.Builder源代碼如何實現,為什么AlertDialog要使用builder模式呢?builder模式優缺點分析。關于builder模式經典的案例可以參考我的彈窗封裝庫:github.com/yangchong21…
1.簡單用法
- 一般都是在使用AlertDialog,但AlertDialog主要也是繼承自Dialog。下面我們來分析分析Dialog源碼。
- 最簡單用法如下所示private AlertDialog alertDialog=null; public void showDialog(){AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setIcon(R.mipmap.ic_launcher);builder.setMessage("瀟湘劍雨");builder.setTitle("這個是標題");builder.setView(R.layout.activity_main);builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {alertDialog.dismiss();}});builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {alertDialog.dismiss();}});alertDialog = builder.create();alertDialog.show(); } 復制代碼
2.AlertDialog源碼分析
2.1 AlertDialog.Builder的構造方法
- 先來看一下AlertDialog.Builder的構造方法,這里的Builder是AlertDialog的內部類,用于封裝AlertDialog的構造過程,看一下Builder的構造方法:public Builder(Context context) {this(context, resolveDialogTheme(context, 0));
}
復制代碼
- 然后調用的是Builder的重載構造方法:
- 接著這里的P是AlertDialog.Builder中的一個AlertController.AlertParams類型的成員變量,可見在這里執行了P的初始化操作。public AlertParams(Context context) {mContext = context;mCancelable = true;mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } 復制代碼
- 可以看到這里主要執行了AlertController.AlertParams的初始化操作,初始化了一些成員變量。這樣執行了一系列操作之后我們的代碼:AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); 復制代碼
2.2 通過AlertDialog.Builder對象設置屬性
- 調用了builder.setIcon方法,這里看一下setIcon方法的具體實現:
- 可以看到AlertDialog的Builder的setIcon方法,這里執行的就是給類型為AlertController.AlertParams的P的mIconId賦值為傳遞的iconId,并且這個方法返回的類型就是Builder。
- 調用了builder.setMessage方法,可以看一下builder.setMessage方法的具體實現:
- 跟setIcon方法的實現邏輯類似,都是給成員變量的mMessage賦值為我們傳遞的Message值,且和setIcon方法類似的,這個方法返回值也是Builder。
- 然后看一下builder.setTitle方法:
- 發現builder的setIcon、setMessage、setTitle等方法都是給Builder的成員變量P的icon,message,title賦值。
- 接著看一下builder.setView方法:
- 發現這里的setView和setIcon,setMessage,setTitle等方法都是類似的,都是將我們傳遞的數據值賦值給Builder的成員變量P。
2.3 builder.create方法
- 然后調用了builder.create方法,并且這個方法返回了AlertDialog。
- 可以看到這里首先構造了一個AlertDialog,我們可以看一下這個構造方法的具體實現:
- 可以看到這里首先調用了super的構造方法,而我們的AlertDialog繼承于Dialog,所以這里執行的就是Dialog的構造方法【備注:高版本是繼承AppCompatDialog,然后AppCompatDialog再繼承Dialog】
- 回到AlertDialog的構造方法中,在構造方法中,除了調用Dialog的構造方法之外還執行了
- 相當于初始化了AlertDiaog的成員變量mAlert。
2.4 看看create方法中的P.apply(dialog.mAlert)源碼
- 再AlertDialog.Builder.create方法,在創建了一個AlertDialog之后,又執行了P.apply(dialog.mAlert);這里的P是一個AlertController.AlertParams的變量,而dialog.mAlert是剛剛創建的AlertDialog中的一個AlertController類型的變量,來看一下apply方法的具體實現:
- 在初始化AlertDialog.Builder的時候設置的icon、title、message賦值給了AlertController.AlertParams,這里就是將初始化時候設置的屬性值賦值給我們創建的Dialog對象的mAlert成員變量
2.5 看看AlertDialog的show方法
- 看看如下所示,可以發現直接調用了dialog中的show方法。下面接著分析
3.Dialog源碼分析
3.1 Dialog的構造方法
- 如下所示
- 看源碼可知在Dialog的構造方法中直接直接構造了一個PhoneWindow,并賦值給Dialog的成員變量mWindow,從這里可以看出其實Dialog和Activity的顯示邏輯都是類似的,都是通過對應的Window變量來實現窗口的加載與顯示的。然后我們執行了一些Window對象的初始化操作,比如設置回調函數為本身,然后調用Window類的setWindowManager方法,并傳入了WindowManager。然后創建一個對話框監聽handler對象。
- 接著看看w.setWindowManager(mWindowManager, null, null)里面的源代碼
- 可以看到跟Activity的Window對象的windowManager的獲取方式是相同的,都是通過new的方式創建一個新的WindowManagerImpl對象。
3.2 Dialog生命周期
- dialog的生命周期如下所示/*** 類似于Activity的onCreate函數,可以在這個方法中進行Dialog的一些初始化操作* 包括調用setContentView方法*/ protected void onCreate(Bundle savedInstanceState) { } /*** 當對話框啟動的時候被調用.*/ protected void onStart() { } /*** 當對話框停止的時候被調用.*/ protected void onStop() { } 復制代碼
3.3 Dialog中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;/* 判斷對話框是否創建過,如果沒有創建過* 在dispatchOnCreate里面就會回調onCreate函數*/if (!mCreated) {dispatchOnCreate(null);}//回調onStart函數onStart();//獲取Window對象總的DecorView,如果調用了setContentView就會創建DecorViewmDecor = 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 {//將DecorView添加到WindowManager中,這些就會顯示了mWindowManager.addView(mDecor, l);//將mShowing置為truemShowing = true;sendShowMessage();} finally {} } 復制代碼
- 方法體的內容比較多,由于一開始mShowing變量用于表示當前dialog是否正在顯示,由于我們剛剛開始調用執行show方法,所以這里的mShowing變量的值為false,所以if分支的內容不會被執行,繼續往下看:if (!mCreated) {dispatchOnCreate(null); } 復制代碼
- mCreated這個控制變量控制dispatchOnCreate方法只被執行一次,由于是第一次執行,所以這里會執行dispatchOnCreate方法,好吧,看一下dispatchOnCreate方法的執行邏輯:
- 可以看到代碼的執行邏輯很簡單就是回調了Dialog的onCreate方法
- 調用了onStart方法,這個方法主要用于設置ActionBar,這里不做過多的說明,然后初始化WindowManager.LayoutParams對象,并最終調用我們的mWindowManager.addView()方法。protected void onStart() {if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true); } 復制代碼
- 最后調用了sendShowMessage方法,可以看一下這個方法的實現:
- 那么發送這個消息主要是什么作用呢,逗比們,接著往下看看。
- 這里會發送一個Dialog已經顯示的異步消息,該消息最終會在ListenersHandler中的handleMessage方法中被執行:private static final class ListenersHandler extends Handler {private WeakReference<DialogInterface> mDialog;public ListenersHandler(Dialog dialog) {mDialog = new WeakReference<DialogInterface>(dialog);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case DISMISS:((OnDismissListener) msg.obj).onDismiss(mDialog.get());break;case CANCEL:((OnCancelListener) msg.obj).onCancel(mDialog.get());break;case SHOW:((OnShowListener) msg.obj).onShow(mDialog.get());break;}} } 復制代碼
- 由于我們的msg.what = SHOW,所以會執行OnShowListener.onShow方法,那么這個OnShowListener是何時賦值的呢?還記得我們構造AlertDialog.Builder么?alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {@Overridepublic void onShow(DialogInterface dialog) {} }); 復制代碼
- 這樣就為我們的AlertDialog.Builder設置了OnShowListener,可以看一下setOnShowListener方法的具體實現:
- 這樣就為我們的Dialog中的mListenersHandler構造了Message對象,并且在Dialog中發送showMessage的時候被mListenersHandler所接收。
3.4 Dialog的dismiss銷毀彈窗
3.4.1 看看cancel()方法
- 調用alertDialog.cancel()或者alertDialog.dismiss()都可以達到銷毀彈窗的效果。
- 首先看一下Dialog的cannel方法的具體實現:
- 可以看到方法體中,若當前Dialog沒有取消,并且設置了取消message,則調用Message.obtain(mCancel).sendToTarget(),前面已經分析過這里的sendToTarget方法會回調注冊的異步消息處理邏輯:public void setOnCancelListener(final OnCancelListener listener) {if (mCancelAndDismissTaken != null) {throw new IllegalStateException("OnCancelListener is already taken by "+ mCancelAndDismissTaken + " and can not be replaced.");}if (listener != null) {mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);} else {mCancelMessage = null;} } 復制代碼
- 可以看到如果在初始化AlertDialog.Builder時,設置了setOnCancelListener,那么就會執行mListenersHandler的異步消息處理,好吧,這里看一下mListenersHandler的定義:private static final class ListenersHandler extends Handler {private WeakReference<DialogInterface> mDialog;public ListenersHandler(Dialog dialog) {mDialog = new WeakReference<DialogInterface>(dialog);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case DISMISS:((OnDismissListener) msg.obj).onDismiss(mDialog.get());break;case CANCEL:((OnCancelListener) msg.obj).onCancel(mDialog.get());break;case SHOW:((OnShowListener) msg.obj).onShow(mDialog.get());break;}} } 復制代碼
- 調用的是設置的OnCancelListener的onCancel方法,也就是說調用dialog.cancel方法時首先會判斷dialog是否調用了setOnCancelListener若設置了,則先調用OnCancelListener的onCancel方法,然后再次執行dismiss方法,若我們沒有為Dialog.Builder設置OnCancelListener那么cancel方法和dismiss方法是等效的。
3.4.2 看看dismiss方法
- 如下所示
- 可以看到,這里首先判斷當前線程的Looper是否是主線程的Looper(由于mHandler是在主線程中創建的,所以mHandler.getLooper返回的是主線程中創建的Looper對象),若是的話,則直接執行dismissDialog()方法,否則的話,通過mHandler發送異步消息至主線程中,簡單來說就是判斷當前線程是否是主線程,若是主線程則執行dismissDialog方法否則發送異步消息
- 然后看一下mHandler對異步消息的處理機制,由于這里的mDismissAction是一個Runnable對象,所以這里直接看一下mDismissAction的定義:
- 這里的異步消息最終也是調用的dismissDialog方法
3.4.3 cancel和dismiss方法都調用dismissDialog方法
- 所以無論執行的cancel方法還是dismiss方法,無論方法是在主線程執行還是子線程中執行,最終調用的都是dismissDialog方法,那么就看一下dismissDialog是怎么個執行邏輯。
- 首先判斷當前的mDector是否為空,或者當前Dialog是否在顯示,若為空或者沒有在顯示,則直接return掉,也就是說當前我們的dialog已經不再顯示了,則不需要往下在執行。然后調用了mWindow.isDestroyed()方法,判斷Window對象是否已經被銷毀,若已經被銷毀,則直接return,并打印錯誤日志。
- 然后再調用了mWindowManager.removeViewImmediate(mDector),這里的mDector是Dialog窗口的根布局,看這個方法的名字應該就是Dialog去除根布局的操作了,可以看一下這個方法的具體實現。
- mWindowManager其實是WindowManagerImpl的實例,所以這里的removeViewImmediate方法應該是WindowManagerImpl中的方法,看一下它的具體實現:@Override public void removeViewImmediate(View view) {mGlobal.removeView(view, true); } 復制代碼
- 可以發現,這里它調用了mGlobal.removeView方法,而這里的mGlobal是WindowManagerGlobal的實例,所以再看一下WIndowManagerGlobal中removeView的實現邏輯:public void removeView(View view, boolean immediate) {if (view == null) {throw new IllegalArgumentException("view must not be null");}synchronized (mLock) {int index = findViewLocked(view, true);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);} } 復制代碼
- 可以發現,這里在獲取了保存的mDector組件之后,又調用了removeViewLocked方法,在看一下這個方法的具體實現邏輯:private void removeViewLocked(int index, boolean immediate) {ViewRootImpl root = mRoots.get(index);View view = root.getView();if (view != null) {InputMethodManager imm = InputMethodManager.getInstance();if (imm != null) {imm.windowDismissed(mViews.get(index).getWindowToken());}}boolean deferred = root.die(immediate);if (view != null) {view.assignParent(null);if (deferred) {mDyingViews.add(view);}} } 復制代碼
- 看到了么,我們獲取了mDector組件的ViewRootImpl,然后調用了其的die方法,通過這個方法實現Window組件的銷毀流程。boolean die(boolean immediate) {// Make sure we do execute immediately if we are in the middle of a traversal or the damage// done by dispatchDetachedFromWindow will cause havoc on return.if (immediate && !mIsInTraversal) {doDie();return false;}if (!mIsDrawing) {destroyHardwareRenderer();} else {Log.e(TAG, "Attempting to destroy the window while drawing!\n" +" window=" + this + ", title=" + mWindowAttributes.getTitle());}mHandler.sendEmptyMessage(MSG_DIE);return true; } 復制代碼
- 可以看到在方法體中有調用了doDie方法,看名字應該就是真正執行window銷毀工作的方法了,我們在看一下doDie方法的具體實現:void doDie() {checkThread();if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);synchronized (this) {if (mRemoved) {return;}mRemoved = true;if (mAdded) {dispatchDetachedFromWindow();}if (mAdded && !mFirst) {destroyHardwareRenderer();if (mView != null) {int viewVisibility = mView.getVisibility();boolean viewVisibilityChanged = mViewVisibility != viewVisibility;if (mWindowAttributesChanged || viewVisibilityChanged) {// If layout params have been changed, first give them// to the window manager to make sure it has the correct// animation info.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); } 復制代碼
- 可以看到方法體中,首先調用了checkThread方法,判斷當前執行代碼的線程,若不是主線程,則拋出異常:void checkThread() {if (mThread != Thread.currentThread()) {throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");} } 復制代碼
- 順著doDie的方法往下看,又調用了dispatchDetachedFromWindow()方法,這個方法主要是銷毀Window中的各中成員變量,臨時變量等void dispatchDetachedFromWindow() {if (mView != null && mView.mAttachInfo != null) {mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);mView.dispatchDetachedFromWindow();}mAccessibilityInteractionConnectionManager.ensureNoConnection();mAccessibilityManager.removeAccessibilityStateChangeListener(mAccessibilityInteractionConnectionManager);mAccessibilityManager.removeHighTextContrastStateChangeListener(mHighContrastTextManager);removeSendWindowContentChangedCallback();destroyHardwareRenderer();setAccessibilityFocus(null, null);mView.assignParent(null);mView = null;mAttachInfo.mRootView = null;mSurface.release();if (mInputQueueCallback != null && mInputQueue != null) {mInputQueueCallback.onInputQueueDestroyed(mInputQueue);mInputQueue.dispose();mInputQueueCallback = null;mInputQueue = null;}if (mInputEventReceiver != null) {mInputEventReceiver.dispose();mInputEventReceiver = null;}try {mWindowSession.remove(mWindow);} catch (RemoteException e) {}// Dispose the input channel after removing the window so the Window Manager// doesn't interpret the input channel being closed as an abnormal termination.if (mInputChannel != null) {mInputChannel.dispose();mInputChannel = null;}mDisplayManager.unregisterDisplayListener(mDisplayListener);unscheduleTraversals(); } 復制代碼
- 可以看到在方法中調用了mView.dispatchDetachedFromWindow方法,這個方法的作用就是將mView從Window中detach出來,可以看一下這個方法的具體實現:void dispatchDetachedFromWindow() {AttachInfo info = mAttachInfo;if (info != null) {int vis = info.mWindowVisibility;if (vis != GONE) {onWindowVisibilityChanged(GONE);}}onDetachedFromWindow();onDetachedFromWindowInternal();InputMethodManager imm = InputMethodManager.peekInstance();if (imm != null) {imm.onViewDetachedFromWindow(this);}ListenerInfo li = mListenerInfo;final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =li != null ? li.mOnAttachStateChangeListeners : null;if (listeners != null && listeners.size() > 0) {// NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to// perform the dispatching. The iterator is a safe guard against listeners that// could mutate the list by calling the various add/remove methods. This prevents// the array from being modified while we iterate it.for (OnAttachStateChangeListener listener : listeners) {listener.onViewDetachedFromWindow(this);}}if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) {mAttachInfo.mScrollContainers.remove(this);mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED;}mAttachInfo = null;if (mOverlay != null) {mOverlay.getOverlayView().dispatchDetachedFromWindow();} } 復制代碼
- 其中onDetachedFromWindow方法是一個空的回調方法,這里重點看一下onDetachedFromWindowInternal方法:protected void onDetachedFromWindowInternal() {mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;removeUnsetPressCallback();removeLongPressCallback();removePerformClickCallback();removeSendViewScrolledAccessibilityEventCallback();stopNestedScroll();// Anything that started animating right before detach should already// be in its final state when re-attached.jumpDrawablesToCurrentState();destroyDrawingCache();cleanupDraw();mCurrentAnimation = null; } 復制代碼
- onDetachedFromWindowInternal方法的方法體也不是特別長,都是一些調用函數,這里看一下destropDrawingCache方法,這個方法主要是銷毀View的緩存Drawing,我們來看一下具體實現:
- 這里的mDrawingCache其實就是一個Bitmap類型的成員變量,而這里調用的recycler和置空操作其實就是把View中執行draw方法之后緩存的bitmap清空。
- 這里需要說明的是,我們View組件的最終顯示落實是通過draw方法實現繪制的,而我們的draw方法的參數是一個Canvas,這是一個畫布的對象,通過draw方法就是操作這個對象并顯示出來,而Canvas對象之所以能夠實現顯示的效果是因為其內部保存著一個Bitmap對象,通過操作Canvas對象實質上是操作Canvas對象內部的Bitmap對象,而View組件的顯示也就是通過這里的Bitmap來實現的。
- 而我們上文中置空了bitmap對象就相當于把View組件的顯示效果置空了,就是相當于我們取消了View的draw方法的執行效果,繼續回到我們的dispatchDetachedFromWindow方法,在執行了mView.dispatchDetachedFromWindow()方法之后,又調用了mView = null;方法,這里設置mView為空,這樣我們有取消了View的meature和layouot的執行效果。
5.Dialog彈窗總結
- Dialog中的Window對象與Activity中的Window對象是相似的,都對應著一個WindowManager對象;Dialog和Activity的顯示邏輯是相似的都是內部管理這一個Window對象,用WIndow對象實現界面的加載與顯示邏輯。
- Dialog相關的幾個類:Dialog,AlertDialog,AlertDialog.Builder,AlertController,AlertController.AlertParams,其中Dialog是窗口的父類,主要實現Window對象的初始化和一些共有邏輯,而AlertDialog是具體的Dialog的操作實現類,AlertDialog.Builder類是AlertDialog的內部類,主要用于構造AlertDialog,AlertController是AlertDialog的控制類,AlertController.AlertParams類是控制參數類;
- 構造AlertDialog用到了很經典的buidler構造者模式。關于buidler模式,可以參考Builder模式。構造顯示Dialog的一般流程,構造AlertDialog.Builder,然后設置各種屬性,最后調用AlertDialog.Builder.create方法獲取AlertDialog對象,并且create方法中會執行,構造AlertDialog,設置dialog各種屬性的操作。最后我們調用Dialog.show方法展示窗口,初始化Dialog的布局文件,Window對象等,然后執行mWindowManager.addView方法,開始執行繪制View的操作,并最終將Dialog顯示出來。
- 窗口的取消繪制流程是相似的,包括Activity和Dialog等;通過調用WindowManager.removeViewImmediate方法,開始執行Window窗口的取消繪制流程;Window窗口的取消繪制流程,通過清空bitma撤銷draw的執行效果,通過置空View撤銷meature和layout的執行效果。
關于其他內容介紹
01.關于博客匯總鏈接
- 1.技術博客匯總
- 2.開源項目匯總
- 3.生活博客匯總
- 4.喜馬拉雅音頻匯總
- 5.其他匯總
02.關于我的博客
- 我的個人站點:www.yczbj.org,www.ycbjie.cn
- github:github.com/yangchong21…
- 知乎:www.zhihu.com/people/yang…
- 簡書:www.jianshu.com/u/b7b2c6ed9…
- csdn:my.csdn.net/m0_37700275
- 喜馬拉雅聽書:www.ximalaya.com/zhubo/71989…
- 開源中國:my.oschina.net/zbj1618/blo…
- 泡在網上的日子:www.jcodecraeer.com/member/cont…
- 郵箱:yangchong211@163.com
- 阿里云博客:yq.aliyun.com/users/artic… 239.headeruserinfo.3.dT4bcV
- segmentfault頭條:segmentfault.com/u/xiangjian…
總結
以上是生活随笔為你收集整理的Dialog源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: metamask中的import acc
- 下一篇: fast.ai 深度学习笔记:第一部分第