SuperNotCalledException Activity

2022-08-16  本文已影响0人  未子涵

问题

线上异常:

android.util.SuperNotCalledException: Activity {com.xxx.app/com.xxx.TestActivity} did not call through to super.onCreate()
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4037)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4247)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2613)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8668)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)

分析

看起来是派生的 Activity 中没有调用超类的 onCreate() ,也就是派生类中没有 super.onCreate() 导致的问题。追一下代码:

搜索“did not call through to super.onCreate()”:

// ActivityThread.java
/**  Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    try {
        ...
        if (activity != null) {
            ...
            // 显示的将mCalled设置为false
            activity.mCalled = false;
            // 若要不抛出下面的‘SuperNotCalledException’,只可能是callActivityOnCreate过程中对mCalled赋值为true了
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            // 检查mCalled,false的情况下就会抛出此异常
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }
            r.activity = activity;
            mLastReportedWindowingMode.put(activity.getActivityToken(),
                    config.windowConfiguration.getWindowingMode());
        }
        ...

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to start activity " + component
                + ": " + e.toString(), e);
        }
    }
    return activity;
}

可以看出,SuperNotCalledException 正是在 performLaunchActivity 中抛出的,而这与错误堆栈完全符合。至于从 ZygoteInit.main 到 ActivityThread.performLaunchActivity 的启动过程这里不做详细分析,我们直接从 performLaunchActivity 之后的流程分析。

既然我们已经分析出了若要正常启动Activity,就一定要在 callActivityOnCreate 过程中为 mCalled 赋值 true,那我们就继续往下追踪:

// Instrumentation.java
/**
 * Perform calling of an activity's {@link Activity#onCreate}
 * method.  The default implementation simply calls through to that method.
 *
 * @param activity The activity being created.
 * @param icicle The previously frozen state (or null) to pass through to onCreate().
 */
public void callActivityOnCreate(Activity activity, Bundle icicle) {
    // 分别查看以下3个方法,得出对 mCalled 的赋值操作是在 activity.performCreate 过程中
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}
final void performCreate(Bundle icicle) {
    performCreate(icicle, null);
}

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
    if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performCreate:"
                + mComponent.getClassName());
    }
    dispatchActivityPreCreated(icicle);
    mCanEnterPictureInPicture = true;
    // initialize mIsInMultiWindowMode and mIsInPictureInPictureMode before onCreate
    final int windowingMode = getResources().getConfiguration().windowConfiguration
            .getWindowingMode();
    mIsInMultiWindowMode = inMultiWindowMode(windowingMode);
    mIsInPictureInPictureMode = windowingMode == WINDOWING_MODE_PINNED;
    restoreHasCurrentPermissionRequest(icicle);
    if (persistentState != null) {
        // 双参数的 onCreate 实际上也是调用的 单参数 onCreate
        onCreate(icicle, persistentState);
    } else {
        onCreate(icicle);
    }
    EventLogTags.writeWmOnCreateCalled(mIdent, getComponentName().getClassName(),
            "performCreate");
    mActivityTransitionState.readState(icicle);

    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
            com.android.internal.R.styleable.Window_windowNoDisplay, false);
    mFragments.dispatchActivityCreated();
    mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
    dispatchActivityPostCreated(icicle);
    Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}

public void onCreate(@Nullable Bundle savedInstanceState,
        @Nullable PersistableBundle persistentState) {
    onCreate(savedInstanceState);
}

/**
 * Called when the activity is starting.  This is where most initialization
 * should go: calling {@link #setContentView(int)} to inflate the
 * activity's UI, using {@link #findViewById} to programmatically interact
 * with widgets in the UI, calling
 * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
 * cursors for data being displayed, etc.
 *
 * <p>You can call {@link #finish} from within this function, in
 * which case onDestroy() will be immediately called after {@link #onCreate} without any of the
 * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc)
 * executing.
 *
 * <p><em>Derived classes must call through to the super class's
 * implementation of this method.  If they do not, an exception will be
 * thrown.</em></p>
 *
 * @param savedInstanceState If the activity is being re-initialized after
 *     previously being shut down then this Bundle contains the data it most
 *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
 *
 * @see #onStart
 * @see #onSaveInstanceState
 * @see #onRestoreInstanceState
 * @see #onPostCreate
 */
@MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);

    if (mLastNonConfigurationInstances != null) {
        mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
    }
    if (mActivityInfo.parentActivityName != null) {
        if (mActionBar == null) {
            mEnableDefaultActionBarUp = true;
        } else {
            mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
        }
    }
    if (savedInstanceState != null) {
        mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED, false);
        mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID,
                View.LAST_APP_AUTOFILL_ID);

        if (mAutoFillResetNeeded) {
            getAutofillManager().onCreate(savedInstanceState);
        }

        Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
        mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.fragments : null);
    }
    mFragments.dispatchCreate();
    dispatchActivityCreated(savedInstanceState);
    if (mVoiceInteractor != null) {
        mVoiceInteractor.attachActivity(this);
    }
    mRestoredFromBundle = savedInstanceState != null;
    // 这里执行完 Activity 的 onCreate 后,会修改 mCalled
    mCalled = true;
}

至此,就确认了这个异常的触发链,不仅从整个代码的执行流程上能得到验证,从 onCreate 的另外两个地方也能看到端倪:

// CallSuper.java
/**
 * Denotes that any overriding methods should invoke this method as well.
 * <p>
 * Example:
 *
 * <pre>
 * <code>
 *  &#64;CallSuper
 *  public abstract void onFocusLost();
 * </code>
 * </pre>
 *
 * @memberDoc If you override this method you <em>must</em> call through to the
 *            superclass implementation.
 * @hide
 */
@Retention(SOURCE)
@Target({METHOD})
public @interface CallSuper {
}
 * <p><em>Derived classes must call through to the super class's
 * <p><em>Derived classes must call through to the super class's
 * implementation of this method.  If they do not, an exception will be
 * thrown.</em></p>

结论

检查相应的 Activity ,确保 onCreate 中调用了 super.onCreate() 。如果不调用,IDE 会有提示,但就算不按照提示做,编译是能通过的,只是运行时,肯定就会抛出异常了。

上一篇下一篇

猜你喜欢

热点阅读