Android Toast 在 Toast 之上 - 顶部的 Toast 消失时,底部的仍然存在

Android Toast on top of Toast - bottom one remains when top one goes

我的应用程序通过调用

在很多地方创建了很多 toasts
Toast.makeText(getBaseContext(), "Blah", Toast.LENGTH_SHORT).show();

(好吧,我使用资源 ID 而不是字符串)。在我用过的 4 到 7 的每个 Android 版本上一切正常,但是对于 Android 8.1.0,如果在第一个 toast 消失之前弹出第二个 toast,则第一个 toast 会恢复当第二个溶解时。我的猜测是显示管理器正在记住 toast 下方的像素并在 toast 消失时恢复它们,但它不够聪明来处理一堆 toast 所以第二个 "remembers"首先,恢复它而不是底层 window 区域。

我可以使用一个 "makeToast" 包装器来解决这个问题,它每次都将 Toast 对象存储在一个静态变量中,并在 .show() 调用新的之前调用旧的 .cancel()一。这是最终的解决方案,还是有更好的方法?

private static Toast lastToast;
private static Context toastContext; // set in onCreate
public static void makeToast(int resId, int duration) {
    if (lastToast != null) lastToast.cancel();
    lastToast = Toast.makeText(toastContext, resId, duration);
    lastToast.show();
}

这为我修复了它 - 我用自己的 class 包装了 Toast,cancel() 是在 show() 调用新对象之前调用 show() 的最后一个对象。看起来像是一个巨大的 hack,但它确实完成了工作,只需要更改我应用程序其余部分中的 import android.widget.Toast 行。

package my.app.hacks;

import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;    

public class Toast extends android.widget.Toast {
    public static final int LENGTH_SHORT = android.widget.Toast.LENGTH_SHORT;
    public static final int LENGTH_LONG = android.widget.Toast.LENGTH_LONG;

    private static Toast lastShown;

    public Toast(Context context) {
        super(context);
    }

    public void show() {
        if (lastShown != null) lastShown.cancel();
        super.show();
        lastShown = this;
    }

    public static Toast makeText(Context context, CharSequence text, int duration) {
        //
        // this is almost copy-n-pasted from android.widget.Toast.makeText()
        //
        Toast result = new Toast(context);

        LayoutInflater inflate = (LayoutInflater)
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        // we can't directly access com.android.internal.R identifiers so use the public interface
        int layout = Resources.getSystem().getIdentifier("transient_notification", "layout", "android");
        View v = inflate.inflate(layout, null);
        int id = Resources.getSystem().getIdentifier("message", "id", "android");
        TextView tv = (TextView)v.findViewById(id);
        tv.setText(text);

        // the original code accesses private members here - again, we have to use the public interface
        result.setView(v);
        result.setDuration(duration);

        return result;
    }

    public static Toast makeText(Context context, int resId, int duration)
            throws Resources.NotFoundException {
        return makeText(context, context.getResources().getText(resId), duration);
    }

}