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

获取字符串资源主机名时为何抛出NullPointerException?

启动应用时getDefaultHostName()抛出NullPointerException排查方案

问题现象

启动应用初始化偏好设置时,调用getDefaultHostName()方法触发NullPointerException,导致应用启动失败。

报错堆栈

Process: com.elto.date, PID: 31344
java.lang.RuntimeException: 无法创建应用com.elto.date.lightDark.MyApp: java.lang.NullPointerException
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7109)
at android.app.ActivityThread.access$1600(ActivityThread.java:271)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2134)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:210)
at android.os.Looper.loop(Looper.java:299)
at android.app.ActivityThread.main(ActivityThread.java:8319)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1038)

Caused by: java.lang.NullPointerException
at com.elto.date.lightDark.MyApp.getDefaultHostName(MyApp.kt:240)
at com.elto.date.lightDark.MyApp.onCreate(MyApp.kt:141)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1212)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7103)
... 其余栈帧省略

代码问题分析

核心原因

在MyApp类中,你定义了一个私有变量sContext并直接初始化为null:

private val sContext: MyApp? = null

而getDefaultHostName()方法中使用!!强制解包这个null变量,直接触发空指针异常:

fun getDefaultHostName(): String {
    return sContext!!.resources
        .getString(if (isEmulator()) R.string.emulator_host_name else R.string.default_host_name)
}

冗余代码问题

实际上你的MyApp类的companion object中已经维护了一个instance变量,并且在onCreate()方法中已经赋值为当前应用实例:

override fun onCreate() {
    super<Application>.onCreate()
    instance = this
    // ... 其余代码
}

自己定义的sContext完全是冗余且未被正确初始化的变量。

修复方案

步骤1:移除冗余的sContext变量

删除MyApp类中定义的private val sContext: MyApp? = null。

步骤2:修改getDefaultHostName()方法

直接使用当前MyApp实例(this)或者companion object中的instance来获取资源:

fun getDefaultHostName(): String {
    return resources.getString(if (isEmulator()) R.string.emulator_host_name else R.string.default_host_name)
}

如果需要在静态场景调用,也可以用:

fun getDefaultHostName(): String {
    return instance.resources.getString(if (isEmulator()) R.string.emulator_host_name else R.string.default_host_name)
}

步骤3:修复getAppContext()方法

如果需要提供全局上下文获取方法,直接返回instance或者this:

fun getAppContext(): Context {
    return instance
}

或者非静态版本:

fun getAppContext(): Context {
    return this
}

修复后的偏好设置初始化代码

原有逻辑无需改动,因为getDefaultHostName()已经能正确获取资源:

val pref = PreferenceManager.getDefaultSharedPreferences(this)
if (TextUtils.isEmpty(pref.getString(Utils.PREFS_HOST_NAME, null))) {
    // 未找到偏好设置,保存默认值
    val editor = pref.edit()
    editor.putString(Utils.PREFS_HOST_NAME, getDefaultHostName())
    editor.putBoolean(Utils.PREFS_USE_TLS, getDefaultTLS())
    editor.apply()
}

额外建议

  • 避免使用!!强制解包可空变量,推荐用?.安全调用结合?:空合并运算符,降低空指针风险。
  • 全局上下文尽量通过Application的instance获取,不要额外定义冗余变量,减少维护成本和初始化错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:49:54