Android 9启动SplashActivity崩溃:ProviderInstaller失败后Application单例为空
Android 9三星设备启动崩溃排查与修复
问题背景
作为后端开发者,我Android相关知识有限,正在排查某应用启动崩溃问题:仅部分三星Android 9设备上,应用启动SplashActivity后立即崩溃。
崩溃日志
Fatal Exception: java.lang.RuntimeException Unable to start activity ComponentInfo{Sample.Sample.production/Sample.Sample.activity.entry.SplashActivity}: java.lang.NullPointerException: Attempt to read from field '...SampleApplication...' on a null object reference Caused by java.lang.NullPointerException at Sample.Sample.SampleApplication.getApplicationComponent(SampleApplication.java:25) at Sample.Sample.activity.entry.SplashActivity.onCreate(SplashActivity.kt:48)
相关代码
SampleBaseApplication.java
@Override public void onCreate() { initTimber(); if (initBefore()) { return; } Sin.ce(this); super.onCreate(); initInject(); }
initBefore()方法
protected boolean initBefore() { try { ProviderInstaller.installIfNeeded(this); return false; } catch (GooglePlayServicesRepairableException e) { GoogleApiAvailability.getInstance().showErrorNotification(this, e.getConnectionStatusCode()); } catch (GooglePlayServicesNotAvailableException e) { Timber.e(e, "cannot execute providerInstaller"); } return true; }
SplashActivity.kt
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Sin.gle().applicationComponent.injectActivity(this) setContentView(binding.root) }
技术问询解答
1. 如何正确修复该启动崩溃问题?
核心原因是:当initBefore()返回true时(即ProviderInstaller执行失败的场景),Sin.ce(this)和initInject()都不会执行,导致Sin类中没有持有Application实例,后续SplashActivity调用Sin.gle().applicationComponent时触发空指针异常。
推荐两种修复方案,选其一即可:
- 方案一:优先初始化核心依赖
把Sin.ce(this)移到initBefore()之前执行,同时修改initBefore()让它始终返回false,不阻断后续初始化:@Override public void onCreate() { initTimber(); Sin.ce(this); // 优先初始化核心实例 super.onCreate(); initBefore(); // 不再用返回值控制流程 initInject(); }protected void initBefore() { // 修改返回值类型为void try { ProviderInstaller.installIfNeeded(this); } catch (GooglePlayServicesRepairableException e) { GoogleApiAvailability.getInstance().showErrorNotification(this, e.getConnectionStatusCode()); } catch (GooglePlayServicesNotAvailableException e) { Timber.e(e, "cannot execute providerInstaller"); } // 不再返回true阻断流程 } - 方案二:补全异常分支的初始化逻辑
保留原有顺序,但在initBefore()返回true的分支里,补全核心初始化操作:
这种方式避免调整整体顺序,但存在代码重复,优先推荐方案一。@Override public void onCreate() { initTimber(); if (initBefore()) { Sin.ce(this); super.onCreate(); initInject(); return; } Sin.ce(this); super.onCreate(); initInject(); }
2. 为何该问题仅出现在Android 9/部分三星设备上?
主要有两点原因:
- Android 9的Google服务校验逻辑变化:Android 9(API 28)对Google Play服务的有效性校验更严格,部分三星设备的Google Play服务版本老旧、未安装或被禁用,导致
ProviderInstaller.installIfNeeded()抛出异常,触发initBefore()返回true的分支。 - 三星定制ROM的特殊处理:三星在Android 9的ROM中对Google服务的集成有定制化限制,比如部分机型默认限制Google Play服务后台权限,或预装的服务版本存在兼容性问题,导致ProviderInstaller执行失败的概率远高于其他设备。
3. 是否应将Sin.ce(this)移至initBefore()之前,还是ProviderInstaller失败不应阻止应用初始化?
推荐同时做两件事:把Sin.ce(this)移至initBefore()之前,且让ProviderInstaller失败不阻止应用初始化:
Sin.ce(this)是持有Application实例的核心逻辑,属于应用启动的基础依赖,必须优先完成,否则所有依赖Application的操作都会触发空指针。- ProviderInstaller的作用是更新安全提供程序,属于可选优化项,而非应用启动的必要条件。即使执行失败,应用仍应正常启动,后续涉及安全加密的功能出现问题时,再提示用户修复Google Play服务即可,不能阻断启动流程。
内容的提问来源于stack exchange,提问作者samsamsamsmasma
相关产品推荐
相关产品推荐

