【问题标题】:ConcurrentModificationException with ORMlite on AndroidAndroid 上 ORMlite 的 ConcurrentModificationException
【发布时间】:2017-05-27 13:18:02
【问题描述】:

当我使用 ORMlite 对我的数据库进行一些更新操作时,我有很多 ConcurrentModificationException。我将执行实际更新的代码包装到rx.Observables 中以使其异步进行。看起来像这样:

@Override
public void setFavoriteTeams(List<Team> teams) {
    final Iterator<Team> it = teams.iterator();
    Observable.create(new Observable.OnSubscribe<Object>() {
        @Override
        public void call(final Subscriber<? super Object> subscriber) {

            try {
                List<String> teamIds = new ArrayList<>();
                while (it.hasNext()) {
                    Team team = it.next();
                    teamIds.add(team.getmSipId());
                }

                setFavoriteTeamsSql(teamIds);
            } catch (Exception e) {
                handleException(e);
            } finally {
                subscriber.onNext(null);
                subscriber.onCompleted();
            }
        }
    }).subscribeOn(Schedulers.computation()).subscribe();
}

具有讽刺意味的是,不久前我开始使用 Interator 而不是 for 循环来避免可能发生的任何 ConcurrenceModificationException,但它们反而增加了很多。 setFavoriteTeamsSql(List&lt;String&gt;) 方法只是使用 ORMlite 的 UpdateBuilder 类来更新表。在Team team = it.next(); 行抛出异常。

知道如何解决这个问题吗?现在我正在回滚更改并返回 for 循环。但我希望以正确的方式做到这一点。

更新:

这是 Stacktrace 的样子:

Non-fatal Exception: java.util.ConcurrentModificationException
       at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
       at com.siplay.android_siplay.data.cache.db.DBTeamCache$4.call(DBTeamCache.java:164)
       at com.siplay.android_siplay.data.cache.db.DBTeamCache$4.call(DBTeamCache.java:157)
       at rx.Observable.unsafeSubscribe(Observable.java:10150)
       at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
       at rx.internal.schedulers.EventLoopsScheduler$EventLoopWorker$1.call(EventLoopsScheduler.java:172)
       at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
       at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:154)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
       at java.lang.Thread.run(Thread.java:818)

更新 2:

...
mNetworkTeamRepository
    .subscribeOn(Schedulers.io())
    .obseveOn(AndroidSchedulers.mainThread())
    .subscribe(new DefaultSubscriber<List<Teams>>() {
        @Override
        public void onSuccess(List<Team> teams) {
            mTeamsCache.setFavoriteTeams(teams);
        }

        public void onResult(List<Team> teams) {
            callback.showTeams(teams);
        }
    });
...

TeamRepository 在内部使用 Retrofit 服务来获取服务器端响应。

【问题讨论】:

    标签: android sqlite rx-java ormlite concurrentmodification


    【解决方案1】:

    你的代码相当于

    public void setFavoriteTeams(List<Team> teams) {
      Observable
      .fromIterable(teams)
      .map(Team::getmSipId)
      .toList()
      .doOnNext(this::setFavoriteTeamsSql)
      .subscribeOn(Schedulers.computation())
      .subscribe();
    }
    

    但我仍然看不到您的代码如何发出 ConcurrentModificationException - 也许堆栈跟踪会有所帮助?

    【讨论】:

    • 我用 Stacktrace 更新了我的问题。是的,我要尝试的第一件事是将迭代器向下移动到订阅者中。
    • 另外,重要的是 - 您的代码的任何其他部分是否修改了传入列表?因为否则没有意义。
    • 嗯,是的,发生的情况是,在服务器端请求响应中,我得到了一个团队列表,然后我调用这个方法将响应保存在数据库中,然后我将集合传递给回调到 UI。该请求是从几个屏幕发送的,所以我不确定哪个会失败。但是 setFavoriteTeams 中的 Interactor 不应该阻止这种情况吗?
    • 我将使用我的 Interactor/UseCase 实现来更新答案,这样您就可以看到我在说什么
    • 也许只是复制一份:final Iterator&lt;Team&gt; it = new ArrayList&lt;&gt;(teams).iterator();
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多