二、Dialog的消失

1、dismiss

private final Runnable mDismissAction = this::dismissDialog;public void dismiss() {if (Looper.myLooper() == mHandler.getLooper()) {dismissDialog();} else {mHandler.post(mDismissAction);}
}
复制代码

保证UI操作都在主线程执行,而且引用了Java8新特性写法this::dismissDialog,最后都会调用dismissDialog()

2、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 {//这里移除DecorViewmWindowManager.removeViewImmediate(mDecor);} finally {if (mActionMode != null) {mActionMode.finish();}mDecor = null;mWindow.closeAllPanels();onStop();mShowing = false;sendDismissMessage();}
}
复制代码

从show中知道,我们将DecorView加入到WindowManager中去,所以这里移除的是DecorView

3、WindowManagerImpl.removeViewImmediate

public void removeViewImmediate(View view) {//委托给mGlobal来进行实现mGlobal.removeView(view, true);
}
复制代码

同样的交给WindowManagerGlobal去处理

4、WindowManagerGlobal.removeView

public void removeView(View view, boolean immediate) {if (view == null) {throw new IllegalArgumentException("view must not be null");}synchronized (mLock) {//待remove view的索引int index = findViewLocked(view, true);//mRoots保存着每一个viewRootImpl对象View curView = mRoots.get(index).getView();//真正对view进行了remove操作removeViewLocked(index, immediate);if (curView == view) {return;}throw new IllegalStateException("Calling with view " + view+ " but the ViewAncestor is attached to " + curView);}
}
复制代码

找到对应要移除的View后进行View逻辑处理工作

5、WindowManagerGlobal.removeViewLocked

private void removeViewLocked(int index, boolean immediate) {ViewRootImpl root = mRoots.get(index);View view = root.getView();if (view != null) {InputMethodManager imm = InputMethodManager.getInstance();if (imm != null) {imm.windowDismissed(mViews.get(index).getWindowToken());}}//重点在ViewRootImpl中的die方法中boolean deferred = root.die(immediate);if (view != null) {view.assignParent(null);if (deferred) {mDyingViews.add(view);}}
}
复制代码

找到对应的ViewRootImpl,进行移除并释放工作

6、ViewRootImpl.die

boolean die(boolean immediate) {if (immediate && !mIsInTraversal) {//继续跟踪doDie();return false;}if (!mIsDrawing) {destroyHardwareRenderer();} else {Log.e(TAG, "Attempting to destroy the window while drawing!\n" +"  window=" + this + ", title=" + mWindowAttributes.getTitle());}mHandler.sendEmptyMessage(MSG_DIE);return true;
}
复制代码

7、ViewRootImpl.doDie

void doDie() {checkThread();if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);synchronized (this) {if (mRemoved) {return;}mRemoved = true;if (mAdded) {//这里是真正移除Dialog的ViewdispatchDetachedFromWindow();}if (mAdded && !mFirst) {//硬件渲染destroydestroyHardwareRenderer();if (mView != null) {int viewVisibility = mView.getVisibility();boolean viewVisibilityChanged = mViewVisibility != viewVisibility;if (mWindowAttributesChanged || viewVisibilityChanged) {// If layout params have been changed, first give them// to the window manager to make sure it has the correct// animation info.try {if ((relayoutWindow(mWindowAttributes, viewVisibility, false)& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {mWindowSession.finishDrawing(mWindow);}} catch (RemoteException e) {}}//Surface的释放mSurface.release();}}mAdded = false;}//移除之前存储的变量WindowManagerGlobal.getInstance().doRemoveView(this);
}
复制代码

保证线程安全后,做移除和释放工作

8、WindowManagerGlobal.doRemoveView

一般程序最后的工作都是释放工作,移除之前存储的变量

void doRemoveView(ViewRootImpl root) {synchronized (mLock) {final int index = mRoots.indexOf(root);if (index >= 0) {//释放工作mRoots.remove(index);mParams.remove(index);final View view = mViews.remove(index);mDyingViews.remove(view);}}if (HardwareRenderer.sTrimForeground && HardwareRenderer.isAvailable()) {doTrimForeground();}
}
复制代码

9、ViewRootImpl.dispatchDetachedFromWindow

void dispatchDetachedFromWindow() {if (mView != null && mView.mAttachInfo != null) {mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);//此方法会回调onDetachedFromWindow方法,会做资源的回收mView.dispatchDetachedFromWindow();}mAccessibilityInteractionConnectionManager.ensureNoConnection();mAccessibilityManager.removeAccessibilityStateChangeListener(mAccessibilityInteractionConnectionManager);mAccessibilityManager.removeHighTextContrastStateChangeListener(mHighContrastTextManager);removeSendWindowContentChangedCallback();destroyHardwareRenderer();setAccessibilityFocus(null, null);mView.assignParent(null);mView = null;mAttachInfo.mRootView = null;mSurface.release();if (mInputQueueCallback != null && mInputQueue != null) {mInputQueueCallback.onInputQueueDestroyed(mInputQueue);mInputQueue.dispose();mInputQueueCallback = null;mInputQueue = null;}if (mInputEventReceiver != null) {mInputEventReceiver.dispose();mInputEventReceiver = null;}try {//这里调用了mWindowSession的remove方法,在WindowManagerService层通过IPC机制完成真正的window删除mWindowSession.remove(mWindow);} catch (RemoteException e) {}// Dispose the input channel after removing the window so the Window Manager// doesn't interpret the input channel being closed as an abnormal termination.if (mInputChannel != null) {mInputChannel.dispose();mInputChannel = null;}mDisplayManager.unregisterDisplayListener(mDisplayListener);unscheduleTraversals();
}
复制代码

到最后会和添加View的时候完成闭环,还是通过WindowSession的IPC机制去调用的,最后在WindowManagerService层通过IPC机制去实现的 ##总结 1.Dialog的dismiss和show形成闭环,调用的过程是相似的,只不过多了资源的释放环节

DialogFragment

DialogFragment本身继承自Fragment

public class DialogFragment extends Fragmentimplements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener
复制代码

在平时中,我们需要自定义WeDialogFragment,而且在正式开发中踩过的坑:

  • 需要对参数进行onSaveInstanceState操作,这类操作主要是防止异步吊起DialogFragment报nullPoint的Bug
  • 需要重写show(),对show做一层弹出时候的保护,这类操作主要是防止异步吊起DialogFragment报onSaveInstanceState的Bug
public class WeDialogFragment extends DialogFragment {@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);Bundle bundle = new Bundle();bundle.putString(BUNDLE_TITLE, title);}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setStyle(DialogFragment.STYLE_NO_TITLE, R.style.WeDialog);if (savedInstanceState != null) {title = savedInstanceState.getString(BUNDLE_TITLE);}}@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Dialog dialog = super.onCreateDialog(savedInstanceState);dialog.setCanceledOnTouchOutside(true);dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);dialog.getWindow().setWindowAnimations(R.style.DialogAnimation);dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);return dialog;}@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,@Nullable Bundle savedInstanceState) {return inflater.inflate(R.layout.view_fragment_dialog, container, false);}@Overridepublic void show(FragmentManager manager, String tag) {if (!manager.isStateSaved()) {super.show(manager, tag);}}
}
复制代码

然后在Activity中弹出DialogFragment

WeDialogFragment weDialogFragment = new WeDialogFragment();
weDialogFragment.show(activity.getSupportFragmentManager(),"weDialogFragment");
复制代码

一、DialogFragment的显示

1、DialogFragment.show

public void show(FragmentManager manager, String tag) {mDismissed = false;mShownByMe = true;FragmentTransaction ft = manager.beginTransaction();ft.add(this, tag);ft.commit();
}
复制代码

show的方法其实就是对Fragment的处理,将Fragment添加到Fragment栈中

二、DialogFragment的隐藏

####1、DialogFragment.dismiss

public void dismiss() {dismissInternal(false);
}public void dismissAllowingStateLoss() {dismissInternal(true);
}void dismissInternal(boolean allowStateLoss) {if (mDismissed) {return;}mDismissed = true;mShownByMe = false;if (mDialog != null) {mDialog.dismiss();}mViewDestroyed = true;if (mBackStackId >= 0) {getFragmentManager().popBackStack(mBackStackId,FragmentManager.POP_BACK_STACK_INCLUSIVE);mBackStackId = -1;} else {FragmentTransaction ft = getFragmentManager().beginTransaction();ft.remove(this);if (allowStateLoss) {ft.commitAllowingStateLoss();} else {ft.commit();}}
}
复制代码

dismiss的方法也是对Fragment的处理,将Fragment移除到Fragment栈中

三、Dialog的创建

1、DialogFragment.onCreateDialog

@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {return new Dialog(getActivity(), getTheme());
}
复制代码

和创建普通的Dialog没什么区别,我们重写该方法,可以自定义弹出AlertDialog等其他自定义Dialog

四、Dialog的视图

1、DialogFragment.onActivityCreated

@Override
public void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);if (!mShowsDialog) {return;}//拿到的就是onCreateView返回值的view对象,具体可以在Fragment源码找到View view = getView();if (view != null) {if (view.getParent() != null) {throw new IllegalStateException("DialogFragment can not be attached to a container view");}//真正设置viewmDialog.setContentView(view);}final Activity activity = getActivity();if (activity != null) {mDialog.setOwnerActivity(activity);}mDialog.setCancelable(mCancelable);mDialog.setOnCancelListener(this);mDialog.setOnDismissListener(this);if (savedInstanceState != null) {Bundle dialogState = savedInstanceState.getBundle(SAVED_DIALOG_STATE_TAG);if (dialogState != null) {mDialog.onRestoreInstanceState(dialogState);}}
}
复制代码

在Activity创建的时候,Fragment的周期会回调onActivityCreated,从而对Dialog设置视图

五、Dialog的显示隐藏

Dialog显示隐藏就简单了,随着Fragment的生命周期显示和隐藏,直接看代码就行了

@Override
public void onStart() {super.onStart();if (mDialog != null) {mViewDestroyed = false;mDialog.show();}
}@Override
public void onStop() {super.onStop();if (mDialog != null) {mDialog.hide();}
}
复制代码

总结

DialogFragment = Fragment + Dialog,DialogFragment本身继承Fragment,Fragment只是用来依附在Activity上,可以监听Activity的生命周期,从而去通知Dialog做对应的操作,而Dialog才是我们正在显示在屏幕上的弹窗,而非一个Fragment。这里的Dialog真正显示出来的View是从**onCreateView()中获取view后,在源码中调用dialog的setContentView()**显示出来的

文末送福利啦!!

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记免费分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。 **下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

资料免费领取方式:现在关注我并且加入群聊 群号:1018342383 或者是点击链接加入群聊【Android开发交流】:jq.qq.com/?_wv=1027&a…

Android弹窗组件工作机制之Dialog、DialogFragment(二)相关推荐

  1. Android进阶——Android弹窗组件工作机制之Dialog、DialogFragment

    前言 Android在DialogFragment推出后,就已经不推荐继续使用Dialog,可替换为DialogFragment,其实DialogFragment只不过是对增加一层看不到的Fragme ...

  2. 【Android】LMK 工作机制

    Android分析之LowMemoryKiller Android Kernel 会定时执行一次检查,杀死一些进程,释放掉内存. 那么,如何来判断,那些进程是需要杀死的呢?答案就是我们的标题:Low ...

  3. Hadoop生态圈(十三)- Namenode元数据管理及各组件工作机制

    目录 前言 1. Namenode元数据管理 1.1 元数据是什么 1.2 元数据管理概述 1.2.1 内存元数据 1.2.2 磁盘元数据 1.2.2.1 fsimage内存镜像文件 1.2.2.2 ...

  4. Android进阶——Android四大组件启动机制之Activity启动过程

    前言 Activity启动过程涉及到的比较多的知识点有Binder的跨进程通讯,建议先看完Binder的跨进程通讯再来阅读本篇文章,在文章阅读开始,我们先要理解Activity启动模型,再者去理解有关 ...

  5. Android Jetpack组件之数据库Room详解(二)

    本文涉及Library的版本如下: androidx.room:room-runtime:2.1.0-alpha03 androidx.room:room-compiler:2.1.0-alpha03 ...

  6. Android Binder驱动的工作机制之要旨

    最近,看了不少Android内核分析的书籍.文章及Android源程序.感觉自己对Android Binder的工作机制算是有了个彻底的理解. 但是,自己是花了很多时间和精力之后才达到这一点的.对于大 ...

  7. 探秘HDFS —— 发展历史、核心概念、架构、工作机制 (上)| 博文精选

    戳蓝字"CSDN云计算"关注我们哦! 作者 |  Mr-Bruce 转自 | CSDN博客 责编 | 阿秃 几周前,笔者做了一个与HDFS有关的技术分享,以知识普及为目的,主要分享 ...

  8. Android插件化开发之动态加载基础之ClassLoader工作机制

    类加载器ClassLoader 早期使用过Eclipse等Java编写的软件的同学可能比较熟悉,Eclipse可以加载许多第三方的插件(或者叫扩展),这就是动态加载.这些插件大多是一些Jar包,而使用 ...

  9. Android四大组件系列7 Broadcast广播机制(上)

    一 概述 广播 (Broadcast) 机制用于进程或线程间通信,广播分为广播发送和广播接收两个过程,其中广播接收者 BroadcastReceiver 是 Android 四大组件之一.Broadc ...

最新文章

  1. hdu 4876 ZCC loves cards(暴力)
  2. java正则 括号_java正则表达式获取大括号小括号内容并判断数字和小数亲测可用...
  3. nssl1436-赛艇表演【最短路】
  4. 搜索 —— 深度优先搜索(DFS)
  5. POJ 3734 Blocks (线性递推)
  6. Oracle存在修改,不存在插入记录 SQL
  7. 华为交换机配置远程连接
  8. font-family:微软雅黑;与font-family:Microsoft YaHei;的区别?
  9. 10张思维导图--javascript
  10. GraphPad Prism 统计教程 :高斯分布
  11. php 打水印,PHP 给图片制作水印的方法
  12. Exce批量发送邮件功能:发件人设置的操作
  13. 还敢搞黄色?4 个色情网站被一锅端,9 名福利姬被刑拘!
  14. linux永久修改dns
  15. Can't create pdf file with font calibri bold 错误解决方案
  16. php bloginfo templatedirectory,lt;?phpbloginfo(#39;template_directory#39;);?这句标签什么意思?...
  17. Zabbix Server trapper命令注入漏洞(CVE-2020-11800)
  18. [学科总结] 《矩阵论》
  19. ConvMixer:Patches Are All You Need
  20. 低潮是人生最佳升值期

热门文章

  1. sqlite 查询 支持多用户同时_开源时代的后端程序员必须要了解的一个数据库SQLite...
  2. python注释以符号什么开始_python注释以什么符号开始
  3. centos一键清理磁盘空间_磁盘空间不够用?教你一键清理电脑重复文件
  4. html3d样式,CSS+HTML3D文字效果
  5. VBox虚拟机仅主机模式时,出现connetct:Network is unreachable,解决方法
  6. lombok链式调用_记一次使用 Lombok 翻车造成的事故!
  7. mysql远程连接oracle数据库服务器配置_远程访问oracle数据库
  8. Python之web开发(三):python使用django框架搭建网站之SQLserver数据库连接
  9. 【视频课】StyleGAN人脸生成与年龄表情编辑:原理与实践
  10. 【完结】如何掌握基于图像和视频的人脸表情识别,这9篇文章可以作为一个参考...