android源码分析-Dialog

今天给大家介绍android -Dialog源码分析

 Dialog 是所有对话框的基类,例如AlertDialog,我们要深入了解指导Dialog的用法,逻辑,必须要把Dilaog弄清楚,下面首先我们来看下Google对Dialog的类描述:
 /**
  • Base class for Dialogs.
    Note: Activities provide a facility to manage the creation, saving and
  • restoring of dialogs. See {@link Activity#onCreateDialog(int)},
  • {@link Activity#onPrepareDialog(int, Dialog)},
  • {@link Activity#showDialog(int)}, and {@link Activity#dismissDialog(int)}. If
  • these methods are used, {@link #getOwnerActivity()} will return the Activity
  • that managed this dialog.
    Often you will want to have a Dialog display on top of the current
  • input method, because there is no reason for it to accept text. You can
  • do this by setting the {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
  • WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} window flag (assuming
  • your Dialog takes input focus, as it the default) with the following code:
  • getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
  •     WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);</pre>
    

*/
通过上面的描述,我们知道有2点重要的信息
1、Acitivity给我们提供了创建,预创建,展示,取消对话框的框架,在这个框架中我们不必担心额外的异常,这写方法包括:
onCreateDialog(int) :创建Dialog过程中要回调
onPrepareDialog(int, Dialog):准备创建对话框过程中要回调
showDialog(int):展示对话框
dismissDialog(int):取消对话框
架构流程图
这里很简单,大家可以自行阅读源码
2、WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 这个是WindowManager里面的flag标志位,当setFlag(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM );之后WindowManager中的EditText自动获取控件,将会获得焦点,有个相反的Flag就是,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,设置之后WindowManager中的视图将得不到任务焦点。

 接下来我看看Dialog的构造方法:
public Dialog(Context context, int theme) {
        this(context, theme, true);
    }

    Dialog(Context context, int theme, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (theme == 0) {
                TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
                        outValue, true);
                theme = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, theme);
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Window w = PolicyManager.makeNewWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);
        mListenersHandler = new ListenersHandler(this);
    }

Dialog的另外两个构造方法最终都要调用的这个方法,只不过在第三个参数为True,

 public Dialog(Context context) {
        this(context, 0, true);
    }
public Dialog(Context context, int theme) {
        this(context, theme, true);
    }

,所以我们先来分析下这个构造方法,首先看到了这个createContextThemeWrapper 参数,这个参数为true的话 dialog会查找系统的主题资源文件id,来初始化context。
如果theme==0,那么就查找theme,
if (theme == 0) { TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme, outValue, true); theme = outValue.resourceId; }
这里有个类TypedValue ,这个类主要是动态的表示和存储不同类型数据的容器,例如,系统资源resourceId,density,data,各种单位转化,例如,sp,dip,px,等等,这个类里面有个我们常用的方法:public static float applyDimension(int unit, float value, DisplayMetrics metrics) { switch (unit) { case COMPLEX_UNIT_PX: return value; case COMPLEX_UNIT_DIP: return value * metrics.density; case COMPLEX_UNIT_SP: return value * metrics.scaledDensity; case COMPLEX_UNIT_PT: return value * metrics.xdpi * (1.0f/72); case COMPLEX_UNIT_IN: return value * metrics.xdpi; case COMPLEX_UNIT_MM: return value * metrics.xdpi * (1.0f/25.4f); } return 0; }
来实现不同单位下的转化。
然后下面有这么一句context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
outValue, true);
这句里面其实是在查找resourceId,最后赋值到TypedValue 里面,Android系统里面系统资源的查找主要有2个类来实现一个是,Resources,和AssetManager,他们的主要区别是,Resources主要是通过资源id来查找资源,例如各种getText(int id),getDrawable(int id),getXml…都是通过id来查找的,而AssetManager,则是通过文件名字来查找的,

    mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

获得窗口管理者,负责对窗口中添加视图和移除视图,

 Window w = PolicyManager.makeNewWindow(mContext);

在这里创建了一个窗口类,我们可以看到这里有个PolicyManager类,这其实是个创建窗口的工厂类,我们看看源码:

public final class PolicyManager {
30    private static final String POLICY_IMPL_CLASS_NAME =
31        "com.android.internal.policy.impl.Policy";
32
33    private static final IPolicy sPolicy;
34
35    static {
36        // Pull in the actual implementation of the policy at run-time
37        try {
38            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
39            sPolicy = (IPolicy)policyClass.newInstance();
40        } catch (ClassNotFoundException ex) {
41            throw new RuntimeException(
42                    POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
43        } catch (InstantiationException ex) {
44            throw new RuntimeException(
45                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
46        } catch (IllegalAccessException ex) {
47            throw new RuntimeException(
48                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
49        }
50    }
51
52    // Cannot instantiate this class
53    private PolicyManager() {}
54
55    // The static methods to spawn new policy-specific objects
56    public static Window makeNewWindow(Context context) {
57        return sPolicy.makeNewWindow(context);
58    }
59
60    public static LayoutInflater makeNewLayoutInflater(Context context) {
61        return sPolicy.makeNewLayoutInflater(context);
62    }
63
64    public static WindowManagerPolicy makeNewWindowManager() {
65        return sPolicy.makeNewWindowManager();
66    }
67
68    public static FallbackEventHandler More ...makeNewFallbackEventHandler(Context context) {
69        return sPolicy.makeNewFallbackEventHandler(context);
70    }
71}

在这个类里面,我们首先会看到IPolicy,IPolicy是一个代理接口,

public interface IPolicy {
32    public Window makeNewWindow(Context context);
33
34    public LayoutInflater makeNewLayoutInflater(Context context);
35
36    public WindowManagerPolicy makeNewWindowManager();
37
38    public FallbackEventHandler makeNewFallbackEventHandler(Context context);
39}

这个接口有三个方法,makeNewWindow()创建一个新窗口,makeNewLayoutInflater创建LayoutInflater ,makeNewWindowManager 窗口管理代理,makeNewFallbackEventHandler,创建FallbackEventHandler 手机回退处理接口,FallbackEventHandler 的实现类有PhoneFallbackEventHandler
IPolicy 在static语句块中用反射实例化了com.android.internal.policy.impl.Policy,然后通过这个实例来创建窗口操作。
com.android.internal.policy.impl.Policy,通过这个我们指导IPolicy 的实现类是Policy ,我们看看Policy

public class More ...Policy implements IPolicy {
35    private static final String TAG = "PhonePolicy";
36
37    private static final String[] preload_classes = {
38        "com.android.internal.policy.impl.PhoneLayoutInflater",
39        "com.android.internal.policy.impl.PhoneWindow",
40        "com.android.internal.policy.impl.PhoneWindow$1",
41        "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
42        "com.android.internal.policy.impl.PhoneWindow$DecorView",
43        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
44        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
45    };
46
47    static {
48        // For performance reasons, preload some policy specific classes when
49        // the policy gets loaded.
50        for (String s : preload_classes) {
51            try {
52                Class.forName(s);
53            } catch (ClassNotFoundException ex) {
54                Log.e(TAG, "Could not preload class for phone policy: " + s);
55            }
56        }
57    }
58
59    public Window More ...makeNewWindow(Context context) {
60        return new PhoneWindow(context);
61    }
62
63    public LayoutInflater More ...makeNewLayoutInflater(Context context) {
64        return new PhoneLayoutInflater(context);
65    }
66
67    public WindowManagerPolicy More ...makeNewWindowManager() {
68        return new PhoneWindowManager();
69    }
70
71    public FallbackEventHandler More ...makeNewFallbackEventHandler(Context context) {
72        return new PhoneFallbackEventHandler(context);
73    }
74}在static里面会提前加载会用到的类,到此我们知道了PolicyManager.makeNewWindow(mContext);最终是是Policy通过直接实例化了PhoneWindow来生成的,android中的window类是抽象类,定义了窗口的行为,和部分实现,他们的实现类为PhoneWindow,在这里面我可以猜到,android系统要适配平板的话应该是有PadWindow,如果是手表的话估计有WatchWindow,具体的PhoneWindow的逻辑会在以后的文章深入分析。
	继续接到前面讲,mWindow = w;设置dialog的mWindow ,w.setCallback(this);设置dialog中mWindow 的回调实现,这样dialog就具有类window的行为,比如我们按back dialog就会关闭等等。
	w.setOnWindowDismissedCallback(this);设置dialog关闭行为回调,
	 mListenersHandler = new ListenersHandler(this);实例化ListenersHandler,ListenersHandler是继承Handler,负责dialog的show,cancel,dismiss的消息接受回调,具体Handler,机制可自行查阅资料,这里不在详述。
	 下面我们来看看dialog是如何展示到Activity中的。
	 首先我们看看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);
        }

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

        try {
            mWindowManager.addView(mDecor, l);
            mShowing = true;
    
            sendShowMessage();
        } finally {
        }
    }
    
    /**
     * Hide the dialog, but do not dismiss it.
     */
    public void hide() {
        if (mDecor != null) {
            mDecor.setVisibility(View.GONE);
        }
    }

逻辑还是很清晰的,首先判断根据if (mShowing) {
if (mDecor != null) {
if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
}
mDecor.setVisibility(View.VISIBLE);
}
return;
}
判断是否dialog正在展示,如果展示的话就 判断dialog是否有actionbar,如果有的话就初始化,然后显示,你可能要问actionbar是什么东西,就是最上面有各icon和名字的标题界面,我们的layout文件初始化的时候就能看到那个东西,dialog也是可以设置的。
然后mCanceled = false;,因为正要展示dialog,当然不能被取消了啊,只有在展示完了之后才可以消失操作,
mDecor = mWindow.getDecorView();设置dialog的mDecor 属性,每个窗口都有一个根视图,所以mDecor 也是dialog的根视图,dialog上的View都是mDecor 的子视图,这个概念在Activity中也存在。
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);
}
如果dialog设置了FEATURE_ACTION_BAR,那么给actionbar设置默认的icon和logo,这里有ApplicationInfo类,这个类描述了Mainifest.xml的配置信息,这个类也可以通过context.getPackageManager();进一步获得,icon,logo就是我们在<application 。。。节点下面配置的信息啦,

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

从mWindow获得dialog的布局属性信息,然后配置SOFT_INPUT_IS_FORWARD_NAVIGATION,这个Flag就是让窗口显示在最前面,这个信息一般有系统完成设置,l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0
在android系统中有很多的flag都是通过这种方式来存储和判断的,一来节省内存提高速度,二来方便逻辑操作,语法优美,在上面这断话是通过按位与操作符,来判SOFT_INPUT_IS_FORWARD_NAVIGATION是否存在,==0则不存在,具体为什么,稍微想下很好理解
WindowManager.LayoutParams 是描述窗口的位置,水平、垂直权重、窗口类型Type、窗口UI交互等众多配置信息的类Flag、例如FLAG_DIM_BEHIND,这个flag控制Window背景是否变暗(dialog就有这个属性),FLAG_NOT_FOCUSABLE设置window不要获取焦点,这样里面的editText不可以输入等等,我以后会在其它文章详细介绍。

     try {
            mWindowManager.addView(mDecor, l);
            mShowing = true;
    
            sendShowMessage();
        } finally {
        }

终于到了dialog的展示语句了,mWindowManager将mDecor视图添加如了窗口中,那么dialog就展示在了我们面前,mWindowManager的实现类是WindowManagerImpl,所以addView()是在WindowManagerImpl中实现的,那么我们看看是怎么实现的。


82     @Override
83     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
84         applyDefaultToken(params);
85         mGlobal.addView(view, params, mDisplay, mParentWindow);
86     }

applyDefaultToken(params); 如果IBinder为null则设置默认的IBinder,IBinder是FrameWork和Wms的通信桥梁,具体怎么实现的我还在继续学习研究,mGlobal.addView(view, params, mDisplay, mParentWindow);真正的添加动作是
public final class WindowManagerImpl implements WindowManager { 49 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); 50 private final Display mDisplay; 51 private final Window mParentWindow; 52 53 private IBinder mDefaultToken;

WindowManagerGlobal完成的,下面这张图看以看出WindowManagerGlobal的位置
这里写图片描述
具体WindowManagerGlobal中addView是怎么添加的,以后的文章会详细讲解。
sendShowMessage(); 这个方法是通知事件的回调例如展示,取消等等,Message.obtain(mShowMessage).sendToTarget();发送各种消息。
下面我们来分析下dismiss(),dialog如何消失的,

public void dismiss() {
        if (Looper.myLooper() == mHandler.getLooper()) {
            dismissDialog();
        } else {
            mHandler.post(mDismissAction);
        }
    }

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

if (Looper.myLooper() == mHandler.getLooper()) {
dismissDialog();
} else {
mHandler.post(mDismissAction);
}
在主线程和子线程都可以安全关闭对话框

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

mWindowManager立刻执行移除视图操作,finally中最后处理操作,回调onStop(),调用dialog消失回调接口,更改mShowing状态。
剩下的其它方法有一部分是Window.Callback,
KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback
接口中的方法,
还有一部分是PhoneWindow中的方法
接下来我来看看Dialog的一个实现类AlertDialog,警告对话框。

AlertDialog

AlertDialog是一个典型的建造者模式,通过Builder来构造AlertDialog,在构造过程中是通过AlertController来管理视图和属性的.下面是一个典型的展示代码:

new AlertDialog.Builder(self)
 .setTitle("标题") 
 .setMessage("简单消息框")
 	.setPositiveButton("确定", null)
 	.show();

AlertDialog 可以展示Text文本对话框,带有EditText对话框,单选对话框,多选对话框,列表对话。
AlertDialog 的构造方法如下

 protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
        super(context, resolveDialogTheme(context, 0));
        mWindow.alwaysReadCloseOnTouchAttr();
        setCancelable(cancelable);
        setOnCancelListener(cancelListener);
        mAlert = new AlertController(context, this, getWindow());
    }

首先我们看到了resolveDialogTheme(context, 0) 方法,我们看看,

static int resolveDialogTheme(Context context, int resid) {
        if (resid == THEME_TRADITIONAL) {
            return com.android.internal.R.style.Theme_Dialog_Alert;
        } else if (resid == THEME_HOLO_DARK) {
            return com.android.internal.R.style.Theme_Holo_Dialog_Alert;
        } else if (resid == THEME_HOLO_LIGHT) {
            return com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert;
        } else if (resid == THEME_DEVICE_DEFAULT_DARK) {
            return com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert;
        } else if (resid == THEME_DEVICE_DEFAULT_LIGHT) {
            return com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert;
        } else if (resid >= 0x01000000) {   // start of real resource IDs.
            return resid;
        } else {
            TypedValue outValue = new TypedValue();
            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
                    outValue, true);
            return outValue.resourceId;
        }
    }

咋这个方法中主要是按照条件设置主题,在AlertDialog中系统给我们提供了,几种主题可以选择,
THEME_TRADITIONAL:透明主题
THEME_HOLO_DARK:全黑色主题
THEME_HOLO_LIGHT:全亮色主题
THEME_DEVICE_DEFAULT_DARK:设备默认黑色主题
THEME_DEVICE_DEFAULT_LIGHT:设备默认亮色主题
在这里面我们看到了HOLO字样,这个其实是Android 系统在4.0后推出的新主题风格,这种主题分为黑色和亮色系和混合系列,在很多的控件都有这种主题可以选择,dialog只是其中一种而已。

else if (resid >= 0x01000000) {   // start of real resource IDs.
            return resid;
        }这里写代码片

如果不是系统的选择,那么就使用用户自己定义的主题,

else {
            TypedValue outValue = new TypedValue();
            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
                    outValue, true);
            return outValue.resourceId;
        }

如果都不是上面的选择,也不是自定义的,那么系统将给出默认的主题,com.android.internal.R.attr.alertDialogTheme,这种属性主题最终通过AssetManager来查找的mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);然后将查找的内容存到TypedValue中,这个在上面的内容中也详细的讲过了。
接下来我们看到了mWindow.alwaysReadCloseOnTouchAttr();这个我们看名字也大概猜到了什么作用呢,应该是在点击窗口外面关闭窗口,的确是这样,这个是在Window中的一个抽象方法,具体的实现是PhoneWindow中的,在PhoneWindow中的实现是很简单的

 public void More ...alwaysReadCloseOnTouchAttr() {
3548        mAlwaysReadCloseOnTouchAttr = true;
3549    }

你看就是赋值而已,那么最终这个属性是在哪里用呢 我们继续跟踪,

if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
3368                >= android.os.Build.VERSION_CODES.HONEYCOMB) {
3369            if (a.getBoolean(
3370                    R.styleable.Window_windowCloseOnTouchOutside,
3371                    false)) {
3372                setCloseOnTouchOutsideIfNotSet(true);
3373            }
3374        }

我们看到了,如果mAlwaysReadCloseOnTouchAttr ==true或者版本大于等于VERSION_CODES.HONEYCOMB(蜂巢,就是3…0版本啦),然后里面继续判断如果窗口风格设置Window_windowCloseOnTouchOutside了就setCloseOnTouchOutsideIfNotSet(true);而setCloseOnTouchOutsideIfNotSet(true) 方法是在Window中实现的

public void More ...setCloseOnTouchOutsideIfNotSet(boolean close) {
889         if (!mSetCloseOnTouchOutside) {
890             mCloseOnTouchOutside = close;
891             mSetCloseOnTouchOutside = true;
892         }
893     }

主要就是设置mCloseOnTouchOutside 和mSetCloseOnTouchOutside 为true。
构造方法接下来就是设置回调,和实例化AlertController了。

然后我们纵观整个AlertDialog,2点重要发现。
第一、AlertDialog只是个壳,真正的实现和管理控制都是通过AlertController来实现的,AlertController中的还有个AlertParams 类,AlertController主要是管理了相关的View和属性变量,很多方法都是对视图的初始化和设置,AlertParams 负责初始化工作例如里面有apply(AlertController dialog) 这个是初始化AlertDialog的方法,在AlertController的create中主要是它来实现的,

public void More ...apply(AlertController dialog) {
949             if (mCustomTitleView != null) {
950                 dialog.setCustomTitle(mCustomTitleView);
951             } else {
952                 if (mTitle != null) {
953                     dialog.setTitle(mTitle);
954                 }
955                 if (mIcon != null) {
956                     dialog.setIcon(mIcon);
957                 }
958                 if (mIconId != 0) {
959                     dialog.setIcon(mIconId);
960                 }
961                 if (mIconAttrId != 0) {
962                     dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
963                 }
964             }
965             if (mMessage != null) {
966                 dialog.setMessage(mMessage);
967             }
968             if (mPositiveButtonText != null) {
969                 dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
970                         mPositiveButtonListener, null);
971             }
972             if (mNegativeButtonText != null) {
973                 dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
974                         mNegativeButtonListener, null);
975             }
976             if (mNeutralButtonText != null) {
977                 dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
978                         mNeutralButtonListener, null);
979             }
980             if (mForceInverseBackground) {
981                 dialog.setInverseBackgroundForced(true);
982             }
983             // For a list, the client can either supply an array of items or an
984             // adapter or a cursor
985             if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
986                 createListView(dialog);
987             }
988             if (mView != null) {
989                 if (mViewSpacingSpecified) {
990                     dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
991                             mViewSpacingBottom);
992                 } else {
993                     dialog.setView(mView);
994                 }
995             } else if (mViewLayoutResId != 0) {
996                 dialog.setView(mViewLayoutResId);
997             }
998 
999             /*
1000            dialog.setCancelable(mCancelable);
1001            dialog.setOnCancelListener(mOnCancelListener);
1002            if (mOnKeyListener != null) {
1003                dialog.setOnKeyListener(mOnKeyListener);
1004            }
1005            */
1006        }

例如还有,createListView(final AlertController dialog) 创建ListView,就是AlertDialog中的多选,单选,列表视图的初始化,所以AlertController结构还是很简单的。
第二、点就是AlertDialog一般都是通过内部类Builder来实例化的,通过点语法风格方便的写,AlertDialog的建造着模式是Android中很经典的。Builder 有create和show 和一大堆配置方法,写法结构很值得我们学习,建造者模式在Android其他地方也可以发现,例如BitmapFactory 图片工厂,ViewPropertyAnimator View的属性动画,

AlertDialog的介绍就是这么多了,AlertDialog很方面的实现警告对话框,也就是说仅仅是警告对话框,很多时候他的布局是死的,远远不能满足我们需求,我们都会继承Dialog来自定义自己的dialog,还可以对设置的View设置动画,提高用户体验,那就发挥大家的想象吧!

Guess you like

Origin blog.csdn.net/fagawee/article/details/50720049