Tencent/QMUI_Android · error · IllegalAccessError

don't call #onEnterAnimationStart() directly

Error message

don't call #onEnterAnimationStart() directly

What it means

QMUIFragment.onEnterAnimationStart() is a lifecycle callback invoked by the framework when the fragment's enter animation begins. It uses a mCalled flag so that invoking it manually is detected; a second/direct call throws IllegalAccessError because the enter-animation status (mEnterAnimationStatus, isInEnterAnimationLiveData) would be corrupted by duplicate invocation.

Source

Thrown at arch/src/main/java/com/qmuiteam/qmui/arch/QMUIFragment.java:1395

    public void runAfterResumed(Runnable runnable) {
        Utils.assertInMainThread();
        if (isResumed()) {
            runnable.run();
        } else {
            if (mPostResumeRunnableList == null) {
                mPostResumeRunnableList = new ArrayList<>(4);
            }
            mPostResumeRunnableList.add(runnable);
        }
    }

    /**
     * may not be call.
     * @param animation
     */
    protected void onEnterAnimationStart(@Nullable Animator animation) {
        if (mCalled) {
            throw new IllegalAccessError("don't call #onEnterAnimationStart() directly");
        }
        mCalled = true;
        mEnterAnimationStatus = ANIMATION_ENTER_STATUS_STARTED;
        isInEnterAnimationLiveData.setValue(true);
    }

    /**
     * may not be call.
     * @param animation
     */
    protected void onEnterAnimationEnd(@Nullable Animator animation) {
        if (mCalled) {
            throw new IllegalAccessError("don't call #onEnterAnimationEnd() directly");
        }
        mCalled = true;
        mEnterAnimationStatus = ANIMATION_ENTER_STATUS_END;
        isInEnterAnimationLiveData.setValue(false);
        notifyDelayRenderRunnableList();

View on GitHub (pinned to 026e7d4866)

Solutions

  1. Remove any direct call to onEnterAnimationStart(); let QMUIFragment's internal animation dispatch call it.
  2. If you need to hook the enter animation, override onEnterAnimationStart() in your fragment subclass and call super, instead of invoking it externally.
  3. Trigger animation-driven behavior via the public fragment transition APIs (e.g. startFragment/postAnimateShow) rather than the callback.
  4. For testing, verify the callback fired by observing isInEnterAnimationLiveData instead of calling it.

Example fix

// before
fragment.onEnterAnimationStart(animator);
// after
@Override
protected void onEnterAnimationStart(@Nullable Animator animation) {
    super.onEnterAnimationStart(animation);
    // custom logic here
}
Defensive patterns

Strategy: validation

Validate before calling

if (fragment instanceof QMUIFragment) {
    // never call onEnterAnimationStart directly; rely on framework dispatch
}

Type guard

boolean isFrameworkLifecycleHook(Method m) {
    return m != null && java.lang.reflect.Modifier.isProtected(m.getModifiers())
        && m.getName().startsWith("onEnterAnimation");
}

Prevention

When it happens

Trigger: Calling fragment.onEnterAnimationStart(animator) directly from app code, or invoking it twice (the mCalled flag is not reset between calls in the visible region), or subclass code invoking super/onEnterAnimationStart outside the framework dispatch path.

Common situations: Developers trying to manually trigger enter-animation behavior, custom animation orchestration that re-fires the callback, or reflection-based testing that calls protected lifecycle hooks directly.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Tencent/QMUI_Android@026e7d4866 (2026-09-06). Data as JSON: /api/errors/302e3996e19fb4c3. Report an issue: GitHub.