android dialog 源码,Android Dialog源码分析

1.当我们查看android dialog源码,首先查看dialog的构造方法,初始化相关数据。由源码可知Dialog获取当前的themeId,通过 new ContextThemeWrapper(context, themeResId);设置主题返回Context对象。通过new PhoneWindow()创建Window对象,设置Window相关方法,

public Dialog(@NonNull Context context) {

this(context, 0, true);

}

public Dialog(@NonNull Context context, @StyleRes int themeResId) {

this(context, themeResId, true);

}

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {

if (createContextThemeWrapper) {

if (themeResId == ResourceId.ID_NULL) {

final TypedValue outValue = new TypedValue();

context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);

themeResId = outValue.resourceId;

}

mContext = new ContextThemeWrapper(context, themeResId);

} else {

mContext = context;

}

mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

final Window w = new PhoneWindow(mContext);

mWindow = w;

w.setCallback(this);

w.setOnWindowDismissedCallback(this);

w.setOnWindowSwipeDismissedCallback(() -> {

if (mCancelable) {

cancel();

}

});

w.setWindowManager(mWindowManager, null, null);

w.setGravity(Gravity.CENTER);

mListenersHandler = new ListenersHandler(this);

}

Dialog创建类似activity创建,通过new PhoneWidow对象,我们查看以下源码调用setContentView()方法可知通过Window实现类PhoneWindow将布局文件添加到DectorView中。

//以下是Window相关的代码

public void setContentView(@LayoutRes int layoutResID) {

mWindow.setContentView(layoutResID);

}

//以下是PhoneWindow的相关的代码

public void setContentView(int layoutResID) {

if (mContentParent == null) {

installDecor();

} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

mContentParent.removeAllViews();

}

if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,

getContext());

transitionTo(newScene);

} else {

mLayoutInflater.inflate(layoutResID, mContentParent);

}

mContentParent.requestApplyInsets();

final Callback cb = getCallback();

if (cb != null && !isDestroyed()) {

cb.onContentChanged();

}

mContentParentExplicitlySet = true;

}

2.查看dialog的show()方法,在show()方法中,判断当前dialog是否已经显示,调用oncreate(),onStart(),获取getDecorView(),通过windowManager添加DectorView,发送消息给主线程通知弹窗已经show.

public void show() {

if (mShowing) {

if (mDecor != null) {

if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {

mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);

}

mDecor.setVisibility(View.VISIBLE);

}

return;

}

mCanceled = false;

if (!mCreated) {

dispatchOnCreate(null);

} else {

final Configuration config = mContext.getResources().getConfiguration();

mWindow.getDecorView().dispatchConfigurationChanged(config);

}

onStart();

mDecor = mWindow.getDecorView();

if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {

final ApplicationInfo info = mContext.getApplicationInfo();

mWindow.setDefaultIcon(info.icon);

mWindow.setDefaultLogo(info.logo);

mActionBar = new WindowDecorActionBar(this);

}

WindowManager.LayoutParams l = mWindow.getAttributes();

if ((l.softInputMode

& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {

WindowManager.LayoutParams nl = new WindowManager.LayoutParams();

nl.copyFrom(l);

nl.softInputMode |=

WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;

l = nl;

}

mWindowManager.addView(mDecor, l);

mShowing = true;

sendShowMessage();

}

当我们查看dismissDisDialog()方法时,可知通过widowManager移除DectorView,mWindowManager.removeViewImmediate(mDecor);

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();

}

}

以下是消息处理,弹窗显示,取消,消失。

Private static final class ListenersHandler extends Handler {

private final WeakReference mDialog;

public ListenersHandler(Dialog dialog) {

mDialog = new WeakReference<>(dialog);

}

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case DISMISS:

((OnDismissListener) msg.obj).onDismiss(mDialog.get());

break;

case CANCEL:

((OnCancelListener) msg.obj).onCancel(mDialog.get());

break;

case SHOW:

((OnShowListener) msg.obj).onShow(mDialog.get());

break;

}

}

}

以上就是Dialog创建和消失的过程,普通Dialog的Context必须通过Activity持有的Context才可以,不然会报异常,报错信息是没有应用token所致,而应用token是Activity持有的,系统弹窗不需要token,在WindowManager.LayoutParams中的type表示window的类型,系统层级范围在2000~2999。若传Application 的Context对象,可以使用如下所示:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

在Manifest声明权限可以使用系统Window

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值