1. 程式人生 > >bug 突然報了SharedPreferences空指標,以前沒遇見過

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


N個程序,N個獨立的虛擬機器,Application被N次初使化
處理時應該在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