内容简介:首先获取在
一、概述
1.1 简介
1.2 用法
首先获取 SharedPreferences
实例,调用 sp.edit()
获得可编辑实例,写入类型的数据并提交。
SharedPreferences sp = getSharedPreferences("PrefsName", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putInt("Int", 1024);
editor.putLong("Long", 47526348576L);
editor.putFloat("Float", 3.1415926F);
editor.putBoolean("Boolean", true);
editor.putString("String", "SharedPreferences String");
editor.apply();
在 Android Studio
右下角有 Device File Explorer
,按照以下路径找出保存的 <PrefsName>.xml
。文件名为 getSharedPreferences("PrefsName", MODE_PRIVATE)
中的实参值。
/data/data/<Application Package Name>/shared_prefs/<PrefsName>.xml
实际写入的文件内容是这样的:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<int name="Int" value="1024" />
<float name="Float" value="3.1415925" />
<boolean name="Boolean" value="true" />
<long name="Long" value="47526348576" />
<string name="String">SharedPreferences String</string>
</map>
简单看来,除了String类型的其他类型值实际上都保存为字符串。
1.3 架构
二、源码剖析
2.1 SharedPreferences抽象接口
SharedPreferences
是一个接口,源码路径是 /frameworks/base/core/java/android/content
。
// 读写由getSharedPreferences返回的数据。修改操作需通过Editor对象,以保证数据一致性和控制回写的时机
// 此类不能用在多进程中,可以在相同进程不同线程中同时调用线程安全
public interface SharedPreferences {
// 当SharedPreference发生变化时回调的监听器
public interface OnSharedPreferenceChangeListener {
// 当SharedPreference发生修改、新增、移除时回调的方法,key为此时变化的键,方法回调在主线程
// @param sharedPreferences 发生变化的SharedPreferences
// @param key 值发生修改、新增、移除的键
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
}
// 修改SharedPreferences中值的接口,所有操作均为批处理,只在调用commit或apply后才回写到磁盘
public interface Editor {
// 向编辑器设置一个String类型的键值对,并在commit或apply方法调用时进行回写
Editor putString(String key, @Nullable String value);
// 向编辑器设置一个String类型的键值对集合,并在commit或apply方法调用时进行回写
Editor putStringSet(String key, @Nullable Set<String> values);
// 向编辑器设置一个int类型的键值对,并在commit或apply方法调用时进行回写
Editor putInt(String key, int value);
// 向编辑器设置一个long类型的键值对,并在commit或apply方法调用时进行回写
Editor putLong(String key, long value);
// 向编辑器设置一个float类型的键值对,并在commit或apply方法调用时进行回写
Editor putFloat(String key, float value);
// 向编辑器设置一个boolean类型的键值对,并在commit或apply方法调用时进行回写
Editor putBoolean(String key, boolean value);
// 移除编辑器中指定的key,并在commit或apply方法调用时进行回写
// 移除操作在其他操作之前,即不管移除操作是否在添加之后调用,都会优先执行
Editor remove(String key);
// 清除所有值,并在commit或apply方法调用时进行回写
// 移除操作在其他操作之前,即不管移除操作是否在添加之后调用,都会优先执行
Editor clear();
// 执行所有preferences修改
// 当有两个editors同时修改preferences,最后一个被调用的总能被执行
// 如果不关心执行的结果值,且在主线程使用,建议通过apply提交修改
// true提交并修改成功,false表示失败
boolean commit();
// 执行所有preferences修改
// 当有两个editors同时修改preferences,最后一个被调用的总能被执行
// apply所有提交保存在内存中,并异步进行回写,即回写失败不会有任何提示
// 当apply还没完成,其他editor的commit操作会阻塞并等待异步回写完成
// SharedPreferences进程内线程安全,且在不关心返回值的情况下可用apply代替commit
// apply的写入安全由Android Framework保证,不受组件生命周期或交互影响
void apply();
}
// 从preferences获得所有值,且一定不能修改这个Map的数据,增删改都不行
// 否则会出现已存储数据不一致的问题
Map<String, ?> getAll();
// 获取key对应的String,若key不存在则返回defValue
// 如果key存在但不是String类型,则直接抛出ClassCastException
@Nullable
String getString(String key, @Nullable String defValue);
// 通过key获取字符串集合,且一直能够不能修改返回的数据,否则会导致数据不一致的问题
@Nullable
Set<String> getStringSet(String key, @Nullable Set<String> defValues);
// 获取key对应的int,若key不存在则返回defValue
// 如果key存在但不是int类型,则直接抛出ClassCastException
int getInt(String key, int defValue);
// 获取key对应的long,若key不存在则返回defValue
// 如果key存在但不是long类型,则直接抛出ClassCastException
long getLong(String key, long defValue);
// 获取key对应的float,若key不存在则返回defValue
// 如果key存在但不是float类型,则直接抛出ClassCastException
float getFloat(String key, float defValue);
// 获取key对应的boolean,若key不存在则返回defValue
// 如果key存在但不是boolean类型,则直接抛出ClassCastException
boolean getBoolean(String key, boolean defValue);
// 检查是否已包含此键代表的preference
boolean contains(String key);
// 给preferences创建多一个新的Editor,并使用commit提交修改
Editor edit();
// 新增一个未注册的监听器
void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
// 移除一个已注册的监听器
void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
}
2.2 SharedPreferencesImpl实现类
类文件在 /frameworks/base/core/java/android/app
中
final class SharedPreferencesImpl implements SharedPreferences {
private static final String TAG = "SharedPreferencesImpl";
private static final boolean DEBUG = false;
private static final Object CONTENT = new Object();
/** If a fsync takes more than {@value #MAX_FSYNC_DURATION_MILLIS} ms, warn */
private static final long MAX_FSYNC_DURATION_MILLIS = 256;
// Lock ordering rules:
// - acquire SharedPreferencesImpl.mLock before EditorImpl.mLock
// - acquire mWritingToDiskLock before EditorImpl.mLock
// 当前的文件
private final File mFile;
// 备份的文件
private final File mBackupFile;
// 模式
private final int mMode;
// 锁
private final Object mLock = new Object();
// 磁盘写入锁
private final Object mWritingToDiskLock = new Object();
@GuardedBy("mLock")
private Map<String, Object> mMap;
@GuardedBy("mLock")
private int mDiskWritesInFlight = 0;
// 已加载标志位
@GuardedBy("mLock")
private boolean mLoaded = false;
@GuardedBy("mLock")
private StructTimespec mStatTimestamp;
@GuardedBy("mLock")
private long mStatSize;
// 监听器列表,通过WeakHashMap持有监听器
@GuardedBy("mLock")
private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
// 当前内存状态,持续递增
@GuardedBy("this")
private long mCurrentMemoryStateGeneration;
// 提交到磁盘的最新内存状态
@GuardedBy("mWritingToDiskLock")
private long mDiskStateGeneration;
// 系统文件同步请求的次数
@GuardedBy("mWritingToDiskLock")
private final ExponentiallyBucketedHistogram mSyncTimes = new ExponentiallyBucketedHistogram(16);
private int mNumSync = 0;
SharedPreferencesImpl(File file, int mode) {
mFile = file;
mBackupFile = makeBackupFile(file);
mMode = mode;
mLoaded = false;
mMap = null;
startLoadFromDisk();
}
// 开始从磁盘加载
private void startLoadFromDisk() {
synchronized (mLock) {
mLoaded = false;
}
new Thread("SharedPreferencesImpl-load") {
public void run() {
loadFromDisk();
}
}.start();
}
private void loadFromDisk() {
synchronized (mLock) {
// 如果已经加载过,跳出
if (mLoaded) {
return;
}
// 备份文件存在,则把源文件删除,备份文件作为原文件
if (mBackupFile.exists()) {
mFile.delete();
mBackupFile.renameTo(mFile);
}
}
Map<String, Object> map = null;
StructStat stat = null;
try {
stat = Os.stat(mFile.getPath());
// 从文件读出数据
if (mFile.canRead()) {
BufferedInputStream str = null;
try {
str = new BufferedInputStream(
new FileInputStream(mFile), 16*1024);
// 把xml转换为对应键值对
map = (Map<String, Object>) XmlUtils.readMapXml(str);
} catch (Exception e) {
Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e);
} finally {
IoUtils.closeQuietly(str);
}
}
} catch (ErrnoException e) {
/* ignore */
}
synchronized (mLock) {
mLoaded = true;
// 读取的数据不为空,则把数据设置到mMap
if (map != null) {
mMap = map;
mStatTimestamp = stat.st_mtim;
mStatSize = stat.st_size;
} else {
// 磁盘没有已保存数据,则创建空HashMap给mMap
mMap = new HashMap<>();
}
mLock.notifyAll();
}
}
// 创建备份文件
static File makeBackupFile(File prefsFile) {
return new File(prefsFile.getPath() + ".bak");
}
// 出现意外是开始重新加载
void startReloadIfChangedUnexpectedly() {
synchronized (mLock) {
if (!hasFileChangedUnexpectedly()) {
return;
}
startLoadFromDisk();
}
}
// Has the file changed out from under us? i.e. writes that
// we didn't instigate.
// 文件被外部操作修改了?
private boolean hasFileChangedUnexpectedly() {
synchronized (mLock) {
if (mDiskWritesInFlight > 0) {
// If we know we caused it, it's not unexpected.
return false;
}
}
final StructStat stat;
try {
/*
* Metadata operations don't usually count as a block guard
* violation, but we explicitly want this one.
*/
BlockGuard.getThreadPolicy().onReadFromDisk();
stat = Os.stat(mFile.getPath());
} catch (ErrnoException e) {
return true;
}
synchronized (mLock) {
return !stat.st_mtim.equals(mStatTimestamp) || mStatSize != stat.st_size;
}
}
// 注册修改监听器
@Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
synchronized(mLock) {
// 向列表中加入监听器
mListeners.put(listener, CONTENT);
}
}
// 移除修改监听器
@Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
synchronized(mLock) {
// 从列表中移除监听器
mListeners.remove(listener);
}
}
// 阻塞等待文件内容已加载到对象中
private void awaitLoadedLocked() {
if (!mLoaded) {
// Raise an explicit StrictMode onReadFromDisk for this
// thread, since the real read will be in a different
// thread and otherwise ignored by StrictMode.
BlockGuard.getThreadPolicy().onReadFromDisk();
}
while (!mLoaded) {
try {
mLock.wait();
} catch (InterruptedException unused) {
}
}
}
// 获取所有
@Override
public Map<String, ?> getAll() {
synchronized (mLock) {
awaitLoadedLocked();
//noinspection unchecked
return new HashMap<String, Object>(mMap);
}
}
// 获取字符串
@Override
@Nullable
public String getString(String key, @Nullable String defValue) {
synchronized (mLock) {
awaitLoadedLocked();
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
// 获取字符串集合
@Override
@Nullable
public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
synchronized (mLock) {
awaitLoadedLocked();
Set<String> v = (Set<String>) mMap.get(key);
return v != null ? v : defValues;
}
}
// 获取Int
@Override
public int getInt(String key, int defValue) {
synchronized (mLock) {
awaitLoadedLocked();
Integer v = (Integer)mMap.get(key);
return v != null ? v : defValue;
}
}
// 获取Long
@Override
public long getLong(String key, long defValue) {
synchronized (mLock) {
awaitLoadedLocked();
Long v = (Long)mMap.get(key);
return v != null ? v : defValue;
}
}
// 获取Float
@Override
public float getFloat(String key, float defValue) {
synchronized (mLock) {
awaitLoadedLocked();
Float v = (Float)mMap.get(key);
return v != null ? v : defValue;
}
}
// 获取Boolean
@Override
public boolean getBoolean(String key, boolean defValue) {
synchronized (mLock) {
awaitLoadedLocked();
Boolean v = (Boolean)mMap.get(key);
return v != null ? v : defValue;
}
}
// 检查时候包含指定key
@Override
public boolean contains(String key) {
synchronized (mLock) {
awaitLoadedLocked();
return mMap.containsKey(key);
}
}
@Override
public Editor edit() {
// 阻塞等待加载完成,并返回编辑对象
synchronized (mLock) {
awaitLoadedLocked();
}
return new EditorImpl();
}
// Return value from EditorImpl#commitToMemory()
private static class MemoryCommitResult {
final long memoryStateGeneration;
@Nullable final List<String> keysModified;
// SharedPreference修改时间监听器
@Nullable final Set<OnSharedPreferenceChangeListener> listeners;
// 需要写磁盘的Map
final Map<String, Object> mapToWriteToDisk;
final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
// 写磁盘结果
@GuardedBy("mWritingToDiskLock")
volatile boolean writeToDiskResult = false;
// 已写入标志位
boolean wasWritten = false;
private MemoryCommitResult(long memoryStateGeneration, @Nullable List<String> keysModified,
@Nullable Set<OnSharedPreferenceChangeListener> listeners,
Map<String, Object> mapToWriteToDisk) {
this.memoryStateGeneration = memoryStateGeneration;
this.keysModified = keysModified;
this.listeners = listeners;
this.mapToWriteToDisk = mapToWriteToDisk;
}
// wasWritten:已写入
// result:结果
void setDiskWriteResult(boolean wasWritten, boolean result) {
this.wasWritten = wasWritten;
writeToDiskResult = result;
writtenToDiskLatch.countDown();
}
}
public final class EditorImpl implements Editor {
// 编辑器锁
private final Object mEditorLock = new Object();
// 需修改记录,记录在内存中
@GuardedBy("mEditorLock")
private final Map<String, Object> mModified = new HashMap<>();
// 是否是干净的
@GuardedBy("mEditorLock")
private boolean mClear = false;
// 存入String
@Override
public Editor putString(String key, @Nullable String value) {
synchronized (mEditorLock) {
// 向HashMap记录最新修改
mModified.put(key, value);
return this;
}
}
// 存入StringSet
@Override
public Editor putStringSet(String key, @Nullable Set<String> values) {
synchronized (mEditorLock) {
// 向HashMap记录最新修改
mModified.put(key,
(values == null) ? null : new HashSet<String>(values));
return this;
}
}
// 存入Int
@Override
public Editor putInt(String key, int value) {
synchronized (mEditorLock) {
// 向HashMap记录最新修改
mModified.put(key, value);
return this;
}
}
// 存入Long
@Override
public Editor putLong(String key, long value) {
synchronized (mEditorLock) {
// 向HashMap记录最新修改
mModified.put(key, value);
return this;
}
}
// 存入Float
@Override
public Editor putFloat(String key, float value) {
synchronized (mEditorLock) {
// 向HashMap记录最新修改
mModified.put(key, value);
return this;
}
}
// 存入Boolean
@Override
public Editor putBoolean(String key, boolean value) {
synchronized (mEditorLock) {
// 向HashMap记录最新修改
mModified.put(key, value);
return this;
}
}
// 移除key
@Override
public Editor remove(String key) {
synchronized (mEditorLock) {
// 向HashMap记录最新修改
mModified.put(key, this);
return this;
}
}
// 清空所有key
@Override
public Editor clear() {
synchronized (mEditorLock) {
// 设置清除标志位
mClear = true;
return this;
}
}
@Override
public void apply() {
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
@Override
public void run() {
try {
mcr.writtenToDiskLatch.await();
} catch (InterruptedException ignored) {
}
}
};
QueuedWork.addFinisher(awaitCommit);
Runnable postWriteRunnable = new Runnable() {
@Override
public void run() {
awaitCommit.run();
QueuedWork.removeFinisher(awaitCommit);
}
};
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
// Okay to notify the listeners before it's hit disk
// because the listeners should always get the same
// SharedPreferences instance back, which has the
// changes reflected in memory.
notifyListeners(mcr);
}
// 有修改返回true
private MemoryCommitResult commitToMemory() {
long memoryStateGeneration;
List<String> keysModified = null;
Set<OnSharedPreferenceChangeListener> listeners = null;
Map<String, Object> mapToWriteToDisk;
synchronized (SharedPreferencesImpl.this.mLock) {
// We optimistically don't make a deep copy until
// a memory commit comes in when we're already
// writing to disk.
if (mDiskWritesInFlight > 0) {
// We can't modify our mMap as a currently
// in-flight write owns it. Clone it before
// modifying it.
// noinspection unchecked
mMap = new HashMap<String, Object>(mMap);
}
mapToWriteToDisk = mMap;
mDiskWritesInFlight++;
// 监听器数量
boolean hasListeners = mListeners.size() > 0;
if (hasListeners) {
keysModified = new ArrayList<String>();
listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
}
synchronized (mEditorLock) {
boolean changesMade = false;
// 如果调用了clear(),则mClear为true
if (mClear) {
// 需写入磁盘的数据不为空
if (!mapToWriteToDisk.isEmpty()) {
changesMade = true;
// 把需写入的数据全部置空
mapToWriteToDisk.clear();
}
mClear = false;
}
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
// "this" is the magic value for a removal mutation. In addition,
// setting a value to "null" for a given key is specified to be
// equivalent to calling remove on that key.
if (v == this || v == null) {
if (!mapToWriteToDisk.containsKey(k)) {
continue;
}
mapToWriteToDisk.remove(k);
} else {
if (mapToWriteToDisk.containsKey(k)) {
Object existingValue = mapToWriteToDisk.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
mapToWriteToDisk.put(k, v);
}
changesMade = true;
if (hasListeners) {
keysModified.add(k);
}
}
mModified.clear();
if (changesMade) {
mCurrentMemoryStateGeneration++;
}
memoryStateGeneration = mCurrentMemoryStateGeneration;
}
}
return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners,
mapToWriteToDisk);
}
@Override
public boolean commit() {
// 获取提交到内存的结果
MemoryCommitResult mcr = commitToMemory();
// 数据写入到磁盘
SharedPreferencesImpl.this.enqueueDiskWrite(
mcr, null /* sync write on this thread okay */);
try {
// 等待磁盘写入完成
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
} finally {
}
// 发送通知
notifyListeners(mcr);
// 返回写入磁盘的结果
return mcr.writeToDiskResult;
}
private void notifyListeners(final MemoryCommitResult mcr) {
// 没有需要通知的监听器或没有被修改的key,则直接退出
if (mcr.listeners == null || mcr.keysModified == null ||
mcr.keysModified.size() == 0) {
return;
}
// 已在主线程,直接通知所有监听器
if (Looper.myLooper() == Looper.getMainLooper()) {
for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
// 逐个获取已修改的key
final String key = mcr.keysModified.get(i);
// 遍历所有监听器
for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
if (listener != null) {
// listener不为空,则发出通知
listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
}
}
}
} else {
// 在主线程调用
ActivityThread.sMainThreadHandler.post(() -> notifyListeners(mcr));
}
}
}
/**
* Enqueue an already-committed-to-memory result to be written
* to disk.
*
* They will be written to disk one-at-a-time in the order
* that they're enqueued.
*
* @param postWriteRunnable if non-null, we're being called
* from apply() and this is the runnable to run after
* the write proceeds. if null (from a regular commit()),
* then we're allowed to do this disk write on the main
* thread (which in addition to reducing allocations and
* creating a background thread, this has the advantage that
* we catch them in userdebug StrictMode reports to convert
* them where possible to apply() ...)
*/
// 从内存写入磁盘任务的排队队列,顺序是FIFO,依次执行
// 如果参数postWriteRunnable非空,则执行apply()
// 如果参数postWriteRunnable为空,则执行commit(),并允许数据在主线程写入磁盘
// 这可以减少内存申请和避免创建后台线程,并能通过StrictMode报告去把commit()改为apply()
private void enqueueDiskWrite(final MemoryCommitResult mcr,
final Runnable postWriteRunnable) {
// postWriteRunnable为空,同步提交数据到磁盘
final boolean isFromSyncCommit = (postWriteRunnable == null);
// 创建磁盘写入Runnable
final Runnable writeToDiskRunnable = new Runnable() {
@Override
public void run() {
synchronized (mWritingToDiskLock) {
// 写入文件,是否同步写入isFromSyncCommit
writeToFile(mcr, isFromSyncCommit);
}
synchronized (mLock) {
mDiskWritesInFlight--;
}
// 仅apply()时执行
if (postWriteRunnable != null) {
postWriteRunnable.run();
}
}
};
// Typical #commit() path with fewer allocations, doing a write on
// the current thread.
// 典型的更少内存申请的commit()方式,并在当前线程写入
if (isFromSyncCommit) {
boolean wasEmpty = false;
synchronized (mLock) {
wasEmpty = mDiskWritesInFlight == 1;
}
if (wasEmpty) {
writeToDiskRunnable.run();
return;
}
}
// 任务进队
QueuedWork.queue(writeToDiskRunnable, !isFromSyncCommit);
}
// 创建文件的输出流
private static FileOutputStream createFileOutputStream(File file) {
FileOutputStream str = null;
try {
// 创建文件输出流
str = new FileOutputStream(file);
} catch (FileNotFoundException e) {
File parent = file.getParentFile();
if (!parent.mkdir()) {
Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
return null;
}
FileUtils.setPermissions(
parent.getPath(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
try {
str = new FileOutputStream(file);
} catch (FileNotFoundException e2) {
Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
}
}
return str;
}
// 写入文件
@GuardedBy("mWritingToDiskLock")
private void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) {
long startTime = 0;
long existsTime = 0;
long backupExistsTime = 0;
long outputStreamCreateTime = 0;
long writeTime = 0;
long fsyncTime = 0;
long setPermTime = 0;
long fstatTime = 0;
long deleteTime = 0;
// 原文件是否存在
boolean fileExists = mFile.exists();
// Rename the current file so it may be used as a backup during the next read
// 重命名当前文件,以便在写一次读取时作为备份
if (fileExists) {
boolean needsWrite = false;
// Only need to write if the disk state is older than this commit
// 仅在磁盘状态比这次提交的更旧时进行写入
if (mDiskStateGeneration < mcr.memoryStateGeneration) {
// 同步写入
if (isFromSyncCommit) {
// 需要写入
needsWrite = true;
} else {
synchronized (mLock) {
// No need to persist intermediate states. Just wait for the latest state to
// be persisted.
if (mCurrentMemoryStateGeneration == mcr.memoryStateGeneration) {
needsWrite = true;
}
}
}
}
if (!needsWrite) {
mcr.setDiskWriteResult(false, true);
return;
}
// 备份是否存在
boolean backupFileExists = mBackupFile.exists();
// 磁盘文件备份不存在
if (!backupFileExists) {
// 把当前文件改名为备份文件
if (!mFile.renameTo(mBackupFile)) {
// 重命名文件失败
mcr.setDiskWriteResult(false, false);
return;
}
} else {
// 备份文件已存在,删除源文件
mFile.delete();
}
}
// Attempt to write the file, delete the backup and return true as atomically as
// possible. If any exception occurs, delete the new file; next time we will restore
// from the backup.
try {
// 创建写出流失败
FileOutputStream str = createFileOutputStream(mFile);
if (str == null) {
mcr.setDiskWriteResult(false, false);
return;
}
// 把内存中需要写入的数据按照Xml的格式写入到str
XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
// 同步流
FileUtils.sync(str);
// 关闭文件写入
str.close();
// 修改文件权限
ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
try {
final StructStat stat = Os.stat(mFile.getPath());
synchronized (mLock) {
mStatTimestamp = stat.st_mtim;
mStatSize = stat.st_size;
}
} catch (ErrnoException e) {
}
// 等待并删除备份的文件
mBackupFile.delete();
mDiskStateGeneration = mcr.memoryStateGeneration;
mcr.setDiskWriteResult(true, true);
mSyncTimes.add(Long.valueOf(fsyncDuration).intValue());
mNumSync++;
return;
} catch (XmlPullParserException e) {
Log.w(TAG, "writeToFile: Got exception:", e);
} catch (IOException e) {
Log.w(TAG, "writeToFile: Got exception:", e);
}
// 清除没用的已写入文件
if (mFile.exists()) {
if (!mFile.delete()) {
Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
}
}
mcr.setDiskWriteResult(false, false);
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 【Java集合源码剖析】ArrayList源码剖析
- Java集合源码剖析:TreeMap源码剖析
- 我的源码阅读之路:redux源码剖析
- ThreadLocal源码深度剖析
- Volley源码剖析
- 一文深度剖析 Axios 源码
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
图片转BASE64编码
在线图片转Base64编码工具
UNIX 时间戳转换
UNIX 时间戳转换