AlertDialog 源码解析一

来源:互联网 发布:mac 虚拟机装office 编辑:程序博客网 时间:2024/06/07 19:16

概要:

AlertDialog,平常用的很多,今天走了一遍内部实现,记录一下。

解析:

一AlertDialog的常用调用:

        new AlertDialog.Builder(mContext)                .setTitle("title")                .setMessage("message")                .create()                .show();

这是一个典型的Builder的构建者模式,Builder作为AlertDialog的内部类,专门用于构建AlertDialog对象。

Builder的链式调用,能够很好的简化代码。


AlertDialog与Builder的内部实现:

 public class AlertDialog extends Dialog implements DialogInterface {        private AlertController mAlert;        AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {            super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,                    createContextThemeWrapper);            mWindow.alwaysReadCloseOnTouchAttr();            mAlert = AlertController.create(getContext(), this, getWindow());        }        @Override        public void setTitle(CharSequence title) {            super.setTitle(title);            mAlert.setTitle(title);        }        public void setMessage(CharSequence message) {            mAlert.setMessage(message);        }        public static class Builder {            private final AlertController.AlertParams P;            public Builder(Context context, int themeResId) {                P = new AlertController.AlertParams(new ContextThemeWrapper(                        context, resolveDialogTheme(context, themeResId)));            }            public Builder setTitle(CharSequence title) {                P.mTitle = title;                return this;            }            public Builder setMessage(@StringRes int messageId) {                P.mMessage = P.mContext.getText(messageId);                return this;            }            public AlertDialog create() {                // Context has already been wrapped with the appropriate theme.                final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);                P.apply(dialog.mAlert);                dialog.setCancelable(P.mCancelable);                if (P.mCancelable) {                    dialog.setCanceledOnTouchOutside(true);                }                dialog.setOnCancelListener(P.mOnCancelListener);                dialog.setOnDismissListener(P.mOnDismissListener);                if (P.mOnKeyListener != null) {                    dialog.setOnKeyListener(P.mOnKeyListener);                }                return dialog;            }            public AlertDialog show() {                final AlertDialog dialog = create();                dialog.show();                return dialog;            }        }    }
通过上面的代码分析:

1,创建AlertDialog.Builder的时候,会创建AlertController.AlertParams对象P,P里面封装了所有的Dialog

的属性。

2,我们在调用Builder的setTitle,setMessage的时候,其实就是在将方法的参数值赋值给AlertParams P;

3,在Builder的create方法里面,会构建AlertDialog对像dialog。其中P.apply(dialog.mAlert);就是将P的属性

全部设置到Dialog的属性变量mAlert中:

        public 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);            }            //省略了次要代码      }                                     
4,Builder的create方法,最后返回了AlertDialog对象dialog。所以最后show方法,是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;        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();        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();    }

5,这里会调用dispatchOnCreate(null),最终会回调AlertDialog的onCreate方法。

        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            mAlert.installContent();        }        //一下是AlertController类中方法。        public void installContent() {            int contentView = selectContentView();            mWindow.setContentView(contentView);            setupView();        }        private int selectContentView() {            if (mButtonPanelSideLayout == 0) {                return mAlertDialogLayout;            }            if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {                return mButtonPanelSideLayout;            }            // TODO: use layout hint side for long messages/lists            return mAlertDialogLayout;        }
6,mAlert.installContent,即是在初始化AlertDialog的控件。(即通过fingViewById,关联控件)

7,最后通过mWindowManager.addView(mDecorView, l);加载到屏幕上。


注:

1,由上分析可知,我们如果想要自定义Dialog,继承AlertDialog,重新onCreate方法(给个建议)。

    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        initViews(getContext());    }    private void initViews(Context context){        setContentView(R.layout.dialog_horizontal);        tv_title = getWindow().findViewById(R.id.tv_title);        tv_size = getWindow().findViewById(R.id.tv_size);        progressBar = getWindow().findViewById(R.id.progress);        WindowManager.LayoutParams lp = getWindow().getAttributes();        lp.width = DensityUtil.dp2px(context.getApplicationContext(), 320);//        lp.width = WindowManager.LayoutParams.MATCH_PARENT;        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;        getWindow().setAttributes(lp);    }
2,其中mWindow是PhoneWindow。在AlertDialog的构造方法中生成。
    Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {        if (createContextThemeWrapper) {            if (themeResId == ResourceId.ID_NULL) {                final TypedValue outValue = new TypedValue();                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);                themeResId = outValue.resourceId;            }            mContext = new ContextThemeWrapper(context, themeResId);        } else {            mContext = context;        }        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        final Window w = new PhoneWindow(mContext);//        mWindow = w;        w.setCallback(this);        w.setOnWindowDismissedCallback(this);        w.setOnWindowSwipeDismissedCallback(() -> {            if (mCancelable) {                cancel();            }        });        w.setWindowManager(mWindowManager, null, null);        w.setGravity(Gravity.CENTER);        mListenersHandler = new ListenersHandler(this);    }











原创粉丝点击