为什么 Toast 在应用程序调用 onDestroy() 时仍然显示?

Why Toast keeps showing even when the app called onDestroy()?

假设我在 onCreate()

中有这段代码
   for (int i = 0; i < 20; i++) {
        Toast.makeText(MainActivity.this, "Toast "+i, Toast.LENGTH_SHORT).show();
    }

当我启动应用程序时,Toasts 开始弹出。

现在,当我按下后退按钮时(比方说在 Toast 5 之后)。 onDestroy() 被调用,应用程序被关闭。

但我仍然可以看到 Toast 弹出,直到达到 20 或我从内存中清除应用程序。

问题:

为什么我的代码 运行 在应用程序之外?

我已经给了我的activity的上下文,那么activity被销毁它不应该立即停止吗?

这里 context 不重要吗?

如果您link任何文档,将会很有帮助。

Toastclass中,Toast.makeText()是静态的method。当您调用此方法时,将创建一个新的 Toast 对象并将您传递的 Context 保存在其中,系统的默认布局用于创建一个 view 附加到您的 Toast 对象和重力也被设置为管理你的 toast 将在屏幕上显示的位置。

您的toast被系统服务显示。此服务维护要显示的 queuetoast messages,并使用其自己的 Thread 显示它们。当您在 toast object 上调用 show() 时,它会将您的 toast 排队到系统服务的消息队列中。因此,当您的 activity 在创建 20 toast 后被销毁时,系统服务已经开始运行并且它的 message queue 中有消息要显示。通过向后按 activity(销毁)系统无法断定您可能不打算显示剩余的 toast 消息。只有当您从内存中清除您的应用程序时,系统才能自信地推断它不再需要从您的应用程序中显示 toast message

有关更多信息,您可以查看 Toast class 的源代码。我为您提供了相关方法。顺便说一句,好问题

Implementation of Toast.makeText

 /**
 * Make a standard toast to display using the specified looper.
 * If looper is null, Looper.myLooper() is used.
 * @hide
 */
public static Toast makeText(@NonNull Context context, @Nullable Looper looper,
        @NonNull CharSequence text, @Duration int duration) {
    Toast result = new Toast(context, looper);

    LayoutInflater inflate = (LayoutInflater)
            context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
    TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
    tv.setText(text);

    result.mNextView = v;
    result.mDuration = duration;

    return result;
}

Creation of new Toast :

/**
 * Constructs an empty Toast object.  If looper is null, Looper.myLooper() is used.
 * @hide
 */
public Toast(@NonNull Context context, @Nullable Looper looper) {
    mContext = context;  // your passed `context` is saved.
    mTN = new TN(context.getPackageName(), looper);
    mTN.mY = context.getResources().getDimensionPixelSize(
            com.android.internal.R.dimen.toast_y_offset);
    mTN.mGravity = context.getResources().getInteger(
            com.android.internal.R.integer.config_toastDefaultGravity);
}

Implementation of show()

/**
 * Show the view for the specified duration.
 */
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;
    final int displayId = mContext.getDisplayId();

    try {
        service.enqueueToast(pkg, tn, mDuration, displayId);
    } catch (RemoteException e) {
        // Empty
    }
}