对于一般的对话框来说,很多人习惯会用dismiss,因为并没有太大的区别。
但对于某些需要保存资源的对话框,比如地图控件,当dismiss后,再次打开,就会发现地图无法加载了,因为资源已经被清除了。
类似的还有滚动条状态,图片加载状态等等。
其实说区别,从名字上就能看出来,一个是取消,一个是隐藏。
本文主要从源码的角度看他们的区别。
@Override
public void dismiss() {
if (Looper.myLooper() == mHandler.getLooper()) {
dismissDialog();
} else {
mHandler.post(mDismissAction);
}
}
public void hide() {
if (mDecor != null) {
mDecor.setVisibility(View.GONE);
}
}
先看hide,这里涉及到一个mDecor的参数,我初步猜想是dialog的view的承载控件。
public void show() {
...
mDecor = mWindow.getDecorView();
...
}
赋值位置在show方法里面。
这里的getDecorView,可以看到如下代码:
/**
* Retrieve the top-level window decor view (containing the standard
* window frame/decorations and the client's content inside of that), which
* can be added as a window to the window manager.
*
* <p><em>Note that calling this function for the first time "locks in"
* various window characteristics as described in
* {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.</em></p>
*
* @return Returns the top-level window decor view.
*/
public abstract View getDecorView();
即返回顶层窗口的视图,很有意思的是,这里返回的是顶层窗口,并没有指定为哪一个窗口,理论上是会出现找错窗口的情况的,但是事实上,该方法是紧跟在show方法上的,show之后立即获取,不会出现找错窗口的情况。
再深我们就暂时不看了,接着看看dismiss方法。
它首先通过:
if (Looper.myLooper() == mHandler.getLooper()) {}
判断了当前线程是否是dialog的所在线程,如果是,就调用dismissdialog,如果不是则将dissmissaction这个操作,传递给dialog所在handle进行处理,我比较感兴趣这个dissmissaction这个参数。
private final Runnable mDismissAction = this::dismissDialog;
可以看到,这里出现了一个双冒号的使用,这是java8中引入的lambda的语法,可以等同于以下:
private final Runnable mDismissAction = new Runnable() {
@Override
public void run() {
dismissDialog()
}
}
很简洁的语法,android26的源码中已经开始大范围的使用lambda的语法了,所以推荐各位平时多尝试不同的lambda,并不只是使用android studio 3.0+默认的alt+enter转lambda,因为很多地方,是不会告诉你可以这样写的。
这里的dismissdialog:
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();
}
}
很直白的语句,先判断承载窗口view是否为空,或者dialog是否没有展示,如果是,就return掉。
然后判断,window是否已销毁,如果是,继续return。
最后通过windowmanager去移除承载窗口view-mDecor。
清除资源、回调关闭状态、发送关闭信息、改变dialog状态等等一系列操作。
源码就看到这,其实,大部分的源码,我们都没必要去看,因为具体的区别在前两段源码就足以看清楚区别了。
但我还是继续往里面挖了一下,可能对我们分析没有太大的用处,但是对于了解dialog的底层机制还是有很大的帮助的。
嗯,就到这儿了。