Android 造成大量ANR的领域

Android 造成大量ANR的领域,android,realm,Android,Realm,在我自己的测试中,我没有遇到这个问题,但我的应用程序发布后,ANR开始大量涌入。我的应用程序目前有22个ANR,其中一些报告多达100次。所有这些痕迹似乎都来自于试图在UI线程上创建新的领域实例 "main" prio=5 tid=1 MONITOR | group="main" sCount=1 dsCount=0 obj=0x4183ede0 self=0x417548b8 | sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684

在我自己的测试中,我没有遇到这个问题,但我的应用程序发布后,ANR开始大量涌入。我的应用程序目前有22个ANR,其中一些报告多达100次。所有这些痕迹似乎都来自于试图在UI线程上创建新的领域实例

"main" prio=5 tid=1 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x4183ede0 self=0x417548b8
| sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684
| state=S schedstat=( 2816413167 710323137 3658 ) utm=215 stm=66 core=1
at io.realm.Realm.createAndValidate(Realm.java:~495)
- waiting to lock <0x41df9c98> held by tid=12          (IntentService[UASyncService])
at io.realm.Realm.create(Realm.java:486)
at io.realm.Realm.getInstance(Realm.java:404)
at io.realm.Realm.getInstance(Realm.java:366)
at io.realm.Realm.getInstance(Realm.java:347)
“主”优先级=5 tid=1监视器
|group=“main”scont=1 dsCount=0 obj=0x4183ede0 self=0x417548b8
|sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684
|state=S schedstat=(2816413167 710323137 3658)utm=215 stm=66 core=1
位于io.realm.realm.createAndValidate(realm.java:~495)
-等待tid持有的锁=12(IntentService[UASyncService])
创建(realm.java:486)
位于io.realm.realm.getInstance(realm.java:404)
位于io.realm.realm.getInstance(realm.java:366)
位于io.realm.realm.getInstance(realm.java:347)
我相信这个问题的根源是,正如Beender提到的,我在一个工作线程中有一个打开的领域事务,它阻止了我在UI线程上获取领域实例的尝试,从而导致了ANR

我将在找到解决方案后再次更新

*编辑:添加更新信息。

显示他们使用异步任务进行读写操作


任何代价高昂的I/O,无论是来自网络、数据库还是大型文件,通常都应该远离主线程,因为这会导致UI缓慢。在没有看到代码的情况下,我猜如果你得到一个ANR,你可能在做一些对主线程来说太复杂的事情。

领域不再有这个问题

作为参考,我当时的解决方案是:

感谢比恩德为我指明了正确的方向,并将这份公关联系起来

问题

当存在挂起的领域事务时,在不同线程上对
Realm.getInstance
的任何调用都将被阻止,直到提交或取消挂起的事务为止

在我的例子中,我有一个IntentService,它用现有的用户数据填充我的领域,同时我尝试通过在UI线程上查询领域来显示任何当前数据。尽管查询很简单,通常不会导致任何问题,但如果IntentService中存在挂起的事务,调用
Realm.getInstance
将被阻止,从而阻止UI线程,可能导致ANR

我第一次尝试的解决方案是拉住比恩德的公关分支并创建一个jar。我相信这个修复确实让我更进一步,允许在不阻塞的情况下创建领域实例,但是UI线程仍然被我试图在UI线程上执行的小事务阻塞

"main" prio=5 tid=1 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x4183ede0 self=0x417548b8
| sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684
| state=S schedstat=( 2816413167 710323137 3658 ) utm=215 stm=66 core=1
at io.realm.Realm.createAndValidate(Realm.java:~495)
- waiting to lock <0x41df9c98> held by tid=12          (IntentService[UASyncService])
at io.realm.Realm.create(Realm.java:486)
at io.realm.Realm.getInstance(Realm.java:404)
at io.realm.Realm.getInstance(Realm.java:366)
at io.realm.Realm.getInstance(Realm.java:347)
解决方案

我实施的解决方案包括几个步骤:

  • 为我的所有模型创建重复对象。重复项不扩展RealmObject(因为RealmObject不能跨线程使用)
  • 将对域的所有访问移到后台线程上。基本上,我将查询包装在AsyncTasks中,并添加了侦听器,这些侦听器返回模型的非RealmObject版本
  • 进行更多的小交易,而不是更少的大交易。以前我在创建许多新RealmObjects的循环的任一侧开始并提交事务,现在我开始并提交每个对象的事务。这样做的目的是减少领域可能处于开放事务状态的总不间断时间,以便为UI提供数据的查询可以完成,而无需等待那么长时间
结论

最初我对使用Realm犹豫不决,因为它仍处于测试阶段,并且需要注意RealmObjects不能跨线程使用。经过一些测试后,我确信我可以毫无问题地在UI线程上执行简单的查询(尽管我内心仍然有一种内疚感)

整体领域是一个值得关注的伟大项目,但我觉得它还没有为大规模商业项目做好准备。在这个项目中使用Realm可能在前期节省了一些时间,但它会让许多不满意的客户付出代价,并且很难诊断问题


*编辑:澄清问题。

您似乎有一笔未关闭的写事务。这可能会阻止领域打开新实例。检查这个公关。如果是这样,我建议您正确地关闭事务,而不是等待修复,因为写入事务无论如何都需要关闭。@Beender因此,如果我在工作线程上开始事务,并在提交工作线程事务之前尝试在UI线程上打开新的域实例,UI线程将在等待提交事务时被阻止?现在,是。虽然我不认为这是正确的行为,但我不知道目前的行为可能有一些原因。现在,当在一个线程中创建一个领域实例,而该线程中还没有打开的实例时,将调用createAndValidate,它可能会被其他线程中的事务阻塞。但是,如果线程中已经有一个打开的实例,那么引用将在不创建的情况下返回。在这种情况下,在onCreate(愚蠢的进程死亡)中打开一个域,或者当有多个活动/服务/etc时,实际上可以防止这个问题发生。整洁的从技术上讲,我在
Application onCreate()
中使用了一个单例域,并且做了很多魔术来确保它始终是开放的,但是在0.83.0及以上版本中,无论出于什么原因,我都得到了很多ANR。不过,我应该在一个月前就发送Realm源代码来重现这个问题;因此,现在所有的责任都在我身上。我所做的任何重要读写操作都是在IntentService的工作线程上执行的。我在主线程上执行的唯一领域访问是相当简单的查询。您应该尝试启用StrictMode,以确保您的应用程序没有执行任何会影响UI的操作。使用该PR,getInstance不应再被阻止。我可以复制你的问题吗?你有可能是c吗