一、首先我们先看下Activity是如何显示View
平常我们在Activity的onCreate会调用setContentView(R.layout.xxx),Activity启动过程与window的源码流程可参考
Activity Window WMS的源码关系流程介绍
总结几个步骤:
1、创建Activity:ActivityThread的performLaunchActivity函数中创建Activity后,调用Activity.attach函数
2、创建PhoneWindow:Activity.attach函数中创建与之关联的PhoneWindow,PhoneWindow会创建DectorView。
3、添加视图:setContentView添加到PhoneWindow的DectorView中
4、关联PhoneWindow到WMS中:ActivityThread实行完performLaunchActivity,会handleResumeActivity,走到Activity的onResume,然后设置Activity的PhoneWindow的type类型:
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
.....
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
...
}
}
PhoneWindow会创建DectorView,通过WindowManagerImpl-->WindowManagerGlobal-->ViewRootImpl-->(binder)WMS中的Session的addToDisplay函数,这样视图就会显示出来。
我们看下l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
WindowManager.java:
public interface WindowManager extends ViewManager {
/**
* Window type: an application window that serves as the "base" window
* of the overall application; all other application windows will
* appear on top of it.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_BASE_APPLICATION = 1;
}
从英文翻译来看,这个type是应用程序的window类型。
二、Dialog显示View:
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("Message部分");
builder.setTitle("Title部分");
builder.setView(R.layout.dialog_main);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
alertDialog = builder.create();
alertDialog.show();
我们顺着alertDialog.show():
public AlertDialog create() {
// Context has already been wrapped with the appropriate theme.
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
其中final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
this(context, 0);
setCancelable(cancelable);
setOnCancelListener(cancelListener);
}
AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
createContextThemeWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
super是Dialog,接着看Dialog的构造函数:
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
...
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Window w = new PhoneWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
}
这边会创建Dialog的PhoneWindow,我们看PhoneWindow的构造函数
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
父类Window的
public abstract class Window {
// The current window attributes.
private final WindowManager.LayoutParams mWindowAttributes =
new WindowManager.LayoutParams();
//默认的PhoneWindow类型
public Window(Context context) {
mContext = context;
mFeatures = mLocalFeatures = getDefaultFeatures(context);
}
}
看WindowManager.LayoutParams:
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
这个type的默认window类型是TYPE_APPLICATION:
/**
* Window type: a normal application window. The {@link #token} must be
* an Activity token identifying who the window belongs to.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_APPLICATION = 2;
这个Dialog的window就需要依赖Activity来显示了。
三、直接使用系统级的Window类型,来添加View:
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_FULLSCREEN;
layoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
layoutParams.gravity = Gravity.CENTER;
layoutParams.x = 0;
layoutParams.y = 0;
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.format = PixelFormat.TRANSPARENT;
LayoutInflater layoutInflater = (LayoutInflater) LayoutInflater.from(context);
View view = (View) layoutInflater.inflate(R.layout.window_test_main, null);
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
windowManager.addView(view, layoutParams);
这个context上下文可以是service、application的。
其中layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
/**
* Window type: internal system error windows, appear on top of
* everything they can.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10;
这是系统级的window