1.Activity中Dialog的使用方法
Activity提供了一套Dialog的管理机制,涉及到以下方法。
-
onCreateDialog: 创建dialog(需要重写)
-
onPrepareDialog: 在创建dialog后的其他准备工作(需要重写)
-
showDialog: 显示dialog(直接调用)
-
dismissDialog: 取消dialog的显示(直接调用)
-
removeDialog: 去掉该dialog(直接调用)
先以一个案例来练习下。(此机制已不被推荐使用,但由于ROM定制中有涉及到,所以特此分析下)
public class MainActivity extends Activity {
Button create;
Button remove;
private static final int TEST_DIALOG = 1;
private String TAG = "Sun: ";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
create = (Button) findViewById(R.id.createDialog);
create.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "showDialog");
showDialog(TEST_DIALOG);
}
});
remove = (Button) findViewById(R.id.removeDialog);
remove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "removeDialog");
removeDialog(TEST_DIALOG);
}
});
}
@Override
protected Dialog onCreateDialog(int id) {
Log.d(TAG, "onCreateDialog");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog dialog = builder.setTitle("Test_Dialog").setIcon(R.mipmap.ic_launcher)
.setMessage("Test_Message").setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, "dismissDialog");
dismissDialog(TEST_DIALOG);
}
}).create();
return dialog;
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
Log.d(TAG, "onPrepareDialog");
super.onPrepareDialog(id, dialog);
}
}
根据log来看方法的执行:
(1)先点击createDialog按钮
06-17 12:10:18.353 18470-18470/com.sunjing.myapplication D/Sun:: showDialog
06-17 12:10:18.353 18470-18470/com.sunjing.myapplication D/Sun:: onCreateDialog
06-17 12:10:18.373 18470-18470/com.sunjing.myapplication D/Sun:: onPrepareDialog
(2)先点击createDialog按钮,等dialog显示后,再点击dialog的"OK"按钮,取消dialog的显示
06-17 12:10:18.353 18470-18470/com.sunjing.myapplication D/Sun:: showDialog
06-17 12:10:18.353 18470-18470/com.sunjing.myapplication D/Sun:: onCreateDialog
06-17 12:10:18.373 18470-18470/com.sunjing.myapplication D/Sun:: onPrepareDialog
06-17 12:10:31.973 18470-18470/com.sunjing.myapplication D/Sun:: dismissDialog
(3)先点击createDialog按钮,等dialog显示后,再点击dialog的"OK"按钮,取消dialog的显示,再次点击createDialog按钮
06-17 12:10:18.353 18470-18470/com.sunjing.myapplication D/Sun:: showDialog
06-17 12:10:18.353 18470-18470/com.sunjing.myapplication D/Sun:: onCreateDialog
06-17 12:10:18.373 18470-18470/com.sunjing.myapplication D/Sun:: onPrepareDialog
06-17 12:10:31.973 18470-18470/com.sunjing.myapplication D/Sun:: dismissDialog
06-17 12:10:47.977 18470-18470/com.sunjing.myapplication D/Sun:: showDialog
06-17 12:10:47.977 18470-18470/com.sunjing.myapplication D/Sun:: onPrepareDialog
(4) 先点击 createDialog按钮,等dialog显示后,再点击dialog的"OK"按钮, 取消dialog的显示,然后再点击removeDialog按钮,最后再点击 createDialog按钮
06-17 12:11:15.241 22224-22224/com.sunjing.myapplication D/Sun:: showDialog
06-17 12:11:15.241 22224-22224/com.sunjing.myapplication D/Sun:: onCreateDialog
06-17 12:11:15.265 22224-22224/com.sunjing.myapplication D/Sun:: onPrepareDialog
06-17 12:11:20.665 22224-22224/com.sunjing.myapplication D/Sun:: dismissDialog
06-17 12:11:21.361 22224-22224/com.sunjing.myapplication D/Sun:: removeDialog
06-17 12:11:21.841 22224-22224/com.sunjing.myapplication D/Sun:: showDialog
06-17 12:11:21.841 22224-22224/com.sunjing.myapplication D/Sun:: onCreateDialog
06-17 12:11:21.845 22224-22224/com.sunjing.myapplication D/Sun:: onPrepareDialog
2.源码分析
下面以Activity的源码进行分析
showDialog方法:// 调用showDialog(id, null)方法
public final void showDialog(int id) {
showDialog(id, null);
}
public final boolean showDialog(int id, Bundle args) {
// private SparseArray<ManagedDialog> mManagedDialogs;
if (mManagedDialogs == null) {
mManagedDialogs = new SparseArray<ManagedDialog>();
}
// 通过id获取ManagedDialog对象(id还是蛮重要的)
ManagedDialog md = mManagedDialogs.get(id);
if (md == null) { // 获取不到就重新创建
md = new ManagedDialog();
md.mDialog = createDialog(id, null, args); // 调用createDialog创建dialog(只需创建,无需show)
if (md.mDialog == null) {
return false;
}
mManagedDialogs.put(id, md); // 将创建好的dialog以及id一起放到集合中,方便后面获取
}
md.mArgs = args;
onPrepareDialog(id, md.mDialog, args); // 调用onPrepareDialog方法,在dialog显示之前的其他逻辑控制
md.mDialog.show(); // 显示dialog
return true; // 根据返回值可以判断是否创建成功
}
createDialog方法:
// createDialog方法
private Dialog createDialog(Integer dialogId, Bundle state, Bundle args) {
// 调用onCreateDialog方法去执行具体的创建dialog的逻辑,即Activity的继承类需要去重写这个方法
final Dialog dialog = onCreateDialog(dialogId, args);
if (dialog == null) {
return null;
}
dialog.dispatchOnCreate(state);
return dialog; // 返回创建的这个dialog对象
}
onCreateDialog方法:
// Activity自身的onCreateDialog方法返回值为空
protected Dialog onCreateDialog(int id, Bundle args) {
return onCreateDialog(id);
}
protected Dialog onCreateDialog(int id) {
return null;
}
onPrepareDialog方法:
// 在dialog显示之前,可以做一些其他相应的逻辑设置工作
protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
onPrepareDialog(id, dialog);
}
protected void onPrepareDialog(int id, Dialog dialog) {
dialog.setOwnerActivity(this);
}
dismissDialog方法:
// dismissDialog方法
public final void dismissDialog(int id) {
if (mManagedDialogs == null) {
throw missingDialog(id);
}
// 获取id对应的dialog
final ManagedDialog md = mManagedDialogs.get(id);
if (md == null) {
throw missingDialog(id);
}
// 不显示dialog,但是该dialog依然还在SparseArray中
md.mDialog.dismiss();
}
removeDialog方法:
// removeDialog方法
public final void removeDialog(int id) {
if (mManagedDialogs != null) {
final ManagedDialog md = mManagedDialogs.get(id); // 根据id获取dialog对象
if (md != null) {
md.mDialog.dismiss(); // dismiss掉dialog
mManagedDialogs.remove(id); // 并且从SparseArray中移除掉该id相应的对象
}
}
}
ManagedDialog类(Activity的内部类):
// ManagedDialog类
private static class ManagedDialog {
Dialog mDialog;
Bundle mArgs;
}
private SparseArray<ManagedDialog> mManagedDialogs;
根据上面的源码分析发现,在dismissDialog后,dialog仅仅是不显示了,但是dialog对象并没有从SparseArray中删除,所以在showDialog后,是可以通过id从SparseArray直接获取这个dialog的,无需再次重新创建。
然而removeDialog时,不仅dismiss掉这个dialog,此外,还从SparseArray中直接删除id对应的dialog对象,所以SparseArray不存在这个id的dialog对象了,如果还要显示这个dialog的话,还需要再次重新创建这个dialog,在进行显示。