AlertDialog源碼分析

在Android源碼中亿柑,最常用到的Builder模式的就是AlertDialog.Builder.

public class AlertDialog extends AppCompatDialog implements DialogInterface {

    final AlertController mAlert;   //用來接收Builder成員變量P中的各個(gè)參數(shù)
    static final int LAYOUT_HINT_SIDE = 1;
   protected AlertDialog(@NonNull Context context) {
        this(context, 0);
    }


    protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, resolveDialogTheme(context, themeResId));
        mAlert = new AlertController(getContext(), this, getWindow());
    }

......................省略代碼...................
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
  //實(shí)際上是mAlert的setTitle方法
        mAlert.setTitle(title);
    }
 Builder是AlertDialog 的內(nèi)部類
public static class Builder {
        private final AlertController.AlertParams P;
        private final int mTheme;

     
        public Builder(@NonNull Context context) {
            this(context, resolveDialogTheme(context, 0));
        }


//設(shè)置各種參數(shù)
        public Builder setView(View view) {
            P.mView = view;
            P.mViewLayoutResId = 0;
            P.mViewSpacingSpecified = false;
            return this;
        }
//構(gòu)建AlertDialog邢疙,傳遞參數(shù)
        public AlertDialog create() {
       
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
//將p中的參數(shù)應(yīng)用到dialog的mAlert對(duì)象中
            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;
        }

     }
上述代碼中,Builder設(shè)置AlertDialog中title、message疟游、button等參數(shù)呼畸,這些參數(shù)都存儲(chǔ)在AlertController.AlertParams P中,其中包含了與AlertDialog視圖中對(duì)應(yīng)的成員變量
看一下P.apply()方法
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));
                }
            } 
在apply函數(shù)中颁虐,只是將AlertParams 參數(shù)設(shè)置到AlertController中蛮原,例如,將標(biāo)題設(shè)置到Dialog對(duì)應(yīng)的標(biāo)題視圖中另绩,需要我們調(diào)用show()方法儒陨。
   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) {
//來調(diào)用AlertDialog的oncreate()函數(shù)
            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);
        }
//調(diào)用Alert的onstart方法
        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;
        }
//將Dialog的DecorView添加到WindowManager中
        mWindowManager.addView(mDecor, l);
        mShowing = true;

        sendShowMessage();
    }
下面來看一下dispatchOnCreate()這個(gè)方法


 void dispatchOnCreate(Bundle savedInstanceState) {
        if (!mCreated) {
            onCreate(savedInstanceState);//調(diào)用Dialog的oncreate,空方法笋籽,   AlertDialog繼承Dialog蹦漠,其自身實(shí)現(xiàn)
            mCreated = true;
        }
    }
AlertDialog的oncreate()方法
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }
跳轉(zhuǎn)進(jìn)去,查看其方法
public void installContent() {
        final int contentView = selectContentView();
        mDialog.setContentView(contentView);
        setupView();
    }
調(diào)用setContentView和Activity的一樣车海,這里設(shè)置AlertDialog的內(nèi)容布局笛园,這個(gè)內(nèi)容布局就是mAlertDialogLayout字段的值,這個(gè)值在AlertController的構(gòu)造函數(shù)中進(jìn)行了初始化侍芝。

最后就是setupView()方法了研铆,初始化AlertDialog布局中各個(gè)部分,Dialog視圖部分設(shè)置完畢州叠。 當(dāng)用戶調(diào)用show()方法時(shí)棵红,WindowManager會(huì)將Window的DecorView(mAlertDialogLayout的視圖), mWindowManager.addView(mDecor, l);添加到用戶窗口上咧栗。
至此逆甜,Dialog就出現(xiàn)在用戶的視野中了。楼熄。忆绰。浩峡。可岂。

Builder模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翰灾,隨后出現(xiàn)的幾起案子缕粹,更是在濱河造成了極大的恐慌,老刑警劉巖纸淮,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件平斩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡咽块,警方通過查閱死者的電腦和手機(jī)绘面,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摊溶,“玉大人颊埃,你說我怎么就攤上這事「炊撸” “怎么了瘦馍?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵歼秽,是天一觀的道長。 經(jīng)常有香客問我情组,道長燥筷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任院崇,我火速辦了婚禮肆氓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘底瓣。我一直安慰自己做院,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布濒持。 她就那樣靜靜地躺著键耕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柑营。 梳的紋絲不亂的頭發(fā)上屈雄,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音官套,去河邊找鬼酒奶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛奶赔,可吹牛的內(nèi)容都是我干的惋嚎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼站刑,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼另伍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起绞旅,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤摆尝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后因悲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堕汞,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年晃琳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了讯检。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琐鲁。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖人灼,靈堂內(nèi)的尸體忽然破棺而出绣否,到底是詐尸還是另有隱情,我是刑警寧澤挡毅,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布蒜撮,位于F島的核電站,受9級(jí)特大地震影響跪呈,放射性物質(zhì)發(fā)生泄漏段磨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一耗绿、第九天 我趴在偏房一處隱蔽的房頂上張望苹支。 院中可真熱鬧,春花似錦误阻、人聲如沸债蜜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寻定。三九已至,卻和暖如春精耐,著一層夾襖步出監(jiān)牢的瞬間狼速,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工卦停, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留向胡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓惊完,卻偏偏與公主長得像僵芹,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子小槐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容