一、成員變量
//錯誤恢復(fù)策略相關(guān)
private static final EnumMap<MMKVRecoverStrategic, Integer> recoverIndex = new EnumMap(MMKVRecoverStrategic.class);
//MMKV日志輸出相關(guān)
private static final EnumMap<MMKVLogLevel, Integer> logLevel2Index;
private static final MMKVLogLevel[] index2LogLevel;
//存儲已經(jīng)打開的 MMKV 描述符集合
private static final Set<Long> checkedHandleSet;
//MMKV 文件存放根路徑
private static String rootDir;
//MMKV 進(jìn)程模式
public static final int SINGLE_PROCESS_MODE = 1;
public static final int MULTI_PROCESS_MODE = 2;
private static final int CONTEXT_MODE_MULTI_PROCESS = 4;
private static final int ASHMEM_MODE = 8;
//序列化相關(guān)的
private static final HashMap<String, Creator<?>> mCreators;
//處理日志重定向询枚、文件錯誤恢復(fù)策略
private static MMKVHandler gCallbackHandler;
private static boolean gWantLogReDirecting;
//內(nèi)容變更通知 主要是被其他進(jìn)程更新時有回調(diào)
private static MMKVContentChangeNotification gContentChangeNotify;
//MMKV描述符 主要用來讀寫文件用
private final long nativeHandle;
二螟炫、API接口
1.初始化MMKV
//傳入context的初始化函數(shù)折欠,log默認(rèn)是LevelInfo
public static String initialize(Context context) {
? ? String root = context.getFilesDir().getAbsolutePath() + "/mmkv";
? ? MMKVLogLevel logLevel = MMKVLogLevel.LevelInfo;
? ? return initialize((String)root, (MMKV.LibLoader)null, logLevel);
}
//傳入context 和 logLevel
public static String initialize(Context context, MMKVLogLevel logLevel) {
? ? String root = context.getFilesDir().getAbsolutePath() + "/mmkv";
? ? return initialize((String)root, (MMKV.LibLoader)null, logLevel);
}
//傳入context 和 loader
public static String initialize(Context context, MMKV.LibLoader loader) {
? ? String root = context.getFilesDir().getAbsolutePath() + "/mmkv";
? ? MMKVLogLevel logLevel = MMKVLogLevel.LevelInfo;
? ? return initialize(root, loader, logLevel);
}
// 傳入 context 固阁、loader/level
public static String initialize(Context context, MMKV.LibLoader loader, MMKVLogLevel logLevel) {
? ? String root = context.getFilesDir().getAbsolutePath() + "/mmkv";
? ? return initialize(root, loader, logLevel);
}
// 傳入路徑
public static String initialize(String rootDir) {
? ? MMKVLogLevel logLevel = MMKVLogLevel.LevelInfo;
? ? return initialize((String)rootDir, (MMKV.LibLoader)null, logLevel);
}
//傳入路徑和日志等級
public static String initialize(String rootDir, MMKVLogLevel logLevel) {
? ? return initialize((String)rootDir, (MMKV.LibLoader)null, logLevel);
}
//傳入路徑和loader
public static String initialize(String rootDir, MMKV.LibLoader loader) {
? ? MMKVLogLevel logLevel = MMKVLogLevel.LevelInfo;
? ? return initialize(rootDir, loader, logLevel);
}
//最后都調(diào)用的該方法? 傳入路徑 /loader 和 日志等級
public static String initialize(String rootDir, MMKV.LibLoader loader, MMKVLogLevel logLevel) {
? ? //如果loader不為空夭禽,則由傳入的loader 加載 c++_shared 和 mmkv 兩個so庫或颊,否則由System.loadLibrary 加載
? ? if (loader != null) {
? ? ? ? if ("SharedCpp".equals("SharedCpp")) {
? ? ? ? ? ? loader.loadLibrary("c++_shared");
? ? ? ? }
? ? ? ? loader.loadLibrary("mmkv");
? ? } else {
? ? ? ? if ("SharedCpp".equals("SharedCpp")) {
? ? ? ? ? ? System.loadLibrary("c++_shared");
? ? ? ? }
? ? ? ? System.loadLibrary("mmkv");
? ? }
? ? //jni 調(diào)用native方法
? ? jniInitialize(rootDir, logLevel2Int(logLevel));
? ? //記錄rootDir
? ? MMKV.rootDir = rootDir;
? ? return MMKV.rootDir;
}
總結(jié):初始化最后都調(diào)用的是 initialize(String rootDir, MMKV.LibLoader loader, MMKVLogLevel logLevel)
2.獲取MMKV存儲根路徑
//可以根據(jù)此方法判斷路徑是否為空 是否初始化成功砸紊,但是要注意是否在調(diào)用exit 后
public static String getRootDir() {
? ? return rootDir;
}
3.獲取MMKV
//通過mapId 獲取,默認(rèn)單進(jìn)程 獲取前必須保證初始化 即路徑不為空
@Nullable
public static MMKV mmkvWithID(String mmapID) {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? long handle = getMMKVWithID(mmapID, 1, (String)null, (String)null);
? ? ? ? return checkProcessMode(handle, mmapID, 1);
? ? }
}
//通過mapId 、進(jìn)程mode 獲取
@Nullable
public static MMKV mmkvWithID(String mmapID, int mode) {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? long handle = getMMKVWithID(mmapID, mode, (String)null, (String)null);
? ? ? ? return checkProcessMode(handle, mmapID, mode);
? ? }
}
//通過mapId mode 饭宾、key 獲取
@Nullable
public static MMKV mmkvWithID(String mmapID, int mode, @Nullable String cryptKey) {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? long handle = getMMKVWithID(mmapID, mode, cryptKey, (String)null);
? ? ? ? return checkProcessMode(handle, mmapID, mode);
? ? }
}
//通過mapID 和 rootpath 獲取
@Nullable
public static MMKV mmkvWithID(String mmapID, String rootPath) {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? long handle = getMMKVWithID(mmapID, 1, (String)null, rootPath);
? ? ? ? return checkProcessMode(handle, mmapID, 1);
? ? }
}
//通過 mapId? rootpath? 進(jìn)程批糟、key 獲取
@Nullable
public static MMKV mmkvWithID(String mmapID, int mode, @Nullable String cryptKey, String rootPath) {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? long handle = getMMKVWithID(mmapID, mode, cryptKey, rootPath);
? ? ? ? return checkProcessMode(handle, mmapID, mode);
? ? }
}
//匿名共享內(nèi)存方式獲取? 跨進(jìn)程傳輸 MMKV對應(yīng)的 handle /size/ mode/key
@Nullable
public static MMKV mmkvWithAshmemID(Context context, String mmapID, int size, int mode, @Nullable String cryptKey) {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? String processName = MMKVContentProvider.getProcessNameByPID(context, Process.myPid());
? ? ? ? if (processName != null && processName.length() != 0) {
? ? ? ? ? ? if (processName.contains(":")) {
? ? ? ? ? ? ? ? Uri uri = MMKVContentProvider.contentUri(context);
? ? ? ? ? ? ? ? if (uri == null) {
? ? ? ? ? ? ? ? ? ? simpleLog(MMKVLogLevel.LevelError, "MMKVContentProvider has invalid authority");
? ? ? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? simpleLog(MMKVLogLevel.LevelInfo, "getting parcelable mmkv in process, Uri = " + uri);
? ? ? ? ? ? ? ? ? ? Bundle extras = new Bundle();
? ? ? ? ? ? ? ? ? ? extras.putInt("KEY_SIZE", size);
? ? ? ? ? ? ? ? ? ? extras.putInt("KEY_MODE", mode);
? ? ? ? ? ? ? ? ? ? if (cryptKey != null) {
? ? ? ? ? ? ? ? ? ? ? ? extras.putString("KEY_CRYPT", cryptKey);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ContentResolver resolver = context.getContentResolver();
? ? ? ? ? ? ? ? ? ? Bundle result = resolver.call(uri, "mmkvFromAshmemID", mmapID, extras);
? ? ? ? ? ? ? ? ? ? if (result != null) {
? ? ? ? ? ? ? ? ? ? ? ? result.setClassLoader(ParcelableMMKV.class.getClassLoader());
? ? ? ? ? ? ? ? ? ? ? ? ParcelableMMKV parcelableMMKV = (ParcelableMMKV)result.getParcelable("KEY");
? ? ? ? ? ? ? ? ? ? ? ? if (parcelableMMKV != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? MMKV mmkv = parcelableMMKV.toMMKV();
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (mmkv != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? simpleLog(MMKVLogLevel.LevelInfo, mmkv.mmapID() + " fd = " + mmkv.ashmemFD() + ", meta fd = " + mmkv.ashmemMetaFD());
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? return mmkv;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? simpleLog(MMKVLogLevel.LevelInfo, "getting mmkv in main process");
? ? ? ? ? ? ? ? mode |= 8;
? ? ? ? ? ? ? ? long handle = getMMKVWithIDAndSize(mmapID, size, mode, cryptKey);
? ? ? ? ? ? ? ? return new MMKV(handle);
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? simpleLog(MMKVLogLevel.LevelError, "process name detect fail, try again later");
? ? ? ? ? ? return null;
? ? ? ? }
? ? }
}
//獲取默認(rèn)的存儲MMKV
@Nullable
public static MMKV defaultMMKV() {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? //默認(rèn)獲取的mode是單進(jìn)程格了,不加密看铆,默認(rèn)獲取的mapId 是DefaultMMKV
? ? ? ? long handle = getDefaultMMKV(1, (String)null);
? ? ? ? return checkProcessMode(handle, "DefaultMMKV", 1);
? ? }
}
//獲取默認(rèn)的存儲文件
@Nullable
public static MMKV defaultMMKV(int mode, @Nullable String cryptKey) {
? ? if (rootDir == null) {
? ? ? ? throw new IllegalStateException("You should Call MMKV.initialize() first.");
? ? } else {
? ? ? ? long handle = getDefaultMMKV(mode, cryptKey);
? ? ? ? return checkProcessMode(handle, "DefaultMMKV", mode);
? ? }
}
//檢查進(jìn)程模式? handle類似句柄不能為0,校驗(yàn)進(jìn)程模式盛末,如果模式不匹配弹惦,會拋異常
//handle 會存入本地的set,如果本地?zé)o記錄handle, 則將當(dāng)前模式和handle進(jìn)行校驗(yàn)悄但,不匹配則報(bào)錯棠隐,拋出異常
//模式校驗(yàn)通過,則將handle 賦值給變量值 private final long nativeHandle檐嚣,即new MMKV();
//這里的疑問見后續(xù)章節(jié)分析助泽,發(fā)現(xiàn)如果用不同進(jìn)程模式取獲取同一文件名,獲取到的handle值是一樣的嚎京,并未報(bào)錯
@Nullable
private static MMKV checkProcessMode(long handle, String mmapID, int mode) {
? ? if (handle == 0L) {
? ? ? ? return null;
? ? } else {
? ? ? ? if (!checkedHandleSet.contains(handle)) {
? ? ? ? ? ? if (!checkProcessMode(handle)) {
? ? ? ? ? ? ? ? String message;
? ? ? ? ? ? ? ? if (mode == 1) {
? ? ? ? ? ? ? ? ? ? message = "Opening a multi-process MMKV instance [" + mmapID + "] with SINGLE_PROCESS_MODE!";
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? message = "Opening a MMKV instance [" + mmapID + "] with MULTI_PROCESS_MODE, ";
? ? ? ? ? ? ? ? ? ? message = message + "while it's already been opened with SINGLE_PROCESS_MODE by someone somewhere else!";
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? throw new IllegalArgumentException(message);
? ? ? ? ? ? }
? ? ? ? ? ? checkedHandleSet.add(handle);
? ? ? ? }
? ? ? ? return new MMKV(handle);
? ? }
}
4.功能接口
/****退出功能******/
//退出MMKV嗡贺,針對的是全局MMKV,退出后必須重新調(diào)用initialize 否則再獲取MMKV 實(shí)例時會拋異常
public static native void onExit();
//當(dāng)某個MMKV實(shí)例不再使用時 可以考慮調(diào)用此方法關(guān)掉,后續(xù)需要重新獲取該實(shí)例
public native void close();
/***操作 加解密 相關(guān)功能***/
//獲取秘鑰針對的是單個MMKV實(shí)例
@Nullable
public native String cryptKey();
//重置秘鑰鞍帝,針對單個MMKV文件诫睬,返回重置成功或者失敗
public native boolean reKey(@Nullable String var1);
public native void checkReSetCryptKey(@Nullable String var1);
/*****獲取size相關(guān)功能****/
//靜態(tài)方法 獲取pagesize? 返回默認(rèn)值 4K
public static native int pageSize();
//獲取某個key 對應(yīng)的value的size? 需要結(jié)合PB編碼 比如整型 1 PB編碼后獲取到的是 1,500獲取到的是 2帕涌,對于引用類型比如字符串摄凡,由于PB編碼會插入字節(jié)表示長度,這里獲取的大小是包含長度字節(jié)的蚓曼,比如“12345”亲澡,這里獲取到是6
public int getValueSize(String key) {
? ? return this.valueSize(this.nativeHandle, key, false);
}
//獲取某個key 對應(yīng)的value的實(shí)際size 需要結(jié)合PB編碼 大部分情況下獲取到的值和上述 getValueSize值是一樣的,但對于字符串類型 比如“12345”獲取到的是實(shí)際大小 5纫版,會去掉表示長度的字節(jié)
public int getValueActualSize(String key) {
? ? return this.valueSize(this.nativeHandle, key, true);
}
//該存儲所占用大小 返回的是 pagesize 的倍數(shù)
public long totalSize() {
? ? return this.totalSize(this.nativeHandle);
}
//測試結(jié)果是 Key的數(shù)量(不含重復(fù)項(xiàng));removeValueForkey 也會刪除key谷扣,clearALL 后變?yōu)?
public long count() {
? ? return this.count(this.nativeHandle);
}
/***操作key相關(guān)功能***/
//是否包含某個key
public boolean containsKey(String key) {
? ? return this.containsKey(this.nativeHandle, key);
}
//刪除某個key 對應(yīng)的value,同時key 也會刪除
public void removeValueForKey(String key) {
? ? this.removeValueForKey(this.nativeHandle, key);
}
@Nullable
//獲取所有key
public native String[] allKeys();
//刪除相關(guān)key對應(yīng)的value
public native void removeValuesForKeys(String[] var1);
/***清除功能***/
//清除所有數(shù)據(jù) 針對單個MMKV
public native void clearAll();
//觸發(fā)對齊 當(dāng)刪除很多key_value后強(qiáng)制對齊下?
public native void trim();
//清除緩存 由于和SP一樣的機(jī)制,會讀緩存加載所有keyvalue,內(nèi)存告警時可以清除,再次使用時會加載所有
public native void clearMemoryCache();
//獲取版本號
public static native String version();
//獲取文件名即mmapId
public native String mmapID();
/****鎖相關(guān) 多進(jìn)程時使用*****/
//加鎖
public native void lock();
//解鎖
public native void unlock();
//嘗試加鎖
public native boolean tryLock();
//文件是否有效
public static native boolean isFileValid(String var0);
/**強(qiáng)制觸發(fā)一次同步 寫文件**/
//一般情況下不要調(diào)用 除非你擔(dān)心 電池沒電了?
public void sync() {
? this.sync(true);
}
//
public void async() {
? this.sync(false);
}
//
private native void sync(boolean var1);
/***共享內(nèi)存相關(guān)***/
public native int ashmemFD();
public native int ashmemMetaFD();
/**當(dāng)從 MMKV 取一個 String or byte[]的時候会涎,會有一次從 native 到 JVM 的內(nèi)存拷貝裹匙。如果這個值立即傳遞到另*一個 native 庫(JNI),又會有一次從 JVM 到 native 的內(nèi)存拷貝末秃。當(dāng)這個值比較大的時候概页,整個過程會非常浪費(fèi)。*Native Buffer 就是為了解決這個問題练慕。
*Native Buffer 是由 native 創(chuàng)建的內(nèi)存緩沖區(qū)惰匙,在 Java 里封裝成 NativeBuffer 類型,可以透明傳遞到另一個 *native 庫進(jìn)行訪問處理铃将。整個過程避免了先拷內(nèi)存到 JVM 又從 JVM 拷回來導(dǎo)致的浪費(fèi)
**/
public static NativeBuffer createNativeBuffer(int size) {
? ? long pointer = createNB(size);
? ? return pointer <= 0L ? null : new NativeBuffer(pointer, size);
}
public static void destroyNativeBuffer(NativeBuffer buffer) {
? ? destroyNB(buffer.pointer, buffer.size);
}
public int writeValueToNativeBuffer(String key, NativeBuffer buffer) {
? ? return this.writeValueToNB(this.nativeHandle, key, buffer.pointer, buffer.size);
}
//多進(jìn)程通知監(jiān)聽
private static native void setWantsContentChangeNotify(boolean var0);
public native void checkContentChangedByOuterProcess();
5.寫/讀數(shù)據(jù)
//讀寫bool類型相關(guān)
public boolean encode(String key, boolean value) {
? ? return this.encodeBool(this.nativeHandle, key, value);
}
public boolean decodeBool(String key) {
? ? return this.decodeBool(this.nativeHandle, key, false);
}
public boolean decodeBool(String key, boolean defaultValue) {
? ? return this.decodeBool(this.nativeHandle, key, defaultValue);
}
//讀寫int 類型
public boolean encode(String key, int value) {
? ? return this.encodeInt(this.nativeHandle, key, value);
}
public int decodeInt(String key) {
? ? return this.decodeInt(this.nativeHandle, key, 0);
}
public int decodeInt(String key, int defaultValue) {
? ? return this.decodeInt(this.nativeHandle, key, defaultValue);
}
//讀寫long 類型
public boolean encode(String key, long value) {
? ? return this.encodeLong(this.nativeHandle, key, value);
}
public long decodeLong(String key) {
? ? return this.decodeLong(this.nativeHandle, key, 0L);
}
public long decodeLong(String key, long defaultValue) {
? ? return this.decodeLong(this.nativeHandle, key, defaultValue);
}
//讀寫float類型
public boolean encode(String key, float value) {
? ? return this.encodeFloat(this.nativeHandle, key, value);
}
public float decodeFloat(String key) {
? ? return this.decodeFloat(this.nativeHandle, key, 0.0F);
}
public float decodeFloat(String key, float defaultValue) {
? ? return this.decodeFloat(this.nativeHandle, key, defaultValue);
}
//讀寫double 類型
public boolean encode(String key, double value) {
? ? return this.encodeDouble(this.nativeHandle, key, value);
}
public double decodeDouble(String key) {
? ? return this.decodeDouble(this.nativeHandle, key, 0.0D);
}
public double decodeDouble(String key, double defaultValue) {
? ? return this.decodeDouble(this.nativeHandle, key, defaultValue);
}
//讀寫字符串類型
public boolean encode(String key, @Nullable String value) {
? ? return this.encodeString(this.nativeHandle, key, value);
}
@Nullable
public String decodeString(String key) {
? ? return this.decodeString(this.nativeHandle, key, (String)null);
}
@Nullable
public String decodeString(String key, @Nullable String defaultValue) {
? ? return this.decodeString(this.nativeHandle, key, defaultValue);
}
//讀寫 set<string> 類型
public boolean encode(String key, @Nullable Set<String> value) {
? ? return this.encodeSet(this.nativeHandle, key, value == null ? null : (String[])value.toArray(new String[0]));
}
@Nullable
public Set<String> decodeStringSet(String key) {
? ? return this.decodeStringSet(key, (Set)null);
}
@Nullable
public Set<String> decodeStringSet(String key, @Nullable Set<String> defaultValue) {
? ? return this.decodeStringSet(key, defaultValue, HashSet.class);
}
@Nullable
public Set<String> decodeStringSet(String key, @Nullable Set<String> defaultValue, Class<? extends Set> cls) {
? ? String[] result = this.decodeStringSet(this.nativeHandle, key);
? ? if (result == null) {
? ? ? ? return defaultValue;
? ? } else {
? ? ? ? Set a;
? ? ? ? try {
? ? ? ? ? ? a = (Set)cls.newInstance();
? ? ? ? } catch (IllegalAccessException var7) {
? ? ? ? ? ? return defaultValue;
? ? ? ? } catch (InstantiationException var8) {
? ? ? ? ? ? return defaultValue;
? ? ? ? }
? ? ? ? a.addAll(Arrays.asList(result));
? ? ? ? return a;
? ? }
}
//讀寫 byte[]
public boolean encode(String key, @Nullable byte[] value) {
? ? return this.encodeBytes(this.nativeHandle, key, value);
}
@Nullable
public byte[] decodeBytes(String key) {
? ? return this.decodeBytes(key, (byte[])null);
}
@Nullable
public byte[] decodeBytes(String key, @Nullable byte[] defaultValue) {
? ? byte[] ret = this.decodeBytes(this.nativeHandle, key);
? ? return ret != null ? ret : defaultValue;
}
//讀寫序列化類型 Parcelable
public boolean encode(String key, @Nullable Parcelable value) {
? ? if (value == null) {
? ? ? ? return this.encodeBytes(this.nativeHandle, key, (byte[])null);
? ? } else {
? ? ? ? Parcel source = Parcel.obtain();
? ? ? ? value.writeToParcel(source, value.describeContents());
? ? ? ? byte[] bytes = source.marshall();
? ? ? ? source.recycle();
? ? ? ? return this.encodeBytes(this.nativeHandle, key, bytes);
? ? }
}
@Nullable
public <T extends Parcelable> T decodeParcelable(String key, Class<T> tClass) {
? ? return this.decodeParcelable(key, tClass, (Parcelable)null);
}
@Nullable
public <T extends Parcelable> T decodeParcelable(String key, Class<T> tClass, @Nullable T defaultValue) {
? ? if (tClass == null) {
? ? ? ? return defaultValue;
? ? } else {
? ? ? ? byte[] bytes = this.decodeBytes(this.nativeHandle, key);
? ? ? ? if (bytes == null) {
? ? ? ? ? ? return defaultValue;
? ? ? ? } else {
? ? ? ? ? ? Parcel source = Parcel.obtain();
? ? ? ? ? ? source.unmarshall(bytes, 0, bytes.length);
? ? ? ? ? ? source.setDataPosition(0);
? ? ? ? ? ? Parcelable var8;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? String name = tClass.toString();
? ? ? ? ? ? ? ? Creator creator;
? ? ? ? ? ? ? ? synchronized(mCreators) {
? ? ? ? ? ? ? ? ? ? //先從本地緩存中獲取
? ? ? ? ? ? ? ? ? ? creator = (Creator)mCreators.get(name);
? ? ? ? ? ? ? ? ? ? if (creator == null) {
? ? ? ? ? ? ? ? ? ? ? ? //獲取public 變量? CREATOR项鬼,? 由于是反射所以會保存到hashmap中 避免耗時
? ? ? ? ? ? ? ? ? ? ? ? Field f = tClass.getField("CREATOR");
? ? ? ? ? ? ? ? ? ? ? ? creator = (Creator)f.get((Object)null);
? ? ? ? ? ? ? ? ? ? ? ? if (creator != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? mCreators.put(name, creator);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? //如果為空 則表明類沒有實(shí)現(xiàn)Parcelable 序列化
? ? ? ? ? ? ? ? if (creator == null) {
? ? ? ? ? ? ? ? ? ? throw new Exception("Parcelable protocol requires a non-null static Parcelable.Creator object called CREATOR on class " + name);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? var8 = (Parcelable)creator.createFromParcel(source);
? ? ? ? ? ? } catch (Exception var16) {
? ? ? ? ? ? ? ? simpleLog(MMKVLogLevel.LevelError, var16.toString());
? ? ? ? ? ? ? ? return defaultValue;
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? source.recycle();
? ? ? ? ? ? }
? ? ? ? ? ? return var8;
? ? ? ? }
? ? }
}
//類型:bool/int/byte[]/long/float/double/Parcelable/Set<String>/string;
//數(shù)據(jù)的讀取和寫入關(guān)鍵是 nativeHandle 類似文件句柄
6.sp 遷移
public int importFromSharedPreferences(SharedPreferences preferences) {
? ? //獲取sp 存儲的所有鍵值對? 這里沒有對參數(shù)判空
? ? Map<String, ?> kvs = preferences.getAll();
? ? if (kvs != null && kvs.size() > 0) {
? ? ? ? Iterator var3 = kvs.entrySet().iterator();
? ? ? ? while(var3.hasNext()) {
? ? ? ? ? ? Entry<String, ?> entry = (Entry)var3.next();
? ? ? ? ? ? String key = (String)entry.getKey();
? ? ? ? ? ? Object value = entry.getValue();
? ? ? ? ? ? if (key != null && value != null) {
? ? ? ? ? ? ? ? if (value instanceof Boolean) {
? ? ? ? ? ? ? ? ? ? this.encodeBool(this.nativeHandle, key, (Boolean)value);
? ? ? ? ? ? ? ? } else if (value instanceof Integer) {
? ? ? ? ? ? ? ? ? ? this.encodeInt(this.nativeHandle, key, (Integer)value);
? ? ? ? ? ? ? ? } else if (value instanceof Long) {
? ? ? ? ? ? ? ? ? ? this.encodeLong(this.nativeHandle, key, (Long)value);
? ? ? ? ? ? ? ? } else if (value instanceof Float) {
? ? ? ? ? ? ? ? ? ? this.encodeFloat(this.nativeHandle, key, (Float)value);
? ? ? ? ? ? ? ? } else if (value instanceof Double) {
? ? ? ? ? ? ? ? ? ? this.encodeDouble(this.nativeHandle, key, (Double)value);
? ? ? ? ? ? ? ? } else if (value instanceof String) {
? ? ? ? ? ? ? ? ? ? this.encodeString(this.nativeHandle, key, (String)value);
? ? ? ? ? ? ? ? } else if (value instanceof Set) {
? ? ? ? ? ? ? ? ? ? this.encode(key, (Set)value);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? simpleLog(MMKVLogLevel.LevelError, "unknown type: " + value.getClass());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //返回SP鍵值對的數(shù)量
? ? ? ? return kvs.size();
? ? } else {
? ? ? ? return 0;
? ? }
}
//sp 數(shù)據(jù)變更監(jiān)聽 這里MMKV沒有做實(shí)現(xiàn),調(diào)用會拋異常 謹(jǐn)慎調(diào)用
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
? ? ? ? throw new UnsupportedOperationException("Not implement in MMKV");
? ? }
? ? public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
? ? ? ? throw new UnsupportedOperationException("Not implement in MMKV");
? ? }
7.日志定向/數(shù)據(jù)恢復(fù)
//默認(rèn)的log等級是levelInfo劲阎,轉(zhuǎn)換成相應(yīng)等級
private static int logLevel2Int(MMKVLogLevel level) {
? ? byte realLevel;
? ? switch(level) {
? ? case LevelDebug:
? ? ? ? realLevel = 0;
? ? ? ? break;
? ? case LevelWarning:
? ? ? ? realLevel = 2;
? ? ? ? break;
? ? case LevelError:
? ? ? ? realLevel = 3;
? ? ? ? break;
? ? case LevelNone:
? ? ? ? realLevel = 4;
? ? ? ? break;
? ? case LevelInfo:
? ? default:
? ? ? ? realLevel = 1;
? ? }
? ? return realLevel;
}
public static void setLogLevel(MMKVLogLevel level) {
? ? int realLevel = logLevel2Int(level);
? ? //設(shè)置給MMKV底層庫
? ? setLogLevel(realLevel);
}
//注冊gCallbackHandler
public static void registerHandler(MMKVHandler handler) {
? ? gCallbackHandler = handler;
? ? if (gCallbackHandler.wantLogRedirecting()) {
? ? ? ? setCallbackHandler(true, true);
? ? ? ? gWantLogReDirecting = true;
? ? } else {
? ? ? ? setCallbackHandler(false, true);
? ? ? ? gWantLogReDirecting = false;
? ? }
}
//解注冊gCallbackHandler
public static void unregisterHandler() {
? ? gCallbackHandler = null;
? ? setCallbackHandler(false, false);
? ? gWantLogReDirecting = false;
}
//文件CRC校驗(yàn)錯誤時 默認(rèn)采用丟棄策略绘盟,如果設(shè)置了gCallbackHandler,則采用設(shè)置的策略悯仙,要么丟棄龄毡,要么恢復(fù),恢復(fù)不可信
private static int onMMKVCRCCheckFail(String mmapID) {
? ? MMKVRecoverStrategic strategic = MMKVRecoverStrategic.OnErrorDiscard;
? ? if (gCallbackHandler != null) {
? ? ? ? strategic = gCallbackHandler.onMMKVCRCCheckFail(mmapID);
? ? }
? ? simpleLog(MMKVLogLevel.LevelInfo, "Recover strategic for " + mmapID + " is " + strategic);
? ? Integer value = (Integer)recoverIndex.get(strategic);
? ? return value == null ? 0 : value;
}
//文件長度錯誤時 默認(rèn)采用丟棄策略锡垄,如果設(shè)置了gCallbackHandler沦零,則采用設(shè)置的策略,要么丟棄要么恢復(fù)货岭,恢復(fù)不可信
private static int onMMKVFileLengthError(String mmapID) {
? ? MMKVRecoverStrategic strategic = MMKVRecoverStrategic.OnErrorDiscard;
? ? if (gCallbackHandler != null) {
? ? ? ? strategic = gCallbackHandler.onMMKVFileLengthError(mmapID);
? ? }
? ? simpleLog(MMKVLogLevel.LevelInfo, "Recover strategic for " + mmapID + " is " + strategic);
? ? Integer value = (Integer)recoverIndex.get(strategic);
? ? return value == null ? 0 : value;
}
//如果gCallbackHandler 設(shè)置了日志重定向 則重定向日志由業(yè)務(wù)方接管路操,否則MMKV采用默認(rèn)的Log 輸出
private static void mmkvLogImp(int level, String file, int line, String function, String message) {
? ? if (gCallbackHandler != null && gWantLogReDirecting) {
? ? ? ? gCallbackHandler.mmkvLog(index2LogLevel[level], file, line, function, message);
? ? } else {
? ? ? ? switch(index2LogLevel[level]) {
? ? ? ? case LevelDebug:
? ? ? ? ? ? Log.d("MMKV", message);
? ? ? ? ? ? break;
? ? ? ? case LevelWarning:
? ? ? ? ? ? Log.w("MMKV", message);
? ? ? ? ? ? break;
? ? ? ? case LevelError:
? ? ? ? ? ? Log.e("MMKV", message);
? ? ? ? case LevelNone:
? ? ? ? default:
? ? ? ? ? ? break;
? ? ? ? case LevelInfo:
? ? ? ? ? ? Log.i("MMKV", message);
? ? ? ? }
? ? }
}
//獲取堆棧信息 組織log? 函數(shù)內(nèi)沒有做越界判斷?
private static void simpleLog(MMKVLogLevel level, String message) {
? ? StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
? ? StackTraceElement e = stacktrace[stacktrace.length - 1];
? ? Integer i = (Integer)logLevel2Index.get(level);
? ? int intLevel = i == null ? 0 : i;
? ? mmkvLogImp(intLevel, e.getFileName(), e.getLineNumber(), e.getMethodName(), message);
}
8.數(shù)據(jù)變化通知(進(jìn)程間使用)
//注冊數(shù)據(jù)變化監(jiān)聽
public static void registerContentChangeNotify(MMKVContentChangeNotification notify) {
? ? gContentChangeNotify = notify;
? ? setWantsContentChangeNotify(gContentChangeNotify != null);
}
//解注冊數(shù)據(jù)變化監(jiān)聽
public static void unregisterContentChangeNotify() {
? ? gContentChangeNotify = null;
? ? setWantsContentChangeNotify(false);
}
//其他進(jìn)程改變數(shù)據(jù)后通知
private static void onContentChangedByOuterProcess(String mmapID) {
? ? if (gContentChangeNotify != null) {
? ? ? ? gContentChangeNotify.onContentChangedByOuterProcess(mmapID);
? ? }
}
private static native void setWantsContentChangeNotify(boolean var0);