Tencent/QMUI_Android · error · RuntimeException

refreshView must be a instance of IRefreshView

Error message

refreshView must be a instance of IRefreshView

What it means

QMUIPullRefreshLayout.addRefreshView throws when the configured mRefreshView is not an instance of IRefreshView. The layout needs the refresh view to implement its refresh interaction contract (onRefreshStart, onRefreshComplete, etc.), so any arbitrary View is rejected.

Source

Thrown at qmui/src/main/java/com/qmuiteam/qmui/widget/pullRefreshLayout/QMUIPullRefreshLayout.java:266

    public boolean isRefreshing() {
        return mIsRefreshing;
    }

    /**
     * 覆盖该方法以实现自己的 RefreshView。
     *
     * @return 自定义的 RefreshView, 注意该 View 必须实现 {@link IRefreshView} 接口
     */
    protected View createRefreshView() {
        return new RefreshView(getContext());
    }

    private void addRefreshView() {
        if (mRefreshView == null) {
            mRefreshView = createRefreshView();
        }
        if (!(mRefreshView instanceof IRefreshView)) {
            throw new RuntimeException("refreshView must be a instance of IRefreshView");
        }
        mIRefreshView = (IRefreshView) mRefreshView;
        if (mRefreshView.getLayoutParams() == null) {
            mRefreshView.setLayoutParams(new LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        }
        addView(mRefreshView);
    }

    /**
     * 设置在下拉过程中 RefreshView 的偏移量
     */
    public void setRefreshOffsetCalculator(RefreshOffsetCalculator refreshOffsetCalculator) {
        mRefreshOffsetCalculator = refreshOffsetCalculator;
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {

View on GitHub (pinned to 026e7d4866)

Solutions

  1. Make the view passed to setRefreshView implement IRefreshView (and its required methods).
  2. Use the library's built-in refresh views (e.g. QMUITopDialog-style default or any bundled IRefreshView implementation).
  3. If wrapping an existing view, implement IRefreshView on the wrapper class you pass to setRefreshView.

Example fix

// before
refreshLayout.setRefreshView(new ProgressBar(context)); // not IRefreshView
// after
class MyRefreshView extends View implements IRefreshView { ... }
refreshLayout.setRefreshView(new MyRefreshView(context));
Defensive patterns

Strategy: type-guard

Validate before calling

View v = candidateRefreshView;
if (v instanceof IRefreshView) {
    refreshLayout.setRefreshView(v);
} else {
    throw new IllegalArgumentException("refresh view must implement IRefreshView");
}

Type guard

private static boolean isIRefreshView(View v) {
    return v instanceof IRefreshView;
}

Try / catch

try {
    refreshLayout.setRefreshView(candidate);
} catch (RuntimeException e) {
    Log.e(TAG, "custom refresh view must implement IRefreshView", e);
}

Prevention

When it happens

Trigger: Calling setRefreshView(someView) with a plain View or a custom view that does not implement com.qmuiteam.qmui.widget.pullRefreshLayout.IRefreshView, then triggering layout/refresh initialization.

Common situations: Setting a custom loading spinner View that implements the wrong (or no) refresh interface; migrating from another pull-to-refresh library whose view classes are not adapted; implementing IRefreshView but on a wrapper rather than the set view itself.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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