bug 突然报了SharedPreferences空指针,以前没遇见过

    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    ... 3 more
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.SharedPreferences android.content.Context.getSharedPreferences(java.lang.String, int)' on a null object reference
  1. N个进程,N个独立的虚拟机,Application被N次初使化
  2. 处理时应该在Application中分进程初始化数据

多进程的不足与缺点

1.数据共享问题
a. 由于处于不同的进程导致了数据无法共享内容,无论是static变量还是单例模式的实现。
b.SharedPreferences 还没有增加对多进程的支持。
c.跨进程共享数据可以通过Intent,Messenger,AIDL等。

2. SQLite容易被锁

a.由于每个进程可能会使用各自的SQLOpenHelper实例,如果两个进程同时对数据库操作,则会发生SQLiteDatabaseLockedException等异常。
解决方法:可以使用ContentProvider来实现或者使用其他存储方式。


3. 不必要的初始化

多进程之后,每个进程在创建的时候,都会执行自己的Application.onCreate方法。
通常情况下,onCreate中包含了我们很多业务相关的初始化,更重要的这其中没有做按照进程按需初始化,即每个进程都会执行全部的初始化。
按需初始化需要根据当前进程名称,进行最小需要的业务初始化。
按需初始化可以选择简单的if else判断,也可以结合工厂模式

结论

所以判断该空指针是由于多进程导致的在application中初始化了多次,从而当非主进程被销毁后,其中的context也随之被销毁了或者多进程调用SharedPreferences

解决方案

android应用在被启动时,对应的进程的进程名一般就是包名。android应用一般是运行在自己的进程中,除非通过AndroidManifest.xml中application定义中通过android:process字段指定运行在其他进程中(这种机制有特殊限定条件)。

判断当前进程是否是 APP 默认进程,只在主进程中进行初始化操作, APP 默认进程名就是包名。

//getApplicationContext().getPackageName()
//小心修改application定义中通过android:process的特殊情况,一般直接写字符串就够用了
private final static String PROCESS_NAME = "com.xx.yy.ccc";  


/** 
     * 判断是不是UI主进程,因为有些东西只能在UI主进程初始化 
     */  
    public static boolean isAppMainProcess() {  
        try {  
            int pid = android.os.Process.myPid();  
            String process = getAppNameByPID(MyApplication.getApplication(), pid);  
            if (TextUtils.isEmpty(process)) {  
                //第一次创建,系统中还不存在该process,所以一定是主进程
                return true;  
            } else if (PROCESS_NAME.equalsIgnoreCase(process)) {  
                return true;  
            } else {  
                return false;  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
            return true;  
        }  
    }  

    /** 
     * 根据Pid得到进程名 
     */  
    public static String getAppNameByPID(Context context, int pid) {  
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);  
        for (android.app.ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {  
            if (processInfo.pid == pid) {  
                //主进程的pid是否和当前的pid相同,若相同,则对应的包名就是app的包名
                return processInfo.processName;  
            }  
        }  
        return "";  
    }  

参考

http://www.jb51.net/article/104173.htm
http://blog.csdn.net/wei1583812/article/details/53395234
http://blog.csdn.net/renkangker/article/details/46888885
http://blog.csdn.net/zhanglianyu00/article/details/51793857

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值