Dialog

Dialog,对话框的基类,(DialogFragment除外)。通过Dialog dialog = new Dialog(this);dialog.show();就可以显示出一个Dialog。
还可以通过Dialog #setTitle和Dialog #setContentView设置标题和需要显示的内容。

最终都会调用这个构造方法,createContextThemeWrapper默认为true,
所以调用dialog.getContext方法得到的context和 传入的context并不是同一个。
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;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }
        根据context获取WindowManager,WindowManager实现了ViewManager接口,可以用来添加、更新、移除View。
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
新建一个PhoneWindow,PhoneWindow大家应该不会陌生,它内部包含一个DecorView,DecorView为整个Window界面的最顶层View,只有一个子元素为LinearLayout包含通知栏,标题栏,内容显示栏三块区域。
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
    }
show方法负责dialog的显示,
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) {如果没有创建,会调用oncreate方法,一般我们在这里设置contentview.
        从而把view设置给phonewindow.
            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();//获取window的DecorView,并添加到mWindowManager,这时,view就被展示出来了。

        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;
        }

        mWindowManager.addView(mDecor, l);
        mShowing = true;

        sendShowMessage();
    }
PhoneWindow的方法
@Override  
    public void setContentView(int layoutResID) {  
    如果mContentParent 为空,先初始化Decorview,并获取mContentParent ,
        if (mContentParent == null) {  
            installDecor();  
        } else {  
            mContentParent.removeAllViews();  
        }  
        将layoutResID对应的view添加到mContentParent中
        mLayoutInflater.inflate(layoutResID, mContentParent);  
        final Callback cb = getCallback();  
        if (cb != null) {  
            cb.onContentChanged();  
        }  
    }  
private void installDecor() {  
        if (mDecor == null) {  
            mDecor = generateDecor();  //新建一个DecorView对象
            mDecor.setIsRootNamespace(true);  
        }  
        if (mContentParent == null) {  
            mContentParent = generateLayout(mDecor);  //生成mContentParent 

            mTitleView = (TextView)findViewById(com.android.internal.R.id.title);  
            if (mTitleView != null) {  
                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {  
                    View titleContainer = findViewById(com.android.internal.R.id.title_container);  
                    if (titleContainer != null) {  
                        titleContainer.setVisibility(View.GONE);  
                    } else {  
                        mTitleView.setVisibility(View.GONE);  
                    }  
                    if (mContentParent instanceof FrameLayout) {  
                        ((FrameLayout)mContentParent).setForeground(null);  
                    }  
                } else {  
                    mTitleView.setText(mTitle);  
                }  
            }  
        }  
    }  
新建一个DecorView对象。
protected DecorView generateDecor() {  
        return new DecorView(getContext(), -1);  
    } 
protected ViewGroup generateLayout(DecorView decor) {  
        // Apply data from current theme.  

       。。。。。。。。。。。。。。
        // 根据不同的类型,获取layoutResource,并将xml转化为view对象.  

        int layoutResource;  
        int features = getLocalFeatures();  
        // System.out.println("Features: 0x" + Integer.toHexString(features));  
        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {  
            if (mIsFloating) {  
                layoutResource = com.android.internal.R.layout.dialog_title_icons;  
            } else {  
                layoutResource = com.android.internal.R.layout.screen_title_icons;  
            }  
            // System.out.println("Title Icons!");  
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {  
            // Special case for a window with only a progress bar (and title).  
            // XXX Need to have a no-title version of embedded windows.  
            layoutResource = com.android.internal.R.layout.screen_progress;  
            // System.out.println("Progress!");  
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {  
            // Special case for a window with a custom title.  
            // If the window is floating, we need a dialog layout  
            if (mIsFloating) {  
                layoutResource = com.android.internal.R.layout.dialog_custom_title;  
            } else {  
                layoutResource = com.android.internal.R.layout.screen_custom_title;  
            }  
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {  
            // If no other features and not embedded, only need a title.  
            // If the window is floating, we need a dialog layout  
            if (mIsFloating) {  
                layoutResource = com.android.internal.R.layout.dialog_title;  
            } else {  
                layoutResource = com.android.internal.R.layout.screen_title;  
            }  
            // System.out.println("Title!");  
        } else {  
            // Embedded, so no decoration is needed.  
            layoutResource = com.android.internal.R.layout.screen_simple;  
            // System.out.println("Simple!");  
        }  

        mDecor.startChanging();  

        View in = mLayoutInflater.inflate(layoutResource, null);  、
        //将view添加到decorview
        decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT));  
         //根据ID_ANDROID_CONTENT找到content view
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  
        if (contentParent == null) {  
            throw new RuntimeException("Window couldn't find content container view");  
        }  

        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {  
            ProgressBar progress = getCircularProgressBar(false);  
            if (progress != null) {  
                progress.setIndeterminate(true);  
            }  
        }  

        ..............................
        mDecor.finishChanging();  

        return contentParent;  
    }  

以上为dialog的显示过程。
当调用dismiss后,会执行WindowManager.removeViewImmediate(mDecor);方法,将DecorView从WindowManager里移除。

如果调用dialog.dismiss()方法时,activity已经销毁,会报View not attached to window manager。
解决方法可参考:http://blog.csdn.net/yihongyuelan/article/details/9829313文章最后部分。
也可将Dialog换成DialogFragment,这样,Dialog的生命周期和Activity就同步了。

你可能感兴趣的:(Android)