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

原始boolean属性赋值触发NullPointerException原因排查

问题描述

正在修复一款已发布至Google Play商店应用的崩溃故障,从Google Play控制台获取的崩溃堆栈如下:

java.lang.NullPointerException: 
  at com.myApp.Advertising.InterstitialAdsRunCallback.setViewed (InterstitialAdsRunCallback.java:11)
  at com.myApp.AndroidLauncher$2.onInterstitialAdClosed (AndroidLauncher.java:65)
  at com.ironsource.mediationsdk.A$4.run (A.java:7)
  at android.os.Handler.handleCallback (Handler.java:938)
  at android.os.Handler.dispatchMessage (Handler.java:99)
  at android.os.Looper.loop (Looper.java:223)
  at android.app.ActivityThread.main (ActivityThread.java:7888)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:981)

堆栈最初定位到InterstitialAdsRunCallback类第11行的setViewed方法,该类源码如下:

package com.myApp.Advertising;

public abstract class InterstitialAdsRunCallback implements Runnable {
    boolean viewed;

    public boolean viewedAd() {
        return viewed;
    }

    public void setViewed(boolean viewed) {
        this.viewed = viewed; // line 11
    }
}

setViewed的调用逻辑位于IronSource插屏广告关闭回调中,对应代码如下:

public void onInterstitialAdClosed() {
    InterstitialAdsRunCallback adRunnable = showInterstitialAdRunnable.getAdRunnable();
    adRunnable.setViewed(true); // line 65
    adRunnable.run();
    IronSource.loadInterstitial();
}

从发布的AAB安装包反编译得到InterstitialAdsRunCallback的smali代码,确认viewed字段为原始boolean类型(smali中标记为Z类型),反编译片段如下:

.class public abstract Lcom/myApp/Advertising/InterstitialAdsRunCallback;
.super Ljava/lang/Object;
.source "InterstitialAdsRunCallback.java"

# interfaces
.implements Ljava/lang/Runnable;


# instance fields
.field public viewed:Z


# direct methods
.method public constructor <init>()V
    .registers 1

    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

按照Java基础语法,原始类型boolean的属性赋值操作不可能触发NullPointerException,目前未定位问题根因,需要明确异常触发原因和排查方向。

根因分析

你被release构建的行号映射错位误导了,这个NPE根本不是setViewed方法内部的赋值操作抛的:

  1. setViewed是仅包含一行赋值逻辑的简单setter,R8(release构建默认开启的代码优化器)会直接把这个方法内联到调用位置,不会保留单独的方法调用栈帧。
  2. 如果构建时生成的mapping映射文件和Google Play控制台的去混淆逻辑匹配有偏差,就会把调用处的NPE错误标记到原setter方法的行号上。
  3. 真正的异常原因是:showInterstitialAdRunnable.getAdRunnable()返回了null,你在null对象上调用setViewed方法触发了NPE。

这个问题本质是多线程竞态导致的:IronSource的广告关闭回调是在SDK自己的Handler线程触发(从堆栈可以看到回调执行在IronSource的A$4 Runnable中),和你主线程维护showInterstitialAdRunnable的逻辑存在时序差——比如广告展示结束后主线程提前清空了adRunnable引用,SDK的关闭回调晚几毫秒触发,就会拿到null值。

排查与修复方向
  • 找到对应版本构建产物中的mapping.txt文件,手动对崩溃堆栈做重新去混淆,可验证实际抛异常的位置就是调用setViewed的那一行,而非setViewed方法内部。
  • 检查showInterstitialAdRunnable的全生命周期逻辑,确认adRunnable的赋值、清空时机,补上多线程访问的同步处理,避免竞态。
  • 临时兼容修复直接加空判断即可,避免崩溃:
public void onInterstitialAdClosed() {
    InterstitialAdsRunCallback adRunnable = showInterstitialAdRunnable.getAdRunnable();
    if (adRunnable != null) {
        adRunnable.setViewed(true);
        adRunnable.run();
    }
    IronSource.loadInterstitial();
}
  • 低概率校验项:补全反编译smali中setViewed方法的片段,确认release包中该方法没有被注入恶意代码、字段引用没有错乱,这个场景出现概率不足1%。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:45:36