一、首先我們先看下Activity是如何顯示View
平常我們在Activity的onCreate會調(diào)用setContentView(R.layout.xxx)臂港,Activity啟動過程與window的源碼流程可參考
Activity Window WMS的源碼關(guān)系流程介紹
總結(jié)幾個步驟:
1卿捎、創(chuàng)建Activity:ActivityThread的performLaunchActivity函數(shù)中創(chuàng)建Activity后配紫,調(diào)用Activity.attach函數(shù)
2、創(chuàng)建PhoneWindow:Activity.attach函數(shù)中創(chuàng)建與之關(guān)聯(lián)的PhoneWindow,PhoneWindow會創(chuàng)建DectorView午阵。
3躺孝、添加視圖:setContentView添加到PhoneWindow的DectorView中
4、關(guān)聯(lián)PhoneWindow到WMS中:ActivityThread實(shí)行完performLaunchActivity底桂,會handleResumeActivity植袍,走到Activity的onResume,然后設(shè)置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會創(chuàng)建DectorView籽懦,通過WindowManagerImpl-->WindowManagerGlobal-->ViewRootImpl-->(binder)WMS中的Session的addToDisplay函數(shù)于个,這樣視圖就會顯示出來。
我們看下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是應(yīng)用程序的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的構(gòu)造函數(shù):
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);
}
這邊會創(chuàng)建Dialog的PhoneWindow羽氮,我們看PhoneWindow的構(gòu)造函數(shù)
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();
//默認(rèn)的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的默認(rèn)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來顯示了。
三惫恼、直接使用系統(tǒng)級的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的祈纯。
其中l(wèi)ayoutParams.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;
這是系統(tǒng)級的window