catalogue

  • 1. Simple usage
  • 2.AlertDialog source code analysis
    • 2.1 Construction method of AlertDialog.Builder
    • 2.2 Setting properties using alertDialog. Builder
    • 2.3 builder. The create method
    • 2.4 Look at the source of p.ply (dialog.malert) in the create method
    • 2.5 Look at the Show method of AlertDialog
  • Dialog source code analysis
    • 3.1 Dialog constructor
    • 3.2 Dialog life cycle
    • The 3.3 Dialog show method displays pop-ups
    • 3.4 Dialog’s Dismiss destroys the popover
  • 4.Dialog pop-up problem analysis
  • 5.Dialog popup summary

Good news

  • Summary of blog notes [March 2016 to present], including Java basic and in-depth knowledge points, Android technology blog, Python learning notes, etc., including the summary of bugs encountered in daily development, of course, I also collected a lot of interview questions in my spare time, updated, maintained and corrected for a long time, and continued to improve… Open source files are in Markdown format! Also open source life blog, since 2012, accumulated a total of 47 articles [nearly 200,000 words], reprint please indicate the source, thank you!
  • Link address:Github.com/yangchong21…
  • If you feel good, you can star, thank you! Of course, also welcome to put forward suggestions, everything starts from small, quantitative change causes qualitative change!
  • DialogFragment Package library project address: github.com/yangchong21…
  • 02.Toast source code in-depth analysis
    • Show () method source code analysis, how scheduleTimeoutLocked Toast is destructed, how the message mechanism in the TN class is implemented, the number of Toast displays in common applications is limited. Explain in code why the Toast is still displayed after the Activity is destroyed, how the Toast occasionally fails to add window, how the Toast runs on a child thread, how the Toast adds system window permissions, etc
  • 03.DialogFragment source code analysis
    • The simplest way to use onCreate(@Nullable Bundle savedInstanceState) source code analysis, focus on the analysis of popup display and destroy source code, using the show() method of IllegalStateException analysis
  • 05 PopupWindow source code analysis
    • PopupWindow = PopupWindow = PopupWindow = PopupWindow = PopupWindow = PopupWindow Why pop up and click and dismiss?
  • 06.Snackbar source code analysis
    • The simplest creation, Snackbar make method source analysis, Snackbar show and click disappear source analysis, show and hide in the animation source analysis, Snackbar design ideas, why is always displayed at the bottom of the Snackbar
  • 07. Common pop-up problems
    • IllegalStateException in DialogFragment using the show() method. Unable to add window Toast runs on a child thread causing a crash.
  • 08. The Builder pattern
    • Builder Builder Builder Builder Builder Builder Builder Builder Builder Analysis of advantages and disadvantages of Builder model. A classic example of builder mode can be found in my popover wrapper library: github.com/yangchong21…

1. Simple usage

  • AlertDialog is generally used, but AlertDialog is also a major descendant of Dialog. Let’s analyze Dialog source code.
  • The simplest usage is shown below
    private AlertDialog alertDialog=null;
    public void showDialog(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setIcon(R.mipmap.ic_launcher);
        builder.setMessage("Rain of Xiaoxiang Swords");
        builder.setTitle("This is the title.");
        builder.setView(R.layout.activity_main);
        builder.setPositiveButton("Sure", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); }}); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); }}); alertDialog = builder.create(); alertDialog.show(); }Copy the code

2.AlertDialog source code analysis

2.1 Construction method of AlertDialog.Builder

  • Builder is an internal class of AlertDialog that encapsulates the process of building an AlertDialog.
    public Builder(Context context) {
        this(context, resolveDialogTheme(context, 0));
    }
    Copy the code
    • The overloaded constructor of Builder is then called:
    public Builder(Context context, int themeResId) {
        P = new AlertController.AlertParams(new ContextThemeWrapper(
                context, resolveDialogTheme(context, themeResId)));
    }
    Copy the code
  • Then the P here is AlertDialog. Builder of a AlertController AlertParams types of member variables, visible here perform the initialization of P.
    public AlertParams(Context context) {
        mContext = context;
        mCancelable = true;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    Copy the code
  • Can see here is mainly carried out AlertController. AlertParams initialization, some member variable initialization. After doing a series of operations like this, our code:
    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    Copy the code

2.2 Setting properties using alertDialog. Builder

  • The builder.setIcon method is called. Here is a look at the implementation of the setIcon method:
    • Can see AlertDialog Builder setIcon methods, here is to give the type of execution to AlertController AlertParams P iconId mIconId assignment for transmission, and this method returns the type of the Builder.
    public Builder setIcon(@DrawableRes int iconId) {
        P.mIconId = iconId;
        return this;
    }
    Copy the code
  • The builder.setMessage method is called, and we can see the implementation of the Builder. setMessage method:
    • As with setIcon, we assign the mMessage value of the member variable to the Message value we passed, and like setIcon, the return value of this method is also Builder.
    public Builder setMessage(CharSequence message) {
        P.mMessage = message;
        return this;
    }
    Copy the code
  • Then look at the Builder.setTitle method:
    • It is found that setIcon, setMessage, setTitle and other methods of Builder all assign values to icon, message, title of member variables P of Builder.
    public Builder setTitle(CharSequence title) {
        P.mTitle = title;
        return this;
    }
    Copy the code
  • Now look at the Builder.setView method:
    • SetView is similar to setIcon, setMessage, setTitle, etc. They all assign the data values we pass to the member variable P of Builder.
    public Builder setView(int layoutResId) {
        P.mView = null;
        P.mViewLayoutResId = layoutResId;
        P.mViewSpacingSpecified = false;
        return this;
    }
    Copy the code

2.3 builder. The create method

  • The Builder.create method is then called and returns an AlertDialog.
  • As you can see, an AlertDialog constructor is constructed. We can look at the implementation of this constructor:
    • As you can see, the super constructor is called first, and our AlertDialog inherits from Dialog, so that’s what the Dialog constructor is doing.
  • Back in the Constructor of the AlertDialog, in the constructor, in addition to calling the constructor of the Dialog, it is executed
    • Equivalent to initializing the member variable mAlert of the AlertDiaog.
    mAlert = new AlertController(getContext(), this, getWindow());
    Copy the code

2.4 Look at the source of p.ply (dialog.malert) in the create method

  • AlertDialog again. Builder. The create method, after to create an AlertDialog, and execute the P.a pply (dialog. MAlert); P here is a AlertController AlertParams variables, and dialog. The mAlert is one of the newly created AlertDialog AlertController variables of type, take a look at the apply methods of concrete implementation:
    • In initialization AlertDialog. Builder set of icon, title, message assigned to the AlertController. AlertParams, Here is the mAlert member variable of the Dialog object we created that is assigned to the property value set at initialization
    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);
        }
    }
    Copy the code

2.5 Look at the Show method of AlertDialog

  • If you look at the following, you can see that the show method in the Dialog is called directly. Now let’s do some analysis

Dialog source code analysis

3.1 Dialog constructor

  • As shown below.
    • In the Dialog constructor, a PhoneWindow is directly constructed and assigned to the member variable mWindow of the Dialog. It can be seen that the display logic of Dialog and Activity is similar. The corresponding Window variable is used to load and display the Window. We then perform some initialization of the Window object, such as setting the callback function to itself, and then call the setWindowManager method of the Window class, passing in the WindowManager. Then create a dialog to listen for the handler object.
    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; } // create a Context mContext = new ContextThemeWrapper(Context, themeResId); }else{ mContext = context; } // Get a WindowManager object mWindowManager = (WindowManager) context.getSystemService(context.window_service); Final Window w = new PhoneWindow(mContext); // Assign the Window object w to mWindow mWindow = w; // Set the Windowd object to callback, and it implements those callback functions itself. w.setOnWindowDismissedCallback(this); // Set the WindowManager object w.setwinDowManager (mWindowManager, null, null); w.setGravity(Gravity.CENTER); // Create a dialog to listen to Handler mListenersHandler = new ListenersHandler(this); }Copy the code
  • Then take a look at the source code inside W.setwindowManager (mWindowManager, NULL, NULL)
    • You can see that the windowManager object is obtained in the same way as the Activity’s Window object, creating a new WindowManagerImpl object.

3.2 Dialog life cycle

  • The dialog life cycle is shown below
    /** * Similar to the Activity's onCreate function, this method can perform some of the Dialog initialization operations * including the callsetContentView method */ protected void onCreate(Bundle savedInstanceState) {} /** * is called when the dialog startsonStart() {} /** * is called when the dialog stops. */ protected voidonStop() {}Copy the code

The 3.3 Dialog show method displays pop-ups

  • The source code is shown below, and I have simply commented on the key logic here.
    public void show() {// First check whether the dialog box is displayedif (mShowing) {
            if(mDecor ! = null) {if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }
    
        mCanceled = false; /* Check if the dialog box has been created. If it has not been created, onCreate will be called in dispatchOnCreateif(! mCreated) { dispatchOnCreate(null); } // call onStart(); // Get the Window object's total DecorView, if calledsetContentView creates DecorView mDecor = mwindow.getDecorView (); // Now we get some of the layout attributesif (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 {// Add DecorView to WindowManager. This shows mWindowManager.addView(mDecor, L); // set mShowing totrue
            mShowing = true;
            sendShowMessage();
        } finally {
        }
    }
    Copy the code
  • Since the mShowing variable is used to indicate whether the current dialog is showing, the value of the mShowing variable is false, so the content of the if branch will not be executed. Continue:
    if(! mCreated) { dispatchOnCreate(null); }Copy the code
  • The mCreated control variable controls that the dispatchOnCreate method is executed only once. This is the first time that the dispatchOnCreate method is executed. Ok, let’s look at the execution logic of the dispatchOnCreate method:
    • As you can see, the execution logic of the code is simple: it calls back to the onCreate method of the Dialog
    void dispatchOnCreate(Bundle savedInstanceState) {
        if(! mCreated) { onCreate(savedInstanceState); mCreated =true; }}Copy the code
  • Invoked the onStart method, this method is mainly used to set the ActionBar, here don’t do too much explanation, and then initializes WindowManager. LayoutParams object, and finally we call our mWindowManager. AddView () method.
    protected void onStart() {
        if(mActionBar ! = null) mActionBar.setShowHideAnimationEnabled(true);
    }
    Copy the code
  • Finally, the sendShowMessage method is called. Look at the implementation of this method:
    • So what’s the main purpose of sending this message, funny guys, read on.
    private void sendShowMessage() {
        if (mShowMessage != null) {
            // Obtain a new message so this dialog can be re-used
            Message.obtain(mShowMessage).sendToTarget();
        }
    }
    Copy the code
  • This sends an asynchronous message already displayed by the Dialog, which will eventually be executed in the handleMessage method in ListenersHandler:
    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; }}}Copy the code
  • Onshowlistener. onShow (MSG, what = SHOW); onshowListener. onShow (MSG, what = SHOW) Remember when we built alertdialog.Builder?
    alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
    
        }
    });
    Copy the code
  • This sets up the OnShowListener method for our Alertdialog. Builder. See the implementation of the setOnShowListener method:
    • This constructs a Message object for the mListenersHandler in our Dialog and is received by the mListenersHandler when it sends a showMessage in the Dialog.
    public void setOnShowListener(OnShowListener listener) {
        if(listener ! = null) { mShowMessage = mListenersHandler.obtainMessage(SHOW, listener); }else{ mShowMessage = null; }}Copy the code

3.4 Dialog’s Dismiss destroys the popover

3.4.1 Look at the cancel() method
  • The popover is destroyed by calling alertdialog.cancel () or alertdialog.dismiss ().
    • Let’s first look at the implementation of Dialog’s cannel method:
    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();
    }
    Copy the code
  • Message.obtain(mCancel).sendtoTarget () is called if the current Dialog is not cancelled and the cancel message is set, as you can see from the body of the method where the sendToTarget method calls back the registered asynchronous message processing logic:
    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; }}Copy the code
  • If setOnCancelListener is set when alertDialog. Builder is initialized, asynchronous message processing for mListenersHandler will be performed.
    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; }}}Copy the code
  • Call the onCancel method of OnCancelListener, that is, the dialog.cancel method is called to determine whether the dialog has called setOnCancelListener. The onCancel method of OnCancelListener is called and the dismiss method is executed again. If we do not set OnCancelListener for dialog. Builder then the Cancel method and the dismiss method are equivalent.
3.4.2 Look at the dismiss method
  • As shown below.
    • If mHandler is created in the main thread, mHandler. GetLooper returns the Looper object created in the main thread. This allows you to dismissDialog() directly; otherwise, you use the dismissDialog() method to dismiss an asynchronous message to the main thread using the mHandler method. This allows you to dismissDialog(); if this thread is dismissDialog, use the dismissDialog method
    public void dismiss() {
        if (Looper.myLooper() == mHandler.getLooper()) {
            dismissDialog();
        } else{ mHandler.post(mDismissAction); }}Copy the code
  • This allows you to dismissAction as it moves in and out of the way. This allows mDismissAction to be dismissable as a Runnable object.
    • The asynchronous message here also ends up calling the dismissDialog method
    private final Runnable mDismissAction = new Runnable() {
        public void run() { dismissDialog(); }};Copy the code
3.4.3 Both the Cancel and Dismiss methods call the dismissDialog method
  • That dismissDialog method is always called, whether it’s executed in the main thread or in dismiss, so take a look at the execution logic that dismissDialog uses.
    • First, check whether the current mDector is empty or whether the current Dialog is displayed. If it is empty or not displayed, then return directly, that is to say, our Dialog is no longer displayed at present, so there is no need to continue to execute. You then call mwindow.isdestroyed () to check whether the Window object has been destroyed. If so, return and print an error log.
    • And then call the mWindowManager. RemoveViewImmediate (mDector), the mDector here is the root of the Dialog window layout, see the name of this method should be Dialog to grubbing layout operations, can have a look at the implementation of this method.
    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(); }}Copy the code
  • MWindowManager is an instance of WindowManagerImpl, so the removeViewImmediate method is a WindowManagerImpl method.
    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }
    Copy the code
  • MGlobal is an instance of Windows ManagerGlobal, so let’s look at the removeView implementation logic in Windows ManagerGlobal:
    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); }}Copy the code
  • After the mDector component is saved, the removeViewLocked method is called.
    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); }}}Copy the code
  • See, we get the mDector component’s ViewRootImpl and call its die method, which implements the Window component’s destruction process.
    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;
    }
    Copy the code
  • The doDie method is called in the body of the method. The name of the method should be used to execute the window destruction.
    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);
    }
    Copy the code
  • Check (checkThread); check (checkThread);
    void checkThread() {
        if(mThread ! = Thread.currentThread()) { throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views."); }}Copy the code
  • Look down doDie method, again call dispatchDetachedFromWindow () method, this method is mainly in the destruction of the Window each member variables, temporary variables, etc
    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(); }Copy the code
  • Can see in a method call mView. DispatchDetachedFromWindow method, this method is to mView detach from the Window, you can have a look at the implementation of this method:
    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 modifiedwhile 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();
        }
    }
    Copy the code
  • The onDetachedFromWindow method is an empty callback methods, highlighted here see onDetachedFromWindowInternal method:
    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;
    }
    Copy the code
  • OnDetachedFromWindowInternal method of the body also is not particularly long, some are calling a function, here have a look at destropDrawingCache method, this method is to destroy the View of cache Drawing, let’s take a look at the specific implementation:
    • MDrawingCache is a Bitmap member variable. Recycler and empty are used to empty bitmaps cached after draw.
    • Here it needs to be noted that the final display implementation of our View component is achieved through the draw method, and the parameter of our Draw method is a Canvas, which is a Canvas object, through the draw method is to manipulate the object and display, The reason why Canvas object can achieve the effect of display is that it saves a Bitmap object inside. In essence, the operation of Canvas object is to operate the Bitmap object inside Canvas object, and the display of View component is realized through the Bitmap here.
    • And we are on the bitmap object is empty is equivalent to the View components display set is empty, is equivalent to we canceled the View the draw method of execution effect, continue to go back to our dispatchDetachedFromWindow method, In performing the mView. DispatchDetachedFromWindow () method, and call the mView = null; The mView is set to empty so that we have the effect of canceling the meature and layouot of the View.
    public void destroyDrawingCache() {
        if(mDrawingCache ! = null) { mDrawingCache.recycle(); mDrawingCache = null; }if (mUnscaledDrawingCache != null) {
            mUnscaledDrawingCache.recycle();
            mUnscaledDrawingCache = null;
        }
    }
    Copy the code

5.Dialog popup summary

  • The Window object in a Dialog is similar to the Window object in an Activity in that both correspond to a WindowManager object. The display logic of Dialog and Activity is similar. They both manage the Window object internally and use the Window object to realize the loading and display logic of the interface.
  • Dialog-related classes: Dialog, AlertDialog, AlertDialog. Builder, AlertController AlertController. AlertParams, the Dialog is window of the parent class, The alertDialog. Builder class is the inner class of AlertDialog, which is mainly used to construct AlertDialog. AlertController is AlertDialog control class, AlertController AlertParams classes is to control the parameters;
  • AlertDialog is constructed using the classic Buidler constructor pattern. For the Buidler pattern, see The Builder pattern. Structure shows the general flow of Dialog AlertDialog. The Builder, and then set various properties, the last call AlertDialog. Builder. The create method to obtain AlertDialog object, and will perform in the create method, Builds an AlertDialog and sets the actions for various dialog properties. Finally, we call dialog.show to display the Window, initialize the layout file of the Dialog, Window object, etc., and then execute mWindowManager.addView to start the operation of drawing the View and finally display the Dialog.
  • The undrawing process for Windows is similar, including activities and dialogs; By calling the WindowManager removeViewImmediate method, implemented the Window Window the cancellation of the drawing process; To cancel the drawing process of Window Window, cancel the execution effect of draw by emptying bitma, and cancel the execution effect of meature and layout by emptying View.

About other content introduction

01. About blog summary links

  • 1. Tech blog round-up
  • 2. Open source project summary
  • 3. Life Blog Summary
  • 4. Himalayan audio summary
  • 5. Other summaries

02. About my blog

  • My personal website: www.yczbj.org, www.ycbjie.cn
  • Github:github.com/yangchong21…
  • Zhihu: www.zhihu.com/people/yang…
  • Jane: www.jianshu.com/u/b7b2c6ed9…
  • csdn:my.csdn.net/m0_37700275
  • The Himalayan listening: www.ximalaya.com/zhubo/71989…
  • Source: China my.oschina.net/zbj1618/blo…
  • Soak in the days of online: www.jcodecraeer.com/member/cont.
  • Email address: [email protected]
  • Blog: ali cloud yq.aliyun.com/users/artic… 239.headeruserinfo.3.dT4bcV
  • Segmentfault headline: segmentfault.com/u/xiangjian…