美文网首页
SuperNotCalledException Activity

SuperNotCalledException Activity

作者: 未子涵 | 来源:发表于2022-08-16 12:27 被阅读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 的另外两个地方也能看到端倪:

    • onCreate 的注解 @CallSuper:标记该方法,任何派生类若要重写该方法,则必须调用超类的方法,即 super.xxx()
    // 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 {
    }
    
    • onCreate 的注释也明确说明了
     * <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 会有提示,但就算不按照提示做,编译是能通过的,只是运行时,肯定就会抛出异常了。

    相关文章

      网友评论

          本文标题:SuperNotCalledException Activity

          本文链接:https://www.haomeiwen.com/subject/kyirgrtx.html