调用SkinManager单例getColor方法触发空指针异常原因排查

SkinManager调用getColor触发NullPointerException排查
崩溃日志
Caused by: java.lang.NullPointerException: at com.manager.loader.SkinManager.getColor (SkinManager.java:28) at base.util.ui.titlebar.BaseTitlebarFragmentActivity.getImmersiveColor (BaseTitlebarFragmentActivity.java:6) at base.util.ui.titlebar.BaseTitlebarFragmentActivity.onCreate (BaseTitlebarFragmentActivity.java)
关联代码片段
BaseTitlebarFragmentActivity 代码
public abstract class BaseTitlebarFragmentActivity extends FragmentActivity { public void onCreate(Bundle savedInstanceState) { setImmersive(getImmersiveColor()); super.onCreate(savedInstanceState); } protected int getImmersiveColor(){ return SkinManager.getInstance().getColor(R.color.v8_common_title_bg); } }
SkinManager 核心代码
public class SkinManager implements ISkinLoader { private static final Object synchronizedLock = new Object(); private static SkinManager instance; private Context context; private Resources mResources; private boolean isDefaultSkin; private SkinManager() { } public static SkinManager getInstance() { if (instance == null) { synchronized (synchronizedLock) { if (instance == null){ instance = new SkinManager(); } } } return instance; } public void init(Context context) { this.context = context.getApplicationContext(); // 其余初始化逻辑 } public int getColor(int resId){ int originColor; if(mResources == null || isDefaultSkin){ try { originColor = context.getResources().getColor(resId); return originColor; } catch (Exception e) { // 空实现,吞掉所有异常 } } int trueColor = 0; try{ trueColor = mResources.getColor(resId); }catch(Exception e){ originColor = context.getResources().getColor(resId); trueColor = originColor; } return trueColor; } }
Application 初始化代码
public class App extends BaseApplication { public void onCreate() { super.onCreate(); initSkins(); } private void initSkins() { AttrFactory.addSupportAttr("iiv_background_color", new IconicsImageViewBgColorAttr()); AttrFactory.addSupportAttr("iiv_color", new IconicsImageViewColorAttr()); AttrFactory.addSupportAttr("matProg_barColor", new ProgressWheelBarColorAttr()); AttrFactory.addSupportAttr("progressDrawable", new ProgressBarDrawableAttr()); AttrFactory.addSupportAttr("indeterminateDrawable", new ProgressBar2DrawableAttr()); AttrFactory.addSupportAttr("button", new CheckBoxButtonDrawableAttr()); SkinManager.getInstance().init(this); SkinManager.getInstance().setUpSkinFile(); if (!ProcessManager.isMainProcess(getContext())) { SkinManager.getInstance().registerProcessSkinLoadReceiver(); } } }
根因分析
崩溃直接原因是getColor方法中调用了null对象的方法,结合代码逻辑具体触发路径按概率排序如下:
- 单例多线程安全缺陷:双检锁实现的单例没有给
instance加volatile关键字修饰,JVM指令重排序会导致其他线程拿到半初始化的实例——实例对象已经分配内存地址赋值给instance,但context、mResources等成员变量还没完成赋值,此时调用getColor就会触发空指针。 - Activity生命周期顺序错误:
BaseTitlebarFragmentActivity的onCreate方法中,先执行了setImmersive(getImmersiveColor())业务逻辑,后调用super.onCreate(savedInstanceState),部分ROM的冷启动/进程重建场景下,会出现Activity启动和Application初始化时序错位,调用getColor时SkinManager还没执行init方法,成员变量都是null。 - 空catch块吞异常导致错误扩散:第一个if分支中如果
context为null,调用context.getResources()抛出的NPE会被空catch直接吞掉,代码不会中断,会继续向下执行到mResources.getColor(resId)行,此时mResources也为null,就会在这行抛出崩溃日志中记录的NPE,反而掩盖了最初的异常点。 - 多进程逻辑错误:Android每个进程有独立的虚拟机,单例对象不跨进程共享。当前代码中仅对非主进程注册换肤广播,逻辑明显写反,非主进程场景下SkinManager很可能初始化不全。
修复方案
- 修正Activity生命周期调用顺序,
onCreate必须第一行先调用super.onCreate,再执行业务逻辑:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setImmersive(getImmersiveColor()); }
- 修复双检锁单例的线程安全问题,给静态实例加
volatile修饰禁止指令重排序:
private static volatile SkinManager instance;
- 移除空catch块,在
getColor方法入口增加兜底校验,避免初始化未完成时触发NPE:
public int getColor(int resId){ // 初始化未完成时走全局默认兜底 if (context == null) { return App.getInstance().getResources().getColor(resId); } if(mResources == null || isDefaultSkin){ return context.getResources().getColor(resId); } try{ return mResources.getColor(resId); }catch(Exception e){ return context.getResources().getColor(resId); } }
- 修正多进程判断逻辑,确保所有进程下SkinManager都完成初始化,换肤广播注册逻辑符合业务预期。
- 如果存在第三方SDK提前启动组件的场景,可以将SkinManager的初始化提前到ContentProvider中执行(执行时机早于Application onCreate),避免时序问题。
内容的提问来源于stack exchange,提问作者thecr0w
相关产品推荐
相关产品推荐

