You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 13调用Activity.startActivities时AOSP空指针崩溃求助

Android 13下启动Activity栈时的NullPointerException排查

崩溃现象

  • 仅出现于Android 13系统
  • 高发设备:三星Galaxy S23+/S22+/S22 Ultra/S21 FE 5G;OPPO Reno5、小米12、小米11T各出现1次
  • 触发场景:仅在通过SplashActivity启动ListActivity -> DetailsActivity任务栈时崩溃

堆栈信息

Non-fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'com.android.server.wm.ActivityRecord com.android.server.wm.WindowContainer.getActivity(java.util.function.Predicate)' on a null object reference
android.os.Parcel.createExceptionOrNull (Parcel.java:3029)
android.os.Parcel.createException (Parcel.java:3007)
android.os.Parcel.readException (Parcel.java:2990)
android.os.Parcel.readException (Parcel.java:2932)
android.app.IActivityTaskManager$Stub$Proxy.startActivities (IActivityTaskManager.java:2816)
android.app.Instrumentation.execStartActivitiesAsUser (Instrumentation.java:1876)
android.app.Instrumentation.execStartActivities (Instrumentation.java:1823)
android.app.Activity.startActivities (Activity.java:6096)
android.app.Activity.startActivities (Activity.java:6069)
.SplashActivity.startMain (SplashActivity.java:149)

排查现状

怀疑崩溃源于自身实现(AOSP代码问题可能性低),尝试查阅AOSP中ActivityTaskManagerService.startActivities的实现,试图解析WindowContainer为空的原因,但代码导航困难、交叉引用失效,克隆仓库后仍未定位到相关逻辑,陷入瓶颈。

核心实现代码

SplashActivity简化逻辑

public final class SplashActivity {
    private boolean resumed;

    @Override
    protected void onStart() {
        super.onStart();
        fetchAsyncData(SplashActivity::onDataFetched);
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        resumed = true;
    }

    @Override
    protected void onPause() {
        super.onPause();
        resumed = false;
    }

    public void onDataFetched() {
        String res1, res2;
        // 解析深层链接或后台通知,填充res1、res2或置空
        // 非活跃状态下不启动Activity
        if (resumed) {
            if (res1 != null && res2 != null) {
                Intent intent = getIntent();
                Bundle extras = intent.getExtras();

                Intent listIntent = new Intent(this, ListActivity.class);
                // 转发原Intent的参数和标记
                listIntent.putExtras(extras != null ? extras : new Bundle());
                listIntent.addFlags(intent.getFlags());

                Intent detailsIntent = new Intent(this, DetailsActivity.class);
                detailsIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                detailsIntent.putExtra("res1", res1);
                detailsIntent.putExtra("res2", res2);

                startActivities(new Intent[]{listIntent, detailsIntent});
                finish();
            } else {
                // 启动其他Activity逻辑
            }
        }
    }
}

Manifest中Activity声明

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <application>
        <activity
            android:name=".SplashActivity"
            android:launchMode="singleInstance"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter android:autoVerify="true" tools:targetApi="m">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data
                    android:scheme="https"
                    android:host="example.com"
                    android:pathPattern="/res1/.*/res2/.*" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ListActivity"
            android:exported="true"
            android:launchMode="singleTop" />
        <activity
            android:name=".DetailsActivity"
            android:launchMode="singleTop"
            android:exported="true"
            android:parentActivityName=".ListActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ListActivity" />
        </activity>
    </application>
</manifest>

问题分析与解决方案建议

可能的问题根源

  1. 启动模式冲突:SplashActivity是singleInstance启动模式,属于独立任务栈,调用startActivities启动多Activity时,系统可能无法正确匹配任务栈,导致WindowContainer为空。
  2. Intent标记误用:DetailsActivity的Intent设置了FLAG_ACTIVITY_CLEAR_TOP,该标记会清除目标Activity之上的所有Activity,但在启动栈的场景下,会干扰系统对新任务栈的创建逻辑。
  3. 生命周期判断不可靠:自定义的resumed标记可能存在时序问题,异步数据返回时,Activity可能处于生命周期的过渡状态(如onPause执行中),此时调用startActivities会导致系统获取WindowContainer失败。

解决方案

  1. 调整启动模式:将SplashActivity的singleInstance改为singleTask,避免独立任务栈带来的启动冲突;或者在启动Intent中显式指定任务栈信息(通过TaskStackBuilder或Intent.setFlags(FLAG_ACTIVITY_NEW_TASK)配合任务栈属性)。
  2. 修正Intent标记:移除DetailsActivity的FLAG_ACTIVITY_CLEAR_TOP标记,依赖parentActivityName的导航关系来维护栈结构;若需要复用已存在的DetailsActivity,可单独在启动后通过onNewIntent处理参数。
  3. 优化生命周期判断:使用系统提供的isResumed()方法替代自定义的resumed标记,确保Activity完全处于前台活跃状态后再执行启动逻辑;或者将数据加载逻辑移至onPostResume中,避免异步回调的时序问题。
  4. 添加异常兜底:在调用startActivities的代码块外添加try-catch捕获NullPointerException,兜底处理(如降级启动单个ListActivity),避免影响用户体验。

内容的提问来源于stack exchange,提问作者Doc_1faux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 18:59:50