@OptIn(markerClass = ExperimentalBadgeUtils.class)
    public void setBadge(@Nullable final View view, @Nullable final BadgeDrawable badge) {
        if (view == null) {
            return;
        }

        synchronized (mutex) {

            //check if there's an existing badge on the view
            final BadgeDrawable oldBadge = badgeMap.remove(view);
            if (badge != null) {
                badgeMap.put(view, badge);
            }

            if (oldBadge == badge) {
                return;
            }

            if (oldBadge == null) {
                //first time a badge is assigned to this view --> add view listeners for later updates
                ViewUtils.addDetachListener(view, v -> {
                    final BadgeDrawable bd;
                    synchronized (mutex) {
                        bd = badgeMap.remove(v);
                    }
                    if (bd != null) {
                        view.getOverlay().remove(bd);
                    }
                });
                ViewUtils.runOnViewMeasured(view, v -> {
                    final BadgeDrawable b;
                    synchronized (mutex) {
                        b = badgeMap.get(v);
                    }
                    if (b != null && view.isAttachedToWindow() && view.getParent() instanceof ViewGroup) {
                        BadgeUtils.setBadgeDrawableBounds(b, view, null);
                    }
                    return true;
                });
            }

            //remove old badge drawable, add new badge drawable as necessary
            if (oldBadge != null) {
                view.getOverlay().remove(oldBadge);
            }
            if (badge != null) {
                view.getOverlay().add(badge);
            }

            //trigger re-layout so badge is applied
            view.post(view::requestLayout);
        }
    }
sets/replaces a badge on a view. Passing a null-badge will cause any existing badge to be removed from view
main/src/main/java/cgeo/geocaching/ui/BadgeManager.java