您好,登錄后才能下訂單哦!
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() {
@Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
alertDialog = builder.create();
alertDialog.show();
}
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
public AlertParams(Context context) {
mContext = context;
mCancelable = true;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
public Builder setIcon(@DrawableRes int iconId) {
P.mIconId = iconId;
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setView(int layoutResId) {
P.mView = null;
P.mViewLayoutResId = layoutResId;
P.mViewSpacingSpecified = false;
return this;
}
mAlert = new AlertController(getContext(), this, getWindow());
ublic void apply(AlertController dialog) {
if (mCustomTitleView != null) {
dialog.setCustomTitle(mCustomTitleView);
} else {
if (mTitle != null) {
dialog.setTitle(mTitle);
}
if (mIcon != null) {
dialog.setIcon(mIcon);
}
if (mIconId != 0) {
dialog.setIcon(mIconId);
}
if (mIconAttrId != 0) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
if (mMessage != null) {
dialog.setMessage(mMessage);
}
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null);
}
if (mNegativeButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
mNegativeButtonListener, null);
}
if (mNeutralButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
mNeutralButtonListener, null);
}
if (mForceInverseBackground) {
dialog.setInverseBackgroundForced(true);
}
// For a list, the client can either supply an array of items or an
// adapter or a cursor
if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
createListView(dialog);
}
if (mView != null) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
} else if (mViewLayoutResId != 0) {
dialog.setView(mViewLayoutResId);
}
}
如下所示
看源碼可知在Dialog的構造方法中直接直接構造了一個PhoneWindow,并賦值給Dialog的成員變量mWindow,從這里可以看出其實Dialog和Activity的顯示邏輯都是類似的,都是通過對應的Window變量來實現窗口的加載與顯示的。然后我們執行了一些Window對象的初始化操作,比如設置回調函數為本身,然后調用Window類的setWindowManager方法,并傳入了WindowManager。然后創建一個對話框監聽handler對象。
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
if (createContextThemeWrapper) {
if (themeResId == 0) {
final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
themeResId = outValue.resourceId;
}
//創建一個Context
mContext = new ContextThemeWrapper(context, themeResId);
} else {
mContext = context;
}
//獲取一個WindowManager對象
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//創建一個Window對象
final Window w = new PhoneWindow(mContext);
//將Window對象w賦值給mWindow
mWindow = w;
//為Windowd對象設置回調,并且它本身實現了這些回調函數
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
//為Window對象設置WindowManager對象
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
//創建一個對話框監聽Handler
mListenersHandler = new ListenersHandler(this);
}
/**
* 類似于Activity的onCreate函數,可以在這個方法中進行Dialog的一些初始化操作
* 包括調用setContentView方法
*/
protected void onCreate(Bundle savedInstanceState) { }
/**
* 當對話框啟動的時候被調用.
*/
protected void onStart() { }
/**
* 當對話框停止的時候被調用.
*/
protected void onStop() { }
源碼如下所示,關于重點的邏輯,我在這里只是簡單的注釋了一下。
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就會創建DecorView
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 {
//將DecorView添加到WindowManager中,這些就會顯示了
mWindowManager.addView(mDecor, l);
//將mShowing置為true
mShowing = true;
sendShowMessage();
} finally {
}
}
if (!mCreated) {
dispatchOnCreate(null);
}
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
onCreate(savedInstanceState);
mCreated = true;
}
}
protected void onStart() {
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
}
private void sendShowMessage() {
if (mShowMessage != null) {
// Obtain a new message so this dialog can be re-used
Message.obtain(mShowMessage).sendToTarget();
}
}
private static final class ListenersHandler extends Handler {
private WeakReference<DialogInterface> mDialog;
public ListenersHandler(Dialog dialog) {
mDialog = new WeakReference<DialogInterface>(dialog);
}
@Override
public 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() {
@Override
public void onShow(DialogInterface dialog) {
}
});
public void setOnShowListener(OnShowListener listener) {
if (listener != null) {
mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
} else {
mShowMessage = null;
}
}
public void cancel() {
if (!mCanceled && mCancelMessage != null) {
mCanceled = true;
// Obtain a new message so this dialog can be re-used
Message.obtain(mCancelMessage).sendToTarget();
}
dismiss();
}
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);
}
@Override
public 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;
}
}
}
public void dismiss() {
if (Looper.myLooper() == mHandler.getLooper()) {
dismissDialog();
} else {
mHandler.post(mDismissAction);
}
}
private final Runnable mDismissAction = new Runnable() {
public void run() {
dismissDialog();
}
};
所以無論執行的cancel方法還是dismiss方法,無論方法是在主線程執行還是子線程中執行,最終調用的都是dismissDialog方法,那么就看一下dismissDialog是怎么個執行邏輯。
然后再調用了mWindowManager.removeViewImmediate(mDector),這里的mDector是Dialog窗口的根布局,看這個方法的名字應該就是Dialog去除根布局的操作了,可以看一下這個方法的具體實現。
void dismissDialog() {
if (mDecor == null || !mShowing) {
return;
}
if (mWindow.isDestroyed()) {
Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
return;
}
try {
mWindowManager.removeViewImmediate(mDecor);
} finally {
if (mActionMode != null) {
mActionMode.finish();
}
mDecor = null;
mWindow.closeAllPanels();
onStop();
mShowing = false;
sendDismissMessage();
}
}
@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);
}
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;
}
public void destroyDrawingCache() {
if (mDrawingCache != null) {
mDrawingCache.recycle();
mDrawingCache = null;
}
if (mUnscaledDrawingCache != null) {
mUnscaledDrawingCache.recycle();
mUnscaledDrawingCache = null;
}
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。