我已经在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文件太大了,在这种情况下,您可以尝试将其精简(例如,使用数据库)。

10-05 23:02
查看更多