我现在和ANR一起挣扎了几个星期,但我仍然对像this这样的日志视而不见。 stackoverflow太长了,我不知道哪个部分可能有用。 它通常在初始同步期间发生,当时在后台处理了大量网络请求(并且我几乎100%确定不在主线程中)并且我也做了很多UI之类的东西,比如通过RxJava observable从共享首选项中填充Recyclerviews,这样我就可以观察到SharedPreferences的大量变化,并使用sample方法来处理可能的背压。感谢您的任何提示,我完全迷失了。
答案 0 :(得分:12)
您有多个进程的线程转储。要获得有用的部分,您可以搜索" 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()
是一种排队的方法当调用活动的onPause
方法时,在主线程上完成工作。这就是发生的事情:onPause
被调用,现在主线程等待工作线程完成其写操作。
现在问题是您发布的日志不完整。缺少多个线程,包括从未调用CountDownLatch.countDown()
的工作线程,因此无法分辨导致死锁的原因。如果您发布整个日志(对于您的流程,我不认为其他的将会有用),我们可能会提供更多帮助。
编辑:我注意到someone else here遇到了同样的问题。对于他们来说,工作线程被卡在fsync(2)
中。如果文件很大和/或磁盘繁忙,fsync
可能会非常慢(如在多秒内)。我想这可能会导致ANR。我不确定这是否会归类为SharedPreferences
中的错误...在主线程上触发可能的长阻塞操作似乎有点奇怪,即使从onPause
调用...如果这确实是您的问题,我能想到的唯一解决方法是使用commit()
而不是apply()
,因为这将同步进行写入。您应该从后台线程执行此操作,因为在您的特定设置中,似乎需要很长时间才能刷新到磁盘!
或者你的SharedPreferences
文件太大了,在这种情况下你可以尝试减少它(例如使用数据库)。