gyf-dev/ImmersionBar · error · IllegalArgumentException

Owner must be attached to a Window.

Error message

Owner must be attached to a Window.

What it means

BarConfig reads window/system-bar metrics, and requireWindow is a null-check guard on the Window passed to it. It throws IllegalArgumentException("Owner must be attached to a Window.") when the supplied Window reference is null, i.e. the owner (Activity/Dialog) has not finished attaching yet.

Solutions

  1. Defer BarConfig creation until the Activity window exists (after onCreate / in onResume or onViewCreated)
  2. Null-check activity.getWindow() before constructing BarConfig and skip/retry the measurement
  3. For dialogs, run config setup in onAttachedToWindow or after show()

Example fix

// before
BarConfig config = new BarConfig(getActivity().getWindow()); // NPE-ish before attach
// after
Window w = getActivity() != null ? getActivity().getWindow() : null;
if (w != null) {
    BarConfig config = new BarConfig(w);
}
Defensive patterns

Strategy: validation

Validate before calling

if (activity != null && activity.getWindow() != null) { new BarConfig(activity.getWindow()); }

Type guard

Window safeWindow(Activity a) { return a == null ? null : a.getWindow(); }

Try / catch

try { config = new BarConfig(window); } catch (IllegalArgumentException e) { config = null; /* defer measurement */ }

Prevention

When it happens

Trigger: Constructing BarConfig with activity.getWindow() or dialog.getWindow() that returns null — typically before onCreate/onAttachedToWindow completes or after the window is destroyed.

Common situations: Measuring bar insets in Fragment.onCreate or a constructor instead of onViewCreated/onActivityCreated; querying config after activity finish/rotation teardown; a Dialog shown before it has a window.

Related errors


AI-assisted analysis of gyf-dev/ImmersionBar@8cac10cd83 (2026-09-08). Data as JSON: /api/errors/8393c043b614d8df. Report an issue: GitHub.

Appendix: source

Thrown at immersionbar/src/main/java/com/gyf/immersionbar/BarConfig.java:119

        Resources res = context.getResources();
        mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
        mSmallestWidthDp = getSmallestWidthDp(window);
        mStatusBarHeight = getStatusBarHeight(window);
        mStatusBarVisible = isStatusBarVisible(window);
        mActionBarHeight = getActionBarHeight(window);
        mNavigationBarVisible = navigationBarVisibleHint != null ? navigationBarVisibleHint : isNavigationBarVisible(window);
        mNavigationBarHeight = getNavigationBarHeight(window, mNavigationBarVisible);
        int navigationBarHeightIgnoringVisibility = getNavigationBarHeightIgnoringVisibility(window);
        mNavigationBarHeightIgnoringVisibility = navigationBarHeightIgnoringVisibility > 0 ? navigationBarHeightIgnoringVisibility : (mNavigationBarVisible ? mNavigationBarHeight : 0);
        mNavigationBarWidth = getNavigationBarWidth(window);
        mHasNavigationBar = (mNavigationBarHeight > 0);
        mNavigationAtBottom = computeNavigationAtBottom(window);
    }

    @NonNull
    private static Window requireWindow(Window window) {
        if (window == null) {
            throw new IllegalArgumentException("Owner must be attached to a Window.");
        }
        return window;
    }

    /**
     * 计算导航栏是否在底部。
     * android 11(API 30)起WindowInsets可用,优先用其实际方向判断(底部有inset即在底部,否则在侧边),
     * 比老的“手机横屏导航栏在侧边”启发式更准;insets不可用或低版本时回退到原启发式。
     *
     * @param window window
     * @return true表示导航栏在底部,false表示在侧边
     */
    private boolean computeNavigationAtBottom(Window window) {
        if (Build.VERSION.SDK_INT >= Version.R) {
            Insets navInsets = getNavigationBarInsets(window);
            if (navInsets != null && (navInsets.bottom > 0 || navInsets.left > 0 || navInsets.right > 0)) {
                return navInsets.bottom > 0;
            }

View on GitHub (pinned to 8cac10cd83)