1. AltertDialog
Android中到处都是Dialog用来向用户展示信息和询问用户的选择。要使用Android的对话框非常简单,只需要使用AlterDialog这个类即可创建一个Android系统提供的标准样式的Dialog。
标准样式的Dialog含有一个或者二个或者三个按钮,可以显示标题和信息。
下面是一个最简单的Dialog的使用的Demo
public class MainActivity extends ActionBarActivity {
private Button dialogButton;
private DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "Button" + which + "was clicked", Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dialogButton = (Button)findViewById(R.id.dialog_button);
dialogButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Title");
builder.setMessage("Hello AlertDialog");
builder.setPositiveButton("Positive", listener);
builder.setNegativeButton("Negative", listener);
builder.setNeutralButton("Neutral", listener);
AlertDialog dialog = builder.create();
dialog.show();
/*
new AlertDialog.Builder(MainActivity.this)
.setTitle("Title")
.setMessage("Hello AlertDialog")
.setPositiveButton("Positive", listener)
.setNegativeButton("Negative", listener)
.setNeutralButton("Neutral", listener)
.create()
.show();*/
}
});
}
}
上面的示例向我们展示了Android的标准对话框的最基本用法。
点击Button,弹出Dialog。
对话框的五个基本元素
1. title: 设置Dialog的标题, setTitle(“Title”)。
2. Message: 设置Dialog的内容, setMessage(“Hello AlertDialog”)。
3. Positive Button: 设置Positive Button的文字及其回调,setPositiveButton(“Positive”, listener)。
4. Neutral Button: 设置Neutral Button的文字及其回调,setNeutralButton(“Neutral”, listener)
5. Negative: 设置Negative Button的文字及其回调,setNegativeButton(“Negative”, listener)
运行Demo程序,点击Button,弹出如下对话框:
2. AlterDialog的构建者AlterDialog.Builder
在构造AlterDialog的时候,用到了AlterDialog.Builder这个类。首先创建了AlterDialog.Builder类,设置Builder的title,Message,Button及Button回调。在构建玩Builder类以后,调用Builder.Create,正式创建AlterDialog。这是为什么呢?
我们来看一下AlterDialog.Builder的源码,并以最简单的setTitle为例。
看一下最简单的
public static class Builder {
private final AlertController.AlertParams P;
private int mTheme;
/**
* Constructor using a context for this builder and the {@link AlertDialog} it creates.
*/
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
....
....
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, 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;
}
}
其中P是一个保存设置AlterDialog的参数类AlertParams的对象
很显然,Builder只是将AlterDialog的参数存放在一个参数对象里,做一个暂时的保存。
在最后调用create方法的时候,创建一个AlterDialog对象,将暂存的参数P一次性应用到这个Dialog对象上。完成Dialog的创建。
我们看到setTitle这样的函数的返回值是this,返回了本身,所以这样的函数可以用作连续调用。
所以Demo中的
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle("Title");
builder.setMessage("Hello AlertDialog");
builder.setPositiveButton("Positive", listener);
builder.setNegativeButton("Negative", listener);
builder.setNeutralButton("Neutral", listener);
AlertDialog dialog = builder.create(); dialog.show();
可以更简洁的写成
new AlertDialog.Builder(MainActivity.this)
.setTitle("Title")
.setMessage("Hello AlertDialog")
.setPositiveButton("Positive", listener)
.setNegativeButton("Negative", listener)
.setNeutralButton("Neutral", listener)
.create()
.show();
如果我们想要创建一个AlterDialog对象,完全可以直接调用AlterDialog的构造函数,或者调用AlterDialog为我们提供setTitle,用来做参数设置。为什么Android要那么麻烦增加一个Builder类呢?
3 如果没有AlterDialog.Buidler
AlterDialog有很多的参数,如我们上面列举的title,message,三个button及其回调,除此以外还有icon,View等属性。如果Android不采用Builder,而采用普通的构造函数来设计AlterDialog,可能要写出很多类似于如下的构造函数:
AlertDialog(String title);
AlertDialog(String message)
AlertDialog(int resId)
AlertDialog(int resId, String title, String message);
AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener);
AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener);
AlterDialog(int resId, String title, String message, String NegativeButtonString, OnClickListener listener);
AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener, String NegativeButtonString, OnClickListener listener);
....
实际上由于AlterDialog的参数众多,组合众多,AlterDialog需要很多个构造函数,而且这将随着AlterDialog的参数的增加而急剧膨胀,最终失去控制。
所以重叠构造函数的方式是可行的,但是会使客户端的代码编写难度增加,且难以阅读。比如如下的客户端代码:
AlterDialog dialog = new AlterDialog("hello", "nihao");
如果用户手边没有API手册,无法记住”hello”和”nihao”,谁是title,谁是message。
那怎么办呢?我们可以借助于Builder模式
4 Builder模式
Builder模式:不直接生成想要的对象,而是让客户端利用构造函数构造一个Builder对象,然后客户端代码在Builder上调用setter方法,用来设置每个参数。最后调用Builder的create方法,生成真正想要的对象。
Builder首先构建了一个最基本的Builder实例,然后提供了一系列setter函数,就像为对象提供具名的可选参数。
AlterDialog.Builder就是Builder模式最好的应用,由于AlterDialog有很多个参数,如果采用构造函数直接构造AlterDialog,会产生构造函数膨胀,也增加了客户端在编写AlterDialog的代码的时候的难度。所以AlterDialog借助于其内部类,Builder,首先以最必须的参数(context)构造了一个Builder对象,然后依次调用setter(比如setTitle, setMessage….)函数,将AlterDialog的参数暂存起来,最后调用create函数,创建一个AlterDialog对象,并将之前暂存的参数一次性应用到该对象上。完成目标对象的创建。
Builder模式有几个好处:
1. Builder的setter函数可以包含安全检查,可以确保构建过程的安全,有效。
2. Builder的setter函数是具名函数,有意义,相对于构造函数的一长串函数列表,更容易阅读维护。
3. 可以利用单个Builder对象构建多个对象,Builder的参数可以在创建对象的时候利用setter函数进行调整
当然Builder模式也有缺点:
1. 更多的代码,需要Builder这样的内部类
2. 增加了类创建的运行时开销
但是当一个类参数很多的时候,Builder模式带来的好处要远胜于其缺点。