我已经在ANR上苦苦挣扎了几个星期,但是对于this这样的日志,我仍然感到盲目。对于stackoverflow来说太长了,我不知道哪一部分可能有用。
通常会在初始同步期间在后台处理大量网络请求时发生这种情况(而且我几乎100%确信其中的任何一个都不在主线程中),而且我还在制作很多UI内容,例如填充通过RxJava observables从共享的首选项中进行recyclerviews的查看,因此我正在观察SharedPreferences中的大量更改,并使用sample方法来处理可能的背压。谢谢你的提示,我完全迷路了。
最佳答案
您在那里有多个进程的线程转储。要获得有用的部分,您可以搜索“Cmd line”,直到找到您的进程(“cz.vcelka.androidapp”,PID为21574)。
如果获得ANR,则意味着您的主线程以某种方式被阻塞,因此您应该查看其堆栈跟踪。这里是 :
"main" prio=5 tid=1 Waiting
| group="main" sCount=1 dsCount=0 obj=0x74bc2fa0 self=0xb4db6500
| sysTid=21574 nice=0 cgrp=default sched=0/0 handle=0xb6fc1b34
| state=S schedstat=( 0 0 0 ) utm=785 stm=88 core=1 HZ=100
| stack=0xbe29a000-0xbe29c000 stackSize=8MB
| held mutexes=
at java.lang.Object.wait!(Native method)
- waiting on <0x05853836> (a java.lang.Object)
at java.lang.Thread.parkFor$(Thread.java:1220)
- locked <0x05853836> (a java.lang.Object)
at sun.misc.Unsafe.park(Unsafe.java:299)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:810)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:971)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1278)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:203)
at android.app.SharedPreferencesImpl$EditorImpl$1.run(SharedPreferencesImpl.java:366)
at android.app.QueuedWork.waitToFinish(QueuedWork.java:88)
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:3560)
at android.app.ActivityThread.-wrap20(ActivityThread.java:-1)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke!(Native method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
因此,您的主线程被阻止在
CountDownLatch
代码内的SharedPreferences
上等待。我们可以查看SharedPreferences的源代码以了解更多信息。在某些时候,当您调用SharedPreferences.Editor.apply()时,SharedPreferences
代码将对磁盘的写入排队到工作线程中。它也称为QueuedWork.add(awaitCommit),其中awaitCommit
是等待写操作(通过Runnable
)的CountDownLatch
,而QueuedWork.add()
是在调用 Activity 的onPause
方法时将要在主线程上完成工作的方法。就是这样:onPause
被调用,现在主线程被卡住,等待工作线程完成其写操作。现在的问题是您发布的日志不完整。缺少几个线程,包括从未调用
CountDownLatch.countDown()
的工作线程,因此无法确定导致死锁的原因。如果您发布整个日志(对于您的流程,我认为其他日志不会有用),我们可能会提供更多帮助。编辑:我注意到someone else here遇到了同样的问题。对于他们来说,工作线程被卡在
fsync(2)
中。如果文件很大和/或磁盘很忙,fsync
可能真的很慢(几秒钟之内)。我想这可能是导致ANR的原因。我不确定这是否会归类为SharedPreferences
中的错误...似乎有点奇怪,即使从onPause
调用也可能触发对主线程的长时间阻塞操作...如果这确实是您的问题,则唯一的解决方法我可以想到的是使用commit()
而不是apply()
,因为那样可以同步进行写操作。您应该从后台线程执行此操作,因为在您的特定设置中,似乎需要很长时间才能刷新到磁盘!或者,您的
SharedPreferences
文件太大了,在这种情况下,您可以尝试将其精简(例如,使用数据库)。