当前位置: 首页 > news >正文

南京手机网站制作wordpress默认首页设置

南京手机网站制作,wordpress默认首页设置,河池网站建设公司,wordpress支付方案解决SP的使用及存在的问题 SharedPreferences(以下简称SP)是Android本地存储的一种方式#xff0c;是以key-value的形式存储在/data/data/项目包名/shared_prefs/sp_name.xml里#xff0c;SP的使用示例及源码解析参见#xff1a;Android本地存储之SharedPreferences源码解析。以…SP的使用及存在的问题 SharedPreferences(以下简称SP)是Android本地存储的一种方式是以key-value的形式存储在/data/data/项目包名/shared_prefs/sp_name.xml里SP的使用示例及源码解析参见Android本地存储之SharedPreferences源码解析。以下是SP的一些结论 SharedPreferences读取xml文件时会以DOM方式解析把整个xml文件直接加载到内存中解析在调用getXXX()方法时取到的是内存中的数据方法执行时会有个锁来阻塞目的是等待文件加载完毕没加载完成之前会wait()。SP第一次初始化到读取到数据存在一定延迟因为需要到文件中读取数据因此可能会对UI线程流畅度造成一定影响严重情况下会产生ANR。SharedPreferences写文件时如果调用的commit(),会将数据同步写入内存中内存数据更新再同步写入磁盘中; 如果调用的apply(),会将数据同步写入内存中内存数据更新然后异步写人磁盘也就是说可能写磁盘操作还没有完成就直接返回了。在UI线程中建议使用apply()因为同步写磁盘当文件较大时commit()会等到写磁盘完成再返回可能会有ANR问题。写文件时即使用的是apply()方法依然有可能会造成ANR问题这是为什么呢先看下apply()的流程。 SharedPreferencesImpl#apply()流程分析基于8.0以上版本SharedPreferencesImpl$EditorImpl Override public void apply() {final long startTime System.currentTimeMillis();// 写入内存(更新修改的字段)final MemoryCommitResult mcr commitToMemory();// 使用CountDownLatch实现等待写入文件操作完成final Runnable awaitCommit new Runnable() {Overridepublic void run() {try {// writtenToDiskLatch初始化为CountDownLatch(1)mcr.writtenToDiskLatch.await();} catch (InterruptedException ignored) {}}};// 将awaitCommit添加到等待队列中后续Activity/Servicede的onStop()会执行该Runnable等待文件写入完成QueuedWork.addFinisher(awaitCommit);Runnable postWriteRunnable new Runnable() {Overridepublic void run() {awaitCommit.run();QueuedWork.removeFinisher(awaitCommit);}};// 将待写入文件的集合添加到工作任务队列中SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);notifyListeners(mcr); } QueuedWork.addFinisher(awaitCommit)将awaitCommit加入到等待队列中awaitCommit在执行时利用CountDownLatch机制可以实现对当前线程的阻塞效果后续Activity的onStop()中会将这里的awaitCommit取出来执行即UI线程会阻塞等待sp文件写入磁盘写入操作是通过SharedPreferencesImpl#enqueueDiskWrite()完成的写入成功后会通过writtenToDiskLatch.countDown()释放awaitCommit中的锁如果写入操作比较耗时就会造成ANR问题。 SharedPreferencesImpl.java private void enqueueDiskWrite(final MemoryCommitResult mcr,final Runnable postWriteRunnable) {final boolean isFromSyncCommit (postWriteRunnable null);final Runnable writeToDiskRunnable new Runnable() {Overridepublic void run() {synchronized (mWritingToDiskLock) {// 写入硬盘操作writeToFile(mcr, isFromSyncCommit);}synchronized (mLock) {mDiskWritesInFlight--;}if (postWriteRunnable ! null) {postWriteRunnable.run();}}};// commit()场景下会在当前线程进行写入硬盘操作if (isFromSyncCommit) {boolean wasEmpty false;synchronized (mLock) {wasEmpty mDiskWritesInFlight 1;}if (wasEmpty) {writeToDiskRunnable.run();return;}}// 添加到写入硬盘的工作队列QueuedWork.queue(writeToDiskRunnable, !isFromSyncCommit); } QueuedWork.java public static void queue(Runnable work, boolean shouldDelay) {Handler handler getHandler();synchronized (sLock) {sWork.add(work);if (shouldDelay sCanDelay) {handler.sendEmptyMessageDelayed(QueuedWorkHandler.MSG_RUN, DELAY);} else {handler.sendEmptyMessage(QueuedWorkHandler.MSG_RUN);}} }// 构造一个Handler并传入HandlerThread的Looper即Handler会在工作线程中处理消息 private static Handler getHandler() {synchronized (sLock) {if (sHandler null) {HandlerThread handlerThread new HandlerThread(queued-work-looper,Process.THREAD_PRIORITY_FOREGROUND);handlerThread.start();sHandler new QueuedWorkHandler(handlerThread.getLooper());}return sHandler;} }private static class QueuedWorkHandler extends Handler {static final int MSG_RUN 1;QueuedWorkHandler(Looper looper) {super(looper);}public void handleMessage(Message msg) {if (msg.what MSG_RUN) {// (1) 消息队列的工作线程中执行processPendingWork();}} }// 该方法存在两种执行路径: 1在消息队列对应的工作线程中执行、2当前线程执行执行前会将任务队列克隆并清空 private static void processPendingWork() {synchronized (sProcessingWork) {LinkedListRunnable work;synchronized (sLock) {// a. 拷贝工作队列中的任务集合然后将原任务集合清理当2场景主线程执行到这里时因为集合没有任务直接跳过进入等待写入磁盘任务完成work (LinkedListRunnable) sWork.clone();sWork.clear();// b. 移除队列中的所有消息下面立即处理getHandler().removeMessages(QueuedWorkHandler.MSG_RUN);}if (work.size() 0) {// 取出Runnable并执行for (Runnable w : work) {w.run();}}} } QueuedWork.waitToFinish Activity的onStop()、Service的onDestroy()执行时都会调用到QueuedWork.waitToFinish()方法 ActivityThread.java private void handleStopService(IBinder token) {Service s mServices.remove(token);if (s ! null) {try {if (localLOGV) Slog.v(TAG, Destroying service s);s.onDestroy();s.detachAndCleanUp();// 看这里QueuedWork.waitToFinish();//......} catch (Exception e) {}} }Override public void handleStopActivity(IBinder token, int configChanges,PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {final ActivityClientRecord r mActivities.get(token);r.activity.mConfigChangeFlags | configChanges;final StopInfo stopInfo new StopInfo();performStopActivityInner(r, stopInfo, true /* saveState */, finalStateRequest,reason);// 大于API11的时候执行if (!r.isPreHoneycomb()) {// 看这里QueuedWork.waitToFinish();}//...... } Activity的onStop()、Service中的onDestroy()都是间接在ActivityThread中的handleStopService()、handleStopActivity()执行的这两个方法里都会执行到QueuedWork.waitToFinish() public static void waitToFinish() {long startTime System.currentTimeMillis();boolean hadMessages false;Handler handler getHandler();synchronized (sLock) {if (handler.hasMessages(QueuedWorkHandler.MSG_RUN)) {// Delayed work will be processed at processPendingWork() belowhandler.removeMessages(QueuedWorkHandler.MSG_RUN);}// We should not delay any work as this might delay the finisherssCanDelay false;}StrictMode.ThreadPolicy oldPolicy StrictMode.allowThreadDiskWrites();try {// (2) 把任务取出来直接在当前线程处理文件操作 8.0之后的逻辑文件操作容易导致anr因为之前清理任务集合这里可能会立即执行完成进入下面执行等待状态processPendingWork();} finally {StrictMode.setThreadPolicy(oldPolicy);}try {while (true) {Runnable finisher;synchronized (sLock) {// 重点finisher sFinishers.poll();}if (finisher null) {break;}finisher.run();}} finally {sCanDelay true;}} } 这里的sFinishers中取的Runnable就是在写文件之前通过QueuedWork.addFinisher(awaitCommit)添加的当取出awaitCommit执行时即会阻塞当前线程如果apply()中写入磁盘时间过长导致awaitCommit的锁没有及时释放UI线程就会因为长时间被阻塞得不到执行而出现ANR了。 总结如下图 图片来自今日头条 ANR 优化实践系列 - 告别 SharedPreference 等待所以结论是使用apply()依然有可能会造成ANR问题。 8.0以下 写文件流程 public void apply() {final MemoryCommitResult mcr commitToMemory();// 这里的操作是为了CountDownLatch实现等待效果final Runnable awaitCommit new Runnable() {public void run() {try {mcr.writtenToDiskLatch.await();} catch (InterruptedException ignored) {}}};QueuedWork.add(awaitCommit);Runnable postWriteRunnable new Runnable() {public void run() {awaitCommit.run();QueuedWork.remove(awaitCommit);}};SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable); } QueuedWork.waitToFinish() public static void waitToFinish() {Runnable toFinish;while ((toFinish sPendingWorkFinishers.poll()) ! null) {toFinish.run();} } 8.0以下的流程相对更简单一些但核心流程是一样的当在UI线程中调用到QueuedWork.waitToFinish()时如果写入磁盘的操作还未完成且耗时比较长都会引起UI线程的ANR。 如何优化 Jetpack DataStore替代 Jetpack DataStore 是一种改进的新数据存储解决方案允许使用协议缓冲区存储键值对或类型化对象。DataStore 以异步、一致的事务方式存储数据克服了 SharedPreferences以下统称为SP的一些缺点。DataStore基于Kotlin协程和Flow实现并且可以对SP数据进行迁移旨在取代SP。 DataStore提供了两种不同的实现Preferences DataStore与Proto DataStore其中Preferences DataStore用于存储键值对Proto DataStore用于存储类型化对象DataStore更详细的介绍参见Android Jetpack系列之DataStore MMKV替代 MMKV 是基于 mmap 内存映射的key-value 组件底层序列化/反序列化使用 protobuf实现性能高稳定性强。从 2015 年中至今在微信上使用其性能和稳定性经过了时间的验证。近期也已移植到 Android / macOS / Win32 / POSIX 平台一并开源。 注mmap 内存映射可以提供一段可供随时写入的内存块App 只管往里面写数据由操作系统负责将内存回写到文件不必担心 crash 导致数据丢失。 MMKV地址https://github.com/tencent/mmkv apply()使用优化 主要是优化UI线程中执行QueuedWork.waitToFinish()当队列执行poll()时通过反射修改poll()的返回值将其设为null这样UI线程会继续往下执行而不会原地阻塞等待了。示例如下注意8.0以上与8.0以下处理不一样 object SPHook {fun optimizeSpTask() {if (Build.VERSION.SDK_INT 26) {reflectSPendingWorkFinishers()} else {reflectSFinishers()}}/*** 8.0以上 Reflect finishers**/private fun reflectSFinishers() {try {val clz Class.forName(android.app.QueuedWork)val field clz.getDeclaredField(sFinishers)field.isAccessible trueval queue field.get(clz) as? LinkedListRunnableif (queue ! null) {val linkedListProxy LinkedListProxy(queue)field.set(queue, linkedListProxy)log(hook success)}} catch (ex: Exception) {log(hook error:${ex})}}/*** 8.0以下 Reflect pending work finishers*/private fun reflectSPendingWorkFinishers() {try {val clz Class.forName(android.app.QueuedWork)val field clz.getDeclaredField(sPendingWorkFinishers)field.isAccessible trueval queue field.get(clz) as? ConcurrentLinkedQueueRunnableif (queue ! null) {val proxy ConcurrentLinkedQueueProxy(queue)field.set(queue, proxy)log(hook success)}} catch (ex: Exception) {log(hook error:${ex})}}/*** 在8.0以上apply()中QueuedWork.addFinisher(awaitCommit), 需要代理的是LinkedList如下* # private static final LinkedListRunnable sFinishers new LinkedList()*/private class LinkedListProxy(private val sFinishers: LinkedListRunnable) :LinkedListRunnable() {override fun add(element: Runnable): Boolean {return sFinishers.add(element)}override fun remove(element: Runnable): Boolean {return sFinishers.remove(element)}override fun isEmpty(): Boolean true/*** 代理的poll()方法永远返回空这样UI线程就可以避免被阻塞继续执行了*/override fun poll(): Runnable? {return null}}/*** 在8.0以下代理* // The set of Runnables that will finish or wait on any async activities started by the application.* private static final ConcurrentLinkedQueueRunnable sPendingWorkFinishers new ConcurrentLinkedQueueRunnable();*/private class ConcurrentLinkedQueueProxy(private val sPendingWorkFinishers: ConcurrentLinkedQueueRunnable) :ConcurrentLinkedQueueRunnable() {override fun add(element: Runnable?): Boolean {return sPendingWorkFinishers.add(element)}override fun remove(element: Runnable?): Boolean {return sPendingWorkFinishers.remove(element)}override fun isEmpty(): Boolean true/*** 代理的poll()方法永远返回空这样UI线程就可以避免被阻塞继续执行了*/override fun poll(): Runnable? {return null}} }
http://www.dnsts.com.cn/news/32941.html

相关文章:

  • 做网站也分内存大小的吗国内wordpress博客
  • 怎么建小说网站山东新闻今天最新消息
  • 国外的服务器做的网站在国外能打开在国内打不开是什么原因工作室名字
  • h5网站开发费用长尾关键词挖掘精灵
  • 陕西省汉中市城乡建设网站免费不良网站代码是多少
  • 采集网站后台客户数据网站域名做固定资产怎么处理
  • 1688精品货源网站入口模板手机网站建设公司排名
  • 租赁网站空间建设行业协会网站发展的建议
  • 西安专业做网站的公司如何选择安卓app开发工具
  • 阜阳网站建设推广小程序后端怎么搭建
  • 北京石景山网站建设软件工程做项目网站
  • 新手淘宝客在百度推广网站么做wordpress站点统计插件
  • php网站建设课程作业企业黄页信息网
  • 产品做网站如何谁来维护价格制作梦核的网站
  • 这么做网站网站建设用户分析
  • 木渎网站制作抓取wordpress站点用户
  • 新注册的公司怎么做网站自己怎么开发网站
  • 营销型网站欣赏做企业网站需要什么文件
  • 做网站的预算表青岛免费模板建站
  • 安庆市城乡建设网站湖北省建设工程信息网官网
  • 网站小游戏怎么做广州网站制作有哪些
  • 建设网站号码wordpress更新配置文件
  • 网站建设可行性方案模板怎么制作手机app及网站
  • 总推荐榜总点击榜总排行榜安卓优化大师清理
  • 做游戏平面设计好的素材网站有哪些网站建设及 维护
  • 好享购物官方网站购物wordpress站点信息修改版权
  • 江苏省建设考试网站太原seo关键词排名优化
  • 高密住房和城乡建设厅网站电子商务就业岗位
  • 建设网站关键词怎么写263企业邮箱官方入口
  • 什么网站可以做任务挣钱的网站策划怎么做内容