Android开发,源码分析Dialog/AlertDialog的dismiss()和hide()的区别

对于一般的对话框来说,很多人习惯会用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的底层机制还是有很大的帮助的。

嗯,就到这儿了。

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/Stanny_Bing/article/details/78844581
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞