The Window creation process of Android Activity Dialog and Toast

One: Activity's Window creation process

During the creation of the Activity, the ActivityThread's

performLaunchActivity() to complete the entire startup process, which will be created internally through the class loader

Activity instance object, and call the attach method to associate a series of context variables. exist

In the attach method of Activity, the system will create the corresponding Window object and set the callback interface.

Then attach the view to the Window in the Activity's setContentView method:

Activity.java

final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor
voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode !=
WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
···
}
···
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
PhoneWindow.java
@Overridepublic void setContentView(int layoutResID) {
if (mContentParent == null) { // 如果没有DecorView,就创建
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
// 回调Activity 的onContentChanged 方法通知Activity 视图已经发生改变
cb.onContentChanged();
}
}

At this time, DecorView has not been officially added by WindowManager. in ActivityThread

In the handleResumeActivity method of the Activity, the onResume method of the Activity will be called first,

Then call Activity's makeVisible() to complete the process of adding and displaying DecorView:

Activity.java

void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}

Two: Dialog's Window creation process

The creation process of Dialog's Window is similar to that of Activity, which is also created through

The makeNewWindow method of PolicyManager is completed, and the created object is actually

PhoneWindow. When the Dialog is closed, it will be removed through the WindowManager

DecorView:mWindowManager.removeViewImmediate(mDecor)。

Dialog.java

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.setOnWindowSwipeDismissedCallback(() -> {
if (mCancelable) {
cancel();
}
});
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
}

Ordinary Dialog must use the Activity Context, and the Application Context is

An error will be reported because of the application token, which is generally only owned by the Activity. Tie

The traditional Window is special and does not require a token.

Three: Toast's Window creation process

Toast belongs to the system Window, because it has the function of timing cancellation, so the system uses Handler.

There are two types of IPC processes inside Toast, the first type is Toast access

NotificationManagerService, the second category is the NotificationManagerService callback

TN interface in Toast.

The view inside Toast has two ways, one is the default style of the system, and the other is setView

Define a custom View, they all correspond to an internal member mNextView of Toast.

Toast.java

public void show() {
if (mNextView == null) {
throw new RuntimeException("setView must have been called");
}
INotificationManager service = getService();
String pkg = mContext.getOpPackageName();
TN tn = mTN;
tn.mNextView = mNextView;
try {
service.enqueueToast(pkg, tn, mDuration);
} catch (RemoteException e) {
// Empty
}
}
···
public void cancel() {
mTN.cancel();
}
NotificationManagerService.java
private void showNextToastLocked() {
ToastRecord record = mToastQueue.get(0);
while (record != null) {
if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" +
record.callback);
try {
record.callback.show();
scheduleTimeoutLocked(record, false);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Object died trying to show notification " +
record.callback
+ " in package " + record.pkg);
// remove it from the list and let the process die
int index = mToastQueue.indexOf(record);
if (index >= 0) {
mToastQueue.remove(index);
}
keepProcessAliveLocked(record.pid);
if (mToastQueue.size() > 0) {
record = mToastQueue.get(0);
} else {
record = null;
}
}
}
}
···private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
{
Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY :
SHORT_DELAY);
mHandler.removeCallbacksAndMessages(r);
mHandler.sendMessageDelayed(m, delay);
}

Guess you like

Origin blog.csdn.net/yzwfeng/article/details/129744283