本文主要包括以下内容
1.SharedPreferences存在的问题
2.MMKV的基本使用与介绍
3.MMKV的原理
SharedPreferences存在的问题
SP的效率比较低
1.读写方式:直接I/O
2.数据格式:xml
3.写入方式:全量更新
由于SP使用的xml格式保存数据,所以每次更新数据只能全量替换更新数据
这意味着如果我们有100个数据,如果只更新一项数据,也需要将所有数据转化成xml格式,然后再通过io写入文件中
这也导致SP的写入效率比较低
commit导致的ANR
public boolean commit() {
// 在当前线程将数据保存到mMap中
MemoryCommitResult mcr = commitToMemory();
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, null);
try {
// 如果是在singleThreadPool中执行写入操作,通过await()暂停主线程,直到写入操作完成。
// commit的同步性就是通过这里完成的。
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
}
/*
- 回调的时机:
- 1. commit是在内存和硬盘操作均结束时回调
- 2. apply是内存操作结束时就进行回调
*/
notifyListeners(mcr);
return mcr.writeToDiskResult;
}
复制代码
如上所示
1.commit有返回值,表示修改是否提交成功
2.commit提交是同步的,直到磁盘操作成功后才会完成
所以当数据量比较大时,使用commit很可能引起ANR
Apply导致的ANR
commit是同步的,同时SP也提供了异步的apply
apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘,因此,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率
但是apply同样会引起ANR的问题
public void apply() {
final long startTime = System.currentTimeMillis();
final MemoryCommitResult mcr = commitToMemory();
final Runnable awaitCommit = new Runnable() {
@Override
public void run() {
mcr.writtenToDiskLatch.await(); // 等待
…
}
};
// 将 awaitCommit 添加到队列 QueuedWork 中
QueuedWork.addFinisher(awaitCommit);
Runnable postWriteRunnable = new Runnable() {
@Override
public void run() {
awaitCommit.run();
QueuedWork.removeFinisher(awaitCommit);
}
};
SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
}
复制代码
- 将一个
awaitCommit
的Runnable
任务,添加到队列QueuedWork
中,在awaitCommit
中会调用await()
方法等待,在handleStopService
、handleStopActivity
等等生命周期会以这个作为判断条件,等待任务执行完毕 - 将一个
postWriteRunnable
的Runnable
写任务,通过enqueueDiskWrite
方法,将写入任务加入到队列中,而写入任务在一个线程中执行
为了保证异步任务及时完成,当生命周期处于 handleStopService()
、 handlePauseActivity()
、 handleStopActivity()
的时候会调用 QueuedWork.waitToFinish()
会等待写入任务执行完毕
private static final ConcurrentLinkedQueue sPendingWorkFinishers =
new ConcurrentLinkedQueue();
public static void waitToFinish() {
Runnable toFinish;
while ((toFinish = sPendingWorkFinishers.poll()) != null) {
toFinish.run(); // 相当于调用 mcr.writtenToDiskLatch.await()
方法
}
}
复制代码
sPendingWorkFinishers
是ConcurrentLinkedQueue
实例,apply
方法会将写入任务添加到sPendingWorkFinishers
队列中,在单个线程的线程池中执行写入任务,线程的调度并不由程序来控制,也就是说当生命周期切换的时候,任务不一定处于执行状态toFinish.run()
方法,相当于调用mcr.writtenToDiskLatch.await()
方法,会一直等待waitToFinish()
方法就做了一件事,会一直等待写入任务执行完毕,其它什么都不做,当有很多写入任务,会依次执行,当文件很大时,效率很低,造成 ANR 就不奇怪了
所以当数据量比较大时,apply
也会造成ANR
getXXX() 导致ANR
不仅是写入操作,所有 getXXX() 方法都是同步的,在主线程调用 get 方法,必须等待 SP 加载完毕,也有可能导致ANR
调用 getSharedPreferences()
方法,最终会调用 SharedPreferencesImpl#startLoadFromDisk()
方法开启一个线程异步读取数据。
private final Object mLock = new Object();
private boolean mLoaded = false;
private void startLoadFromDisk() {
synchronized (mLock) {
mLoaded = false;
}
new Thread(“SharedPreferencesImpl-load”) {
public void run() {
loadFromDisk();
}
}.start();
}
复制代码
正如你所看到的,开启一个线程异步读取数据,当我们正在读取一个比较大的数据,还没读取完,接着调用 getXXX()
方法。
public String getString(String key, @Nullable String defValue) {
synchronized (mLock) {
awaitLoadedLocked();
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
private void awaitLoadedLocked() {
…
while (!mLoaded) {
try {
mLock.wait();
} catch (InterruptedException unused) {
}
}
…
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
前端框架
前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。
以 Vue 为例,我整理了如下的面试题。
CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
I人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**