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

Android静态对象成员丢失:appctx为何偶现空指针异常?

问题分析:单例类中appctx为空导致GoogleSignIn初始化异常

简化代码

public class MyTest { 
    static MyTest instance = null; 
    Context appctx = null;
    public static MyTest Instance() {
        if (null == instance) {
            instance = new MyTest();
        }
        return instance;
    }
    // call from Application onCreate  MyTest.Instance().onAppCreate(this);
    public void onAppCreate(Context context) {
        appctx = context;
    }
    // call from Activity onCreate MyTest.Instance().onActivityCreate(this);
    public void onActivityCreate(Activity act) {
        if (null == appctx) {
            Log.d("error", "null app");
        }
        //...
        //client = GoogleSignIn.getClient(appctx, gso);
    }
}

异常信息

Exception java.lang.RuntimeException:
      at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3851)
      at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:4027)
      at android.app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:85)
      at android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
      at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
      at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2336)
      at android.os.Handler.dispatchMessage (Handler.java:106)
      at android.os.Looper.loop (Looper.java:247)
      at android.app.ActivityThread.main (ActivityThread.java:8676)
      at java.lang.reflect.Method.invoke
      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
      at com.google.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)
    Caused by java.lang.NullPointerException: Null context is not permitted.
      at com.google.android.gms.common.internal.Preconditions.checkNotNull (com.google.android.gms:play-services-basement@@18.3.0:2)
      at com.google.android.gms.common.api.GoogleApi.<init> (com.google.android.gms:play-services-base@@18.4.0:4)
      at com.google.android.gms.common.api.GoogleApi.<init> (com.google.android.gms:play-services-base@@18.4.0:21)
      at com.google.android.gms.auth.api.signin.GoogleSignInClient.<init> (com.google.android.gms:play-services-auth@@21.0.0:2)
      at com.google.android.gms.auth.api.signin.GoogleSignIn.getClient (com.google.android.gms:play-services-auth@@21.0.0:2)

原因分析

1. 静态instance被GC回收的可能性为0

instance是静态成员变量,属于类本身,只要类没有被ClassLoader卸载(Android常规开发场景下几乎不会发生类卸载),静态变量就会一直存在于方法区,不会被GC回收。因此这不是导致appctx为空的原因。

2. 真正的可能原因

  • 线程不安全的单例实现:当前的Instance()方法没有同步机制,多线程并发调用时可能创建多个MyTest实例。比如线程A进入if (null == instance)还未创建实例,线程B也进入该分支并创建实例、调用onAppCreate赋值appctx;随后线程A继续执行,又创建了一个新的MyTest实例,这个新实例的appctx未被赋值,后续调用onActivityCreate时就会出现空指针。

  • 初始化顺序异常:虽然onAppCreate在Application的onCreate中调用,但存在极端场景:比如冷启动时系统调度异常,或者第三方库提前触发Activity启动,导致Activity的onCreate先于Application的onCreate执行完成,此时调用onActivityCreate时appctx还未被赋值。

  • 进程重启后的状态异常:当App因内存不足被系统杀死,用户重新打开时,系统会重启进程并恢复Activity栈。如果此时Application的onCreate执行过程中出现异常,导致onAppCreate未完成赋值,或者系统恢复逻辑异常,都会导致appctx为空。

修复建议

  • 实现线程安全的单例:采用双重检查锁(DCL)确保单例唯一,同时私有化构造方法防止外部创建实例:
public class MyTest { 
    private static volatile MyTest instance = null; 
    private Context appctx = null;

    private MyTest() {} // 私有构造,禁止外部实例化

    public static MyTest Instance() {
        if (null == instance) {
            synchronized (MyTest.class) {
                if (null == instance) {
                    instance = new MyTest();
                }
            }
        }
        return instance;
    }
}
  • 确保appctx正确初始化:在onAppCreate中使用Application的Context避免内存泄漏,同时增加兜底逻辑:
public void onAppCreate(Context context) {
    if (appctx == null) {
        appctx = context.getApplicationContext(); // 持有Application Context,避免内存泄漏
    }
}

public void onActivityCreate(Activity act) {
    if (null == appctx) {
        Log.d("error", "null app, use fallback context");
        appctx = act.getApplicationContext(); // 兜底获取Application Context
    }
    // 后续GoogleSignIn初始化逻辑
}
  • 保证初始化顺序:将MyTest.Instance().onAppCreate(this)放在Application onCreate方法的最开始执行,避免被其他逻辑阻塞或跳过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:27:25