【问题标题】:Running Firebase callback on another thread is blocking UI在另一个线程上运行 Firebase 回调会阻塞 UI
【发布时间】:2017-07-26 23:13:43
【问题描述】:

我知道这个问题可能看起来是重复的,我已经阅读了十个关于同一件事的其他帖子,但我找不到问题

我的活动中有这个方法:

public void saveResponse(final Response studentResponse, final Content content)
    fb.getReference("...").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(final DataSnapshot dataSnapshot) {

           new Thread(new Runnable() {
               @Override
               public void run() {
                    Map<String, Object> responseMap = new HashMap<>();
                    responseMap.put("end_date", studentResponse.end_date);
                    responseMap.put("start_date", studentResponse.start_date);
                    responseMap.put("time", studentResponse.time);
                    responseMap.put("points", studentResponse.points);
                    responseMap.put("max_points", studentResponse.max_points);
                    responseMap.put("selected_options", studentResponse.selected_options);
                    if (!TextUtils.isEmpty(studentResponse.free_text))
                        responseMap.put("free_text", studentResponse.free_text);

                    DataSnapshot contentRef = dataSnapshot.child("/sections/" + currentSection + "/sections/" + currentSubsection + "/contents/" + content.id);
                    final int oldPoints = contentRef.hasChild("points") ? contentRef.child("points").getValue(int.class) : 0;
                    contentRef.getRef().setValue(responseMap);
                    contentRef.getRef().setPriority(ServerValue.TIMESTAMP);

                    DataSnapshot subSectionRef = dataSnapshot.child("/sections/" + currentSection + "/sections/" + currentSubsection);
                    long subSectionPoints = (subSectionRef.hasChild("points") ? subSectionRef.child("points").getValue(long.class) : 0) + studentResponse.points - oldPoints;
                    subSectionRef.child("points").getRef().setValue(subSectionPoints);

                    int indexOf = currentContents.indexOf(content) + 1;
                    if(indexOf > 0 && indexOf < currentContents.size()) {
                        CourseContent content = currentContents.get(indexOf);
                        subSectionRef.child("currentPosition").getRef().setValue(content.order);
                    }

                    DataSnapshot sectionRef = dataSnapshot.child("/sections/" + currentSection);
                    long sectionPoints = (sectionRef.hasChild("points") ? sectionRef.child("points").getValue(long.class) : 0) + studentResponse.points - oldPoints;
                    sectionRef.child("points").getRef().setValue(sectionPoints);

                    long coursePoints = (dataSnapshot.hasChild("points") ? dataSnapshot.child("points").getValue(long.class) : 0) + studentResponse.points - oldPoints;
                    dataSnapshot.child("points").getRef().setValue(coursePoints);
                    dataSnapshot.getRef().setPriority(MAX_SAFE_INTEGER - coursePoints);

                    int completed = 0;
                    for (DataSnapshot sect : dataSnapshot.child("sections").getChildren()) {
                        for (DataSnapshot subSect : sect.child("sections").getChildren()) {
                            int currPos = subSect.hasChild("currentPosition") ? subSect.child("currentPosition").getValue(int.class) : 0;
                            completed += currPos;
                        }
                    }

                    double progress = totalContents > 0 ? (double) completed / (double) totalContents : 0;
                    dataSnapshot.child("progress").getRef().setValue(progress);
               }
           }.start();
        }
        ...
    });
}

在单击处理程序中,我调用此方法,然后更改片段(使用自定义动画)。

问题是,片段过渡并不平滑,它会冻结一点,如果我在可运行文件中注释所有内容,那么它会运行顺利。我也尝试过使用 AsyncTask 并且发生了同样的情况。

在 runnable 内部,我只是查询 dataSnapshot 及其子项,并设置一些值 (dataSnapshot.child("item").getRef().setValue(x))

另外一个奇怪的地方是,如果我在run()里面放了一个断点,它也能顺利运行。

【问题讨论】:

  • 也许是 Android 处理程序而不是创建新线程? stackoverflow.com/questions/15136199/…
  • “当你想在 UI 线程中执行操作时,你应该使用 Handler.post()”,我不想在 UI 线程中执行它,这就是我创建另一个线程的原因。
  • 请更新帖子以将代码包含在run() 方法中。
  • @qbix 在run()method 中添加了代码
  • saveResponse() 参数response 未使用。这是您发布的代码中的错字吗?应该是studentResponsecurrentSectioncurrentSubsectioncurrentContents 声明在哪里?

标签: android multithreading firebase firebase-realtime-database


【解决方案1】:

我认为问题出在你方法的逻辑上。

监听器 onDataChange() 处于活动状态,它将响应数据的任何更改。我的意思是,如果您在 onDataChange() 方法中更改数据,则每次使用 (dataSnapshot.child("item").getRef().setValue(x))) 设置值时都会调用它,因此,它类似于在不退出的情况下进行“递归”调用。

为了解决这个问题,你应该在点击事件中获取你想要改变的键,然后使用

mDatabase = FirebaseDatabase.getInstance().getReference(); mDatabase.child("key").child("item").setValue(x);

查看https://firebase.google.com/docs/database/android/read-and-write了解更多信息

【讨论】:

  • 不完全是,addListenerForSingleValueEvent 只执行一次 de 回调,我也是先查询数据,因为我需要以前的数据来增加一些值,我也尝试过交易,同样的事情。跨度>
【解决方案2】:

衍生线程继承创建它的线程的优先级。尝试降低工作线程的优先级以防止它与 UI 线程竞争:

@Override
public void onDataChange(final DataSnapshot dataSnapshot) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            ...
        }).start();

【讨论】:

  • 同样的情况
【解决方案3】:

每次调用 onDataChange 方法都会创建一个新线程,奇怪的是:“如果我在 run() 中放置断点,它也可以顺利运行。” 可能是您应该检查是否创建了太多线程。

【讨论】:

  • 如何检查是否创建了太多线程?有多少是太多了?
  • developer.android.com/studio/profile/am-methodtrace.html,本文将告诉您如何找出导致应用程序运行缓慢的根本原因。
  • 按照您的建议,我发现在另一个活动中还有另一个听众仍然活着并且做太多工作。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
相关资源
最近更新 更多